# Run scripts with dependencies conda-exec can run Python scripts that declare their dependencies inline using the [PEP 723](https://peps.python.org/pep-0723/) metadata format. Add a PEP 723 `# /// script` metadata block to the Python file itself, usually near the top before imports or executable code. The lines inside the block are TOML, with the leading `# ` comment prefix stripped before parsing. The examples below show complete metadata blocks you can copy into a script. ## Conda-only dependencies Use TOML syntax and the `[tool.conda]` table to declare conda packages: ```python # /// script # [tool.conda] # channels = ["conda-forge", "bioconda"] # dependencies = ["samtools>=1.19", "htslib"] # /// ``` ```bash conda exec script.py ``` ## PyPI dependencies Use the standard PEP 723 `dependencies` field for PyPI packages: ```python # /// script # dependencies = ["requests>=2.31", "rich"] # /// ``` ```bash conda exec script.py ``` ```{warning} PyPI dependencies require [conda-pypi](https://github.com/conda/conda-pypi) to be installed. Without it, conda-exec cannot resolve PyPI packages and will exit with an error. ``` conda-exec adds the `conda-pypi` channel automatically. Install conda-pypi if you haven't already: ```bash conda install -n base -c conda-forge conda-pypi ``` ## Mixed conda and PyPI dependencies Combine both in a single script: ```python # /// script # requires-python = ">=3.12" # dependencies = ["requests"] # # [tool.conda] # channels = ["conda-forge", "bioconda"] # dependencies = ["samtools>=1.19"] # /// ``` Both conda and PyPI requirements are included in one environment solve. `conda-pypi` exposes PyPI packages through a conda channel so the solver can handle the combined dependency set. ## Pin the Python version Use `requires-python` to constrain which Python version is installed: ```python # /// script # requires-python = ">=3.12" # dependencies = ["click"] # /// ``` This adds a `python >=3.12` spec to the environment solve. ## Add extra dependencies from the CLI Add dependencies and channels for one run from the command line: ```bash conda exec --with numpy -c defaults script.py ``` CLI extras (`--with` and `-c`) are merged with the script's declared dependency input. They create a separate cache entry and bypass discovered lock data for that run. ## Scripts without metadata ```{note} Scripts without a `# /// script` block run directly with the current Python interpreter. No environment is created, and no packages are installed. ``` Scripts without metadata are passed through as-is: ```bash conda exec hello.py ``` ## Make scripts directly executable Add a shebang line to run scripts without typing `conda exec` or `ce`: ```python #!/usr/bin/env ce # /// script # [tool.conda] # channels = ["conda-forge"] # dependencies = ["numpy"] # /// import numpy as np print(np.random.default_rng().random(5)) ``` ```bash chmod +x demo.py ./demo.py ``` The `ce` standalone command is the recommended shebang target because it works on all platforms. Using `conda exec` in a shebang does not work because the kernel cannot split multi-word interpreter arguments portably. ```{note} On macOS and recent Linux kernels, `#!/usr/bin/env -S conda exec` works via the `-S` (split string) flag, but this is not portable to all systems. Use `#!/usr/bin/env ce` for maximum compatibility. ``` ## Force re-creation If the cached script environment is stale: ```bash conda exec --refresh script.py ``` ## Reproduce exact environments Use `--lock` when the resolved package versions should be recorded: ```bash conda exec --lock script.py ``` With the default `rattler-lock-v6` exporter, this writes `script.py.conda-exec.lock`. Future `conda exec script.py` runs use the lock data instead of solving from metadata when possible. For single-file distribution, embed generated lock data in the script: ```bash conda exec --lock --embed script.py ``` See [Lock script environments](lock-scripts.md) for sidecar, embedded, and multi-platform lock workflows.