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):
- Parses arguments using
argparseto mirror the flags passed byrun.py - Loads the configuration via
ConfigManager - Dynamically loads the method class using
ClassLoader.load_methodfrombenchmark/core/registry.py - Iterates over scenes and calls
run_scenefor 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
envkey inconfigs/base.yaml, enabling isolation without code changes. - Conditional execution:
run.pychecks for theenvkey at lines 94-96 to decide between in-process execution and subprocess dispatch. - Conda wrapper: The
run_via_subprocessfunction at lines 91-112 builds aconda run -n {env}command that executesrun_worker.pywith the same arguments. - Exit code propagation:
run_worker.pyreturns0for success or1for failure, whichrun.pyinterprets 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →