How run.py Dispatches Methods to Subprocess via Conda in LingBot-Map

In the LingBot-Map benchmark, run.py dispatches methods to isolated Conda environments by checking for an env key in the method configuration and executing run_worker.py via conda run if present.

run.py serves as the entry point for the run phase of the LingBot-Map benchmark, orchestrating the execution of method-dataset combinations defined in configs/base.yaml. When a method requires dependencies isolated from the main environment, run.py dispatches it to a subprocess via Conda, ensuring clean dependency management while maintaining centralized orchestration logic.

Method Configuration and Environment Detection

Declaring Isolated Environments in base.yaml

Each method entry in configs/base.yaml can optionally specify an env key to trigger subprocess dispatch. This declaration binds the method to a specific Conda environment without modifying the runner code.

methods:
  - name: cut3r
    method_class: benchmark.methods.cut3r.Cut3R
    params:
      # method-specific parameters

    env: cut3r_env        # ← triggers subprocess dispatch

Detection Logic in run.py

During the main execution loop, run.py inspects every method configuration. At lines 94-96, it checks for the presence of an environment specifier:

env = method_cfg.get('env')
if env:
    rc = run_via_subprocess(env, config_path, method_name, dataset_name, scene, force, logger)
else:
    # Execute in-process

    rc = run_in_process(...)

This conditional branch determines whether to execute the method within the current Python process or dispatch it to an isolated subprocess.

Subprocess Dispatch via run_via_subprocess

The run_via_subprocess function, implemented at lines 91-112 in benchmark/run.py, constructs and executes a conda run command that spawns run_worker.py inside the target environment.

def run_via_subprocess(env: str, config_path: str, method_name: str,
                       dataset_name: str, scene: str | None, force: bool,
                       logger: logging.Logger) -> int:
    """Dispatch a (method, dataset[, scene]) job to run_worker.py via conda run."""
    cmd = [
        'conda', 'run', '-n', env, '--no-capture-output',
        'python', 'run_worker.py',
        '--config', config_path,
        '--method', method_name,
        '--dataset', dataset_name,
    ]
    if scene:
        cmd += ['--scene', scene]
    if force:
        cmd += ['--force']

    logger.info(f"Dispatching to env '{env}': {' '.join(cmd)}")
    result = subprocess.run(cmd)
    return result.returncode

The function builds a command list starting with conda run -n {env} --no-capture-output, ensuring stdout/stderr flow back to the parent process unbuffered. It passes the configuration file path, method name, and dataset name as arguments to run_worker.py, with optional --scene and --force flags for debug mode and overwrite behavior respectively.

Result Handling and Exit Codes

After the subprocess completes, run.py inspects the return code at lines 126-133. An exit code of 0 indicates that all scenes for the method-dataset combination succeeded, while any non-zero value is recorded as a failure. This binary outcome allows the main loop to aggregate results across multiple environments without parsing detailed logs.

The Worker Process: run_worker.py

run_worker.py acts as the isolated execution engine inside the Conda environment. It receives the same arguments passed by run_via_subprocess and performs the following steps (lines 84-98):

  1. Parses arguments using argparse to mirror the flags passed by run.py
  2. Loads the configuration via ConfigManager
  3. Dynamically loads the method class using ClassLoader.load_method from benchmark/core/registry.py
  4. Iterates over scenes and calls run_scene for each

At lines 176-182, it exits with status 0 if every scene succeeded, or 1 if any scene failed. This exit code propagates back to run.py, closing the dispatch loop.

Practical Dispatch Examples

Manual Conda Invocation

To manually replicate what run.py constructs automatically:

conda run -n cut3r_env --no-capture-output python run_worker.py \
    --config configs/base.yaml \
    --method cut3r \
    --dataset 7scenes_s10 \
    --scene chess/seq-01 \
    --force

Python Subprocess Call

To programmatically dispatch a method as run.py does:

import subprocess

def dispatch_method():
    cmd = [
        "conda", "run", "-n", "cut3r_env", "--no-capture-output",
        "python", "run_worker.py",
        "--config", "configs/base.yaml",
        "--method", "cut3r",
        "--dataset", "7scenes_s10",
    ]
    result = subprocess.run(cmd)
    print(f"Exit code: {result.returncode}")
    return result.returncode == 0

dispatch_method()

Summary

  • Configuration-driven dispatch: Methods declare their Conda environment via the env key in configs/base.yaml, enabling isolation without code changes.
  • Conditional execution: run.py checks for the env key at lines 94-96 to decide between in-process execution and subprocess dispatch.
  • Conda wrapper: The run_via_subprocess function at lines 91-112 builds a conda run -n {env} command that executes run_worker.py with the same arguments.
  • Exit code propagation: run_worker.py returns 0 for success or 1 for failure, which run.py interprets at lines 126-133 to track benchmark progress.
  • Dependency isolation: This architecture keeps the main runner lightweight while allowing methods with conflicting dependencies to execute in their own managed environments.

Frequently Asked Questions

Why does LingBot-Map use subprocess dispatch instead of importing methods directly?

Direct imports would force all method dependencies into the same Python environment, causing version conflicts when methods require incompatible libraries (e.g., different PyTorch or CUDA versions). By dispatching via conda run, each method executes with its own dependency tree while the main run.py orchestrator remains dependency-light.

How does exit code handling work between run.py and run_worker.py?

run_worker.py aggregates scene-level results and exits with 0 only if all scenes succeed (lines 176-182). run.py captures this via subprocess.run() and checks the return code at lines 126-133. A non-zero code marks that specific method-dataset combination as failed in the benchmark results, allowing the main loop to continue with other combinations.

Can I debug a single scene using the subprocess dispatch?

Yes. When run.py is invoked with the --scene flag, it passes this argument through to run_worker.py via the run_via_subprocess function (lines 104-105 in run.py). The worker then processes only that specific scene, making it easier to debug method-specific issues within the isolated environment without running the full dataset.

What happens if the specified Conda environment does not exist?

The conda run command will fail immediately with an environment not found error, and subprocess.run() will return a non-zero exit code. run.py will record this as a failure for the method-dataset combination and continue to the next iteration, as implemented in the result handling logic at lines 126-133.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →