{"id":13478162,"url":"https://github.com/basnijholt/unidep","last_synced_at":"2026-02-25T01:01:55.779Z","repository":{"id":207499159,"uuid":"719396628","full_name":"basnijholt/unidep","owner":"basnijholt","description":"Single source of truth with requirements for pip and conda","archived":false,"fork":false,"pushed_at":"2026-02-18T08:18:26.000Z","size":1407,"stargazers_count":242,"open_issues_count":39,"forks_count":7,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-02-18T12:53:17.934Z","etag":null,"topics":["conda","conda-environment","conda-lock","pip","pip-compile","setuptools"],"latest_commit_sha":null,"homepage":"https://unidep.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/basnijholt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-16T04:23:01.000Z","updated_at":"2026-02-11T00:54:33.000Z","dependencies_parsed_at":"2026-01-26T21:02:52.573Z","dependency_job_id":null,"html_url":"https://github.com/basnijholt/unidep","commit_stats":{"total_commits":575,"total_committers":5,"mean_commits":115.0,"dds":"0.19304347826086954","last_synced_commit":"75295016affa95c82837ab2e2bceaa85545908d7"},"previous_names":["basnijholt/requirements.yaml","basnijholt/conda-merge","basnijholt/conda-join","basnijholt/unidep"],"tags_count":86,"template":false,"template_full_name":null,"purl":"pkg:github/basnijholt/unidep","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basnijholt%2Funidep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basnijholt%2Funidep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basnijholt%2Funidep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basnijholt%2Funidep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/basnijholt","download_url":"https://codeload.github.com/basnijholt/unidep/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basnijholt%2Funidep/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29807689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T22:43:48.403Z","status":"ssl_error","status_checked_at":"2026-02-24T22:43:18.536Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conda","conda-environment","conda-lock","pip","pip-compile","setuptools"],"created_at":"2024-07-31T16:01:53.287Z","updated_at":"2026-02-25T01:01:55.765Z","avatar_url":"https://github.com/basnijholt.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# 🚀 UniDep - Unified Conda and Pip Dependency Management 🚀\n\n![UniDep logo](https://media.githubusercontent.com/media/basnijholt/nijho.lt/main/content/project/unidep/featured.png)\n\n[![PyPI](https://img.shields.io/pypi/v/unidep.svg)](https://pypi.python.org/pypi/unidep)\n[![Build Status](https://github.com/basnijholt/unidep/actions/workflows/pytest.yml/badge.svg)](https://github.com/basnijholt/unidep/actions/workflows/pytest.yml)\n[![CodeCov](https://codecov.io/gh/basnijholt/unidep/branch/main/graph/badge.svg)](https://codecov.io/gh/basnijholt/unidep)\n[![GitHub Repo stars](https://img.shields.io/github/stars/basnijholt/unidep)](https://github.com/basnijholt/unidep)\n[![Documentation](https://readthedocs.org/projects/unidep/badge/?version=latest)](https://unidep.readthedocs.io/)\n[![Python Bytes](https://img.shields.io/badge/Python_Bytes-366-D7F9FF?logo=applepodcasts\u0026labelColor=blue)](https://www.youtube.com/live/PRaTs3PnJvI?si=UrVozo81Pj8WcyXh\u0026t=489)\n\n\u003e UniDep streamlines Python project dependency management by unifying Conda and Pip packages in a single system.\n\u003e [Learn when to use UniDep](#q-when-to-use-unidep) in our [FAQ](#-faq).\n\nHandling dependencies in Python projects can be challenging, especially when juggling Python and non-Python packages.\nThis often leads to confusion and inefficiency, as developers juggle between multiple dependency files.\n\n- **📝 Unified Dependency File**: Use either `requirements.yaml` or `pyproject.toml` to manage both Conda and Pip dependencies in one place.\n- **⚙️ Build System Integration**: Integrates with Setuptools and Hatchling for automatic dependency handling during `pip install ./your-package`.\n- **💻 One-Command Installation**: `unidep install` handles Conda, Pip, and local dependencies effortlessly.\n- **⚡️ Fast Pip Operations**: Leverages `uv` (if installed) for faster pip installations.\n- **🏢 Monorepo-Friendly**: Render (multiple) `requirements.yaml` or `pyproject.toml` files into one Conda `environment.yaml` file and maintain fully consistent global *and* per sub package `conda-lock` files.\n- **🌍 Platform-Specific Support**: Specify dependencies for different operating systems or architectures.\n- **🔧 `pip-compile` Integration**: Generate fully pinned `requirements.txt` files from `requirements.yaml` or `pyproject.toml` files using `pip-compile`.\n- **🔒 Integration with `conda-lock`**: Generate fully pinned `conda-lock.yml` files from (multiple) `requirements.yaml` or `pyproject.toml` file(s), leveraging `conda-lock`.\n- **🥧 Pixi Support**: Generate `pixi.toml` files from your dependency files, enabling Pixi-based workflows while keeping UniDep as the single source of truth.\n- **🤓 Nerd stats**: written in Python, \u003e99% test coverage, fully-typed, all Ruff's rules enabled, easily extensible, and minimal dependencies\n\n`unidep` is designed to make dependency management in Python projects as simple and efficient as possible.\nTry it now and streamline your development process!\n\n\u003e [!TIP]\n\u003e Check out the [example `requirements.yaml` and `pyproject.toml` below](#example).\n\n\u003c!-- toc-start --\u003e\n\n## :books: Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [:rocket: Bootstrap from Scratch](#rocket-bootstrap-from-scratch)\n- [:package: Installation](#package-installation)\n- [:memo: `requirements.yaml` and `pyproject.toml` structure](#memo-requirementsyaml-and-pyprojecttoml-structure)\n  - [Example](#example)\n    - [Example `requirements.yaml`](#example-requirementsyaml)\n    - [Example `pyproject.toml`](#example-pyprojecttoml)\n  - [Key Points](#key-points)\n  - [Supported Version Pinnings](#supported-version-pinnings)\n  - [Conflict Resolution](#conflict-resolution)\n    - [How It Works](#how-it-works)\n  - [Platform Selectors](#platform-selectors)\n    - [Supported Selectors](#supported-selectors)\n    - [Usage](#usage)\n    - [Implementation](#implementation)\n  - [`[project.dependencies]` in `pyproject.toml` handling](#projectdependencies-in-pyprojecttoml-handling)\n- [:jigsaw: Build System Integration](#jigsaw-build-system-integration)\n  - [Local Dependencies in Monorepos](#local-dependencies-in-monorepos)\n  - [PyPI Alternatives for Local Dependencies](#pypi-alternatives-for-local-dependencies)\n  - [Overriding Nested Vendor Copies with `use`](#overriding-nested-vendor-copies-with-use)\n    - [Example: Override foo's bundled bar with your PyPI build](#example-override-foos-bundled-bar-with-your-pypi-build)\n  - [All `use` values](#all-use-values)\n  - [Build System Behavior](#build-system-behavior)\n  - [Example packages](#example-packages)\n  - [Setuptools Integration](#setuptools-integration)\n  - [Hatchling Integration](#hatchling-integration)\n- [:desktop_computer: As a CLI](#desktop_computer-as-a-cli)\n  - [`unidep merge`](#unidep-merge)\n  - [`unidep install`](#unidep-install)\n  - [`unidep install-all`](#unidep-install-all)\n  - [`unidep conda-lock`](#unidep-conda-lock)\n  - [`unidep pixi`](#unidep-pixi)\n    - [What `unidep pixi` generates](#what-unidep-pixi-generates)\n    - [Dependency reconciliation rules (important)](#dependency-reconciliation-rules-important)\n    - [Channels/platforms precedence](#channelsplatforms-precedence)\n    - [Example (single-file)](#example-single-file)\n  - [`unidep pip-compile`](#unidep-pip-compile)\n  - [`unidep pip`](#unidep-pip)\n  - [`unidep conda`](#unidep-conda)\n- [❓ FAQ](#-faq)\n  - [**Q: When to use UniDep?**](#q-when-to-use-unidep)\n  - [**Q: Just show me a full example!**](#q-just-show-me-a-full-example)\n  - [**Q: Uses of UniDep in the wild?**](#q-uses-of-unidep-in-the-wild)\n  - [**Q: How do I force PyPI instead of a local path for one dependency?**](#q-how-do-i-force-pypi-instead-of-a-local-path-for-one-dependency)\n  - [**Q: How do I ignore a local dependency entirely?**](#q-how-do-i-ignore-a-local-dependency-entirely)\n  - [**Q: A submodule brings its own copy of package X. How do I avoid conflicts?**](#q-a-submodule-brings-its-own-copy-of-package-x-how-do-i-avoid-conflicts)\n  - [**Q: How is this different from conda/mamba/pip?**](#q-how-is-this-different-from-condamambapip)\n  - [**Q: I found a project using unidep, now what?**](#q-i-found-a-project-using-unidep-now-what)\n  - [**Q: How to handle local dependencies that do not use UniDep?**](#q-how-to-handle-local-dependencies-that-do-not-use-unidep)\n  - [**Q: Can't Conda already do this?**](#q-cant-conda-already-do-this)\n  - [**Q: What is the difference between `conda-lock` and `unidep conda-lock`?**](#q-what-is-the-difference-between-conda-lock-and-unidep-conda-lock)\n  - [**Q: What is the difference between `hatch-conda` / `pdm-conda` and `unidep`?**](#q-what-is-the-difference-between-hatch-conda--pdm-conda-and-unidep)\n- [:hammer_and_wrench: Troubleshooting](#hammer_and_wrench-troubleshooting)\n  - [`pip install` fails with `FileNotFoundError`](#pip-install-fails-with-filenotfounderror)\n- [:warning: Limitations](#warning-limitations)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n\u003c!-- toc-end --\u003e\n\n## :rocket: Bootstrap from Scratch\n\nTo get started quickly with UniDep, run the following command. This will download and install [micromamba](https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html) (recommended for fast Conda environment management), [uv](https://docs.astral.sh/uv/getting-started/installation/) (recommended for faster pip installations), and then install UniDep:\n\n```bash\n\"${SHELL}\" \u003c(curl -LsSf raw.githubusercontent.com/basnijholt/unidep/main/bootstrap.sh)\n```\n\n\u003e [!NOTE]\n\u003e Micromamba and uv are recommended to optimize your installation experience, but they are not required if you prefer to use your existing Conda and pip setup.\n\n\u003e [!WARNING]\n\u003e NEVER! run scripts from the internet without understanding what they do. Always inspect the script first!\n\n\u003cdetails\u003e\n\u003csummary\u003ePin the hash of the bootstrap script with:\u003c/summary\u003e\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- HASH=$(git log -n 1 --pretty=format:\"%H\" -- bootstrap.sh) --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- echo '\"${SHELL}\"' '\u003c(curl -LsSf raw.githubusercontent.com/basnijholt/unidep/'\"$HASH\"'/bootstrap.sh)' --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\n\"${SHELL}\" \u003c(curl -LsSf raw.githubusercontent.com/basnijholt/unidep/939246571b65004391c425eb6df713303663054a/bootstrap.sh)\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n\u003c/details\u003e\n\n## :package: Installation\n\nTo install `unidep`, run one of the following commands that use [`pipx`](https://pipx.pypa.io/) (recommended), `pip`, or `conda`:\n\n```bash\npipx install \"unidep[all]\"  # Recommended (install as a standalone CLI)\n```\n\nor\n\n```bash\npip install \"unidep[all]\"\n```\n\nor\n\n```bash\nconda install -c conda-forge unidep\n```\n\n## :memo: `requirements.yaml` and `pyproject.toml` structure\n\n`unidep` allows either using a\n1. `requirements.yaml` file with a specific format (similar but _**not**_ the same as a Conda `environment.yaml` file) or\n2. `pyproject.toml` file with a `[tool.unidep]` section.\n\nBoth files contain the following keys:\n\n- **name** (Optional): For documentation, not used in the output.\n- **channels**: List of conda channels for packages, such as `conda-forge`.\n- **dependencies**: Mix of Conda and Pip packages.\n- **local_dependencies** (Optional): List of paths to other `requirements.yaml` or `pyproject.toml` files to include.\n- **optional_dependencies** (Optional): Dictionary with lists of optional dependencies.\n- **platforms** (Optional): List of platforms that are supported (used in `conda-lock`).\n\nWhether you use a `requirements.yaml` or `pyproject.toml` file, the same information can be specified in either.\nChoose the format that works best for your project.\n\n### Example\n\n#### Example `requirements.yaml`\n\nExample of a `requirements.yaml` file:\n\n```yaml\nname: example_environment\nchannels:\n  - conda-forge\ndependencies:\n  - numpy                   # same name on conda and pip\n  - conda: python-graphviz  # When names differ between Conda and Pip\n    pip: graphviz\n  - pip: slurm-usage \u003e=1.1.0,\u003c2  # pip-only\n  - conda: mumps                 # conda-only\n  # Use platform selectors\n  - conda: cuda-toolkit =11.8    # [linux64]\nlocal_dependencies:\n  - ../other-project-using-unidep     # include other projects that use unidep\n  - ../common-requirements.yaml       # include other requirements.yaml files\n  - ../project-not-managed-by-unidep  # 🚨 Skips its dependencies!\noptional_dependencies:\n  test:\n    - pytest\n  full:\n    - ../other-local-dep[test]  # include its optional 'test' dependencies\nplatforms:  # (Optional) specify platforms that are supported (used in conda-lock)\n  - linux-64\n  - osx-arm64\n```\n\n\u003e [!IMPORTANT]\n\u003e `unidep` can process this during `pip install` and create a Conda installable `environment.yaml` or `conda-lock.yml` file, and more!\n\n\u003e [!NOTE]\n\u003e For a more in-depth example containing multiple installable projects, see the [`example`](example/) directory.\n\n#### Example `pyproject.toml`\n\n***Alternatively***, one can fully configure the dependencies in the `pyproject.toml` file in the `[tool.unidep]` section:\n\n```toml\n[tool.unidep]\nchannels = [\"conda-forge\"]\ndependencies = [\n    \"numpy\",                                         # same name on conda and pip\n    { conda = \"python-graphviz\", pip = \"graphviz\" }, # When names differ between Conda and Pip\n    { pip = \"slurm-usage \u003e=1.1.0,\u003c2\" },              # pip-only\n    { conda = \"mumps\" },                             # conda-only\n    { conda = \"cuda-toolkit =11.8:linux64\" }         # Use platform selectors by appending `:linux64`\n]\nlocal_dependencies = [\n    \"../other-project-using-unidep\",    # include other projects that use unidep\n    \"../common-requirements.yaml\",      # include other requirements.yaml files\n    \"../project-not-managed-by-unidep\"  # 🚨 Skips its dependencies!\n]\noptional_dependencies = {\n    test = [\"pytest\"],\n    full = [\"../other-local-dep[test]\"]  # include its optional 'test' dependencies\n}\nplatforms = [ # (Optional) specify platforms that are supported (used in conda-lock)\n    \"linux-64\",\n    \"osx-arm64\"\n]\n```\n\nThis data structure is *identical* to the `requirements.yaml` format, with the exception of the `name` field and the [platform selectors](#platform-selectors).\nIn the `requirements.yaml` file, one can use e.g., `# [linux64]`, which in the `pyproject.toml` file is `:linux64` at the end of the package name.\n\nSee [Build System Integration](#jigsaw-build-system-integration) for more information on how to set up `unidep` with different build systems (Setuptools or Hatchling).\n\n\u003e [!IMPORTANT]\n\u003e In these docs, we often mention the `requirements.yaml` format for simplicity, but the same information can be specified in `pyproject.toml` as well.\n\u003e Everything that is possible in `requirements.yaml` is also possible in `pyproject.toml`!\n\n### Key Points\n\n- Standard names (e.g., `- numpy`) are assumed to be the same for Conda and Pip.\n- Use a dictionary with `conda: \u003cpackage\u003e` *and* `pip: \u003cpackage\u003e` to specify different names across platforms.\n- Use `pip:` to specify packages that are only available through Pip.\n- Use `conda:` to specify packages that are only available through Conda.\n- Use `# [selector]` (YAML only) or `package:selector` to specify platform-specific dependencies.\n- Use `local_dependencies:` to include other `requirements.yaml` or `pyproject.toml` files and merge them into one. Also allows projects that are not managed by `unidep` to be included, but be aware that this skips their dependencies! Can specify PyPI alternatives for monorepo setups (see [PyPI Alternatives for Local Dependencies](#pypi-alternatives-for-local-dependencies)).\n- Use `optional_dependencies:` to specify optional dependencies. Can be installed like `unidep install \".[test]\"` or `pip install \".[test]\"`.\n- Use `platforms:` to specify the platforms that are supported. If omitted, all platforms are assumed to be supported.\n\n\u003e *We use the YAML notation here, but the same information can be specified in `pyproject.toml` as well.*\n\n### Supported Version Pinnings\n\nUniDep supports a range of version pinning operators (the same as Conda):\n\n- **Standard Version Constraints**: Specify exact versions or ranges with standard operators like `=`, `\u003e`, `\u003c`, `\u003e=`, `\u003c=`.\n  - Example: `=1.0.0`, `\u003e1.0.0, \u003c2.0.0`.\n\n- **Version Exclusions**: Exclude specific versions using `!=`.\n  - Example: `!=1.5.0`.\n\n- **Redundant Pinning Resolution**: Automatically resolves redundant version specifications.\n  - Example: `\u003e1.0.0, \u003e0.5.0` simplifies to `\u003e1.0.0`.\n\n- **Contradictory Version Detection**: Errors are raised for contradictory pinnings to maintain dependency integrity. See the [Conflict Resolution](#conflict-resolution) section for more information.\n  - Example: Specifying `\u003e2.0.0, \u003c1.5.0` triggers a `VersionConflictError`.\n\n- **Invalid Pinning Detection**: Detects and raises errors for unrecognized or improperly formatted version specifications.\n\n- **Conda Build Pinning**: UniDep also supports Conda's build pinning, allowing you to specify builds in your pinning patterns.\n  - Example: Conda supports pinning builds like `qsimcirq * cuda*` or `vtk * *egl*`.\n  - **Limitation**: While UniDep allows such build pinning, it requires that there be a single pin per package. UniDep cannot resolve conflicts where multiple build pinnings are specified for the same package.\n    - Example: UniDep can handle `qsimcirq * cuda*`, but it cannot resolve a scenario with both `qsimcirq * cuda*` and `qsimcirq * cpu*`.\n\n- **Other Special Cases**: In addition to Conda build pins, UniDep supports all special pinning formats, such as VCS (Version Control System) URLs or local file paths. This includes formats like `package @ git+https://git/repo/here` or `package @ file:///path/to/package`. However, UniDep has a limitation: it can handle only one special pin per package. These special pins can be combined with an unpinned version specification, but not with multiple special pin formats for the same package.\n  - Example: UniDep can manage dependencies specified as `package @ git+https://git/repo/here` and `package` in the same `requirements.yaml`. However, it cannot resolve scenarios where both `package @ git+https://git/repo/here` and `package @ file:///path/to/package` are specified for the same package.\n\n\u003e [!WARNING]\n\u003e **Pinning Validation and Combination**: UniDep actively validates and/or combines pinnings only when **multiple different pinnings** are specified for the same package.\n\u003e This means if your `requirements.yaml` files include multiple pinnings for a single package, UniDep will attempt to resolve them into a single, coherent specification.\n\u003e However, if the pinnings are contradictory or incompatible, UniDep will raise an error to alert you of the conflict.\n\n### Conflict Resolution\n\n`unidep` features a conflict resolution mechanism to manage version conflicts and platform-specific dependencies in `requirements.yaml` or `pyproject.toml` files.\n\n#### How It Works\n\n- **Version Pinning Priority**: `unidep` gives priority to version-pinned packages when the same package is specified multiple times. For instance, if both `foo` and `foo \u003c1` are listed, `foo \u003c1` is selected due to its specific version pin.\n\n- **Platform-Specific Version Pinning**: `unidep` resolves platform-specific dependency conflicts by preferring the version with the narrowest platform scope. For instance, given `foo \u003c3 # [linux64]` and `foo \u003e1`, it installs `foo \u003e1,\u003c3` exclusively on Linux-64 and `foo \u003e1` on all other platforms.\n\n- **Intractable Conflicts**: When conflicts are irreconcilable (e.g., `foo \u003e1` vs. `foo \u003c1`), `unidep` raises an exception.\n\n### Platform Selectors\n\nThis tool supports a range of platform selectors that allow for specific handling of dependencies based on the user's operating system and architecture. This feature is particularly useful for managing conditional dependencies in diverse environments.\n\n#### Supported Selectors\n\nThe following selectors are supported:\n\n- `linux`: For all Linux-based systems.\n- `linux64`: Specifically for 64-bit Linux systems.\n- `aarch64`: For Linux systems on ARM64 architectures.\n- `ppc64le`: For Linux on PowerPC 64-bit Little Endian architectures.\n- `osx`: For all macOS systems.\n- `osx64`: Specifically for 64-bit macOS systems.\n- `arm64`: For macOS systems on ARM64 architectures (Apple Silicon).\n- `macos`: An alternative to `osx` for macOS systems.\n- `unix`: A general selector for all UNIX-like systems (includes Linux and macOS).\n- `win`: For all Windows systems.\n- `win64`: Specifically for 64-bit Windows systems.\n\n#### Usage\n\nSelectors are used in `requirements.yaml` files to conditionally include dependencies based on the platform:\n\n```yaml\ndependencies:\n  - some-package \u003e=1  # [unix]\n  - another-package   # [win]\n  - special-package   # [osx64]\n  - pip: cirq         # [macos win]\n    conda: cirq       # [linux]\n```\n\nOr when using `pyproject.toml` instead of `requirements.yaml`:\n\n```toml\n[tool.unidep]\ndependencies = [\n    \"some-package \u003e=1:unix\",\n    \"another-package:win\",\n    \"special-package:osx64\",\n    { pip = \"cirq:macos win\", conda = \"cirq:linux\" },\n]\n```\n\nIn this example:\n\n- `some-package` is included only in UNIX-like environments (Linux and macOS).\n- `another-package` is specific to Windows.\n- `special-package` is included only for 64-bit macOS systems.\n- `cirq` is managed by `pip` on macOS and Windows, and by `conda` on Linux. This demonstrates how you can specify different package managers for the same package based on the platform.\n\nNote that the `package-name:unix` syntax can also be used in the `requirements.yaml` file, but the `package-name # [unix]` syntax is not supported in `pyproject.toml`.\n\n#### Implementation\n\n`unidep` parses these selectors and filters dependencies according to the platform where it's being installed.\nIt is also used for creating environment and lock files that are portable across different platforms, ensuring that each environment has the appropriate dependencies installed.\n\n### `[project.dependencies]` in `pyproject.toml` handling\n\nThe `project_dependency_handling` option in `[tool.unidep]` (in `pyproject.toml`) controls how dependencies listed in the standard `[project.dependencies]` section of `pyproject.toml` are handled when processed by `unidep`.\n\n**Modes:**\n\n- **`ignore`** (default): Dependencies in `[project.dependencies]` are ignored by `unidep`.\n- **`same-name`**: Dependencies in `[project.dependencies]` are treated as dependencies with the same name for both Conda and Pip. They will be added to the `dependencies` list in `[tool.unidep]` under the assumption that the package name is the same for both package managers.\n- **`pip-only`**: Dependencies in `[project.dependencies]` are treated as pip-only dependencies. They will be added to the `dependencies` list in `[tool.unidep]` under the `pip` key.\n\n**Example `pyproject.toml`:**\n\n```toml\n[build-system]\nrequires = [\"hatchling\", \"unidep\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-project\"\nversion = \"0.1.0\"\ndependencies = [  # These will be handled according to the `project_dependency_handling` option\n  \"requests\",\n  \"pandas\",\n]\n\n[tool.unidep]\nproject_dependency_handling = \"same-name\"  # Or \"pip-only\", \"ignore\"\ndependencies = [\n    {conda = \"python-graphviz\", pip = \"graphivz\"},\n]\n```\n\n**Notes:**\n\n- The `project_dependency_handling` option only affects how dependencies from `[project.dependencies]` are processed. Dependencies directly listed under `[tool.unidep.dependencies]` are handled as before.\n- This feature is helpful for projects that are already using the standard `[project.dependencies]` field and want to integrate `unidep` without duplicating their dependency list.\n- The `project_dependency_handling` feature is _*only available*_ when using `pyproject.toml` files. It is not supported in `requirements.yaml` files.\n\n## :jigsaw: Build System Integration\n\n\u003e [!TIP]\n\u003e See [`example/`](example/) for working examples of using `unidep` with different build systems.\n\n`unidep` seamlessly integrates with popular Python build systems to simplify dependency management in your projects.\n\n### Local Dependencies in Monorepos\n\nLocal dependencies are essential for monorepos and multi-package projects, allowing you to:\n- Share code between packages during development\n- Maintain separate releases for each package\n- Test changes across multiple packages simultaneously\n\nHowever, when building wheels for distribution, local paths create non-portable packages that only work on the original system.\n\n### PyPI Alternatives for Local Dependencies\n\nUniDep solves this problem by letting you specify both local paths (for development) and PyPI packages (for distribution):\n\n```yaml\n# requirements.yaml\ndependencies:\n  - numpy\n  - pandas\n\nlocal_dependencies:\n  # Standard string format for local dependencies\n  - ../shared-lib\n\n  # Dictionary format with optional PyPI alternative for build-time\n  - local: ../auth-lib\n    pypi: company-auth-lib\u003e=1.0\n\n  - local: ../utils\n    pypi: company-utils~=2.0\n    use: pypi  # see [Overriding Nested Vendor Copies](#overriding-nested-vendor-copies-with-use)\n```\n\nOr in `pyproject.toml`:\n\n```toml\n[tool.unidep]\ndependencies = [\"numpy\", \"pandas\"]\n\nlocal_dependencies = [\n    # Standard string format for local dependencies\n    \"../shared-lib\",\n\n    # Dictionary format with optional PyPI alternative for build-time\n    {local = \"../auth-lib\", pypi = \"company-auth-lib\u003e=1.0\"},\n    {local = \"../utils\", pypi = \"company-utils~=2.0\", use = \"pypi\"},\n]\n```\n\n**How it works:**\n- **During development** (e.g., `unidep install` or `pip install -e .`): Uses local paths when they exist\n- **When building wheels**: PyPI alternatives (if specified) are used to create portable packages\n- The standard string format continues to work as always for local dependencies\n\n\u003e [!TIP]\n\u003e PyPI alternatives ensure your wheels are portable and can be installed anywhere, not just on the build system. Use the `use` field (see [Overriding Nested Vendor Copies](#overriding-nested-vendor-copies-with-use)) to control whether UniDep installs the local path, forces PyPI, or skips the entry entirely.\n\n### Overriding Nested Vendor Copies with `use`\n\n**The Problem:** When vendoring dependencies as git submodules, you often encounter conflicts where a submodule bundles its own copy of a dependency you also use, but at a different version.\n\n**The Solution:** Use `use: pypi` to force your PyPI package instead of the vendored copy, with automatic propagation to all nested references.\n\n#### Example: Override foo's bundled bar with your PyPI build\n\nYour project vendors `foo` as a submodule. Foo bundles `bar@1.0`, but you need `bar@2.0`:\n\n```\nproject/\n  third_party/\n    foo/                    # git submodule you don't control\n      third_party/\n        bar/                # foo bundles bar@1.0\n```\n\n**Solution with `use: pypi`:**\n\n```yaml\nlocal_dependencies:\n  - ./third_party/foo       # Keep foo editable for development\n\n  # Override: force YOUR PyPI build of bar\n  - local: ./third_party/foo/third_party/bar\n    pypi: my-bar\u003e=2.0\n    use: pypi               # Install from PyPI, skip local path\n```\n\n**What happens:**\n1. `foo` stays local (editable for development)\n2. `my-bar\u003e=2.0` gets installed from PyPI (not foo's bundled v1.0)\n3. **Propagates**: Every nested reference to `bar` uses your PyPI package\n4. Works with `unidep install`, `unidep conda-lock`, all CLI commands\n\nThis is the **key difference** from just using `pypi:` as a build-time fallback - `use: pypi` **forces the PyPI package during development** while keeping other local dependencies editable.\n\n---\n\n### All `use` values\n\nTell UniDep what to **use** for each entry in `local_dependencies`:\n\n| `use` value | When to use | Installs from | Propagates override? |\n|------------|-------------|---------------|---------------------|\n| `local` *(default)* | Normal local development | Local path | - |\n| `pypi` | **Force PyPI** even when local exists | `pypi:` spec | Yes |\n| `skip` | Ignore this path entirely | Nothing | Yes |\n\n**Common patterns:**\n\n```yaml\nlocal_dependencies:\n  # Standard local development (default)\n  - ../shared-lib\n\n  # Force PyPI to override nested vendor copy\n  - local: ./vendor/foo/nested/bar\n    pypi: my-bar\u003e=2.0\n    use: pypi\n\n  # Skip a path without installing anything\n  - local: ./deprecated-module\n    use: skip\n```\n\n\u003e [!NOTE]\n\u003e **Precedence:** The `use` flag on the entry itself always wins. When UniDep encounters the same path in nested `local_dependencies`, it uses your override. Setting `UNIDEP_SKIP_LOCAL_DEPS=1` forces any effective `use: local` to behave like `pypi` (if specified) or `skip`, but does **not** override explicit `use: pypi` or `use: skip`.\n\n\u003e [!WARNING]\n\u003e If `use: pypi` is set but no `pypi:` requirement is provided, UniDep exits with a clear error so you can supply the missing spec.\n\n### Build System Behavior\n\n**Important differences between build backends:**\n- **Setuptools**: Builds wheels containing `file://` URLs with absolute paths. These wheels only work on the original system.\n- **Hatchling**: Rejects `file://` URLs by default, preventing non-portable wheels.\n\nTo ensure portable wheels, you can use the `UNIDEP_SKIP_LOCAL_DEPS` environment variable:\n\n```bash\n# Force use of PyPI alternatives even when local paths exist\nUNIDEP_SKIP_LOCAL_DEPS=1 python -m build\n\n# For hatch projects\nUNIDEP_SKIP_LOCAL_DEPS=1 hatch build\n\n# For uv build\nUNIDEP_SKIP_LOCAL_DEPS=1 uv build\n```\n\n\u003e [!NOTE]\n\u003e **When `UNIDEP_SKIP_LOCAL_DEPS=1` is set:**\n\u003e - Any effective `use: local` behaves as `use: pypi` (if a `pypi` spec exists) or `use: skip`\n\u003e - Explicit `use: pypi` and `use: skip` remain unchanged\n\u003e - Dependencies from local packages are still included (from their `requirements.yaml`/`pyproject.toml`)\n\n### Example packages\n\nExplore these installable [example](example/) packages to understand how `unidep` integrates with different build tools and configurations:\n\n| Project                                                    | Build Tool   | `pyproject.toml` | `requirements.yaml` | `setup.py` |\n| ---------------------------------------------------------- | ------------ | ---------------- | ------------------- | ---------- |\n| [`setup_py_project`](example/setup_py_project)             | `setuptools` | ✅                | ✅                   | ✅          |\n| [`setuptools_project`](example/setuptools_project)         | `setuptools` | ✅                | ✅                   | ❌          |\n| [`pyproject_toml_project`](example/pyproject_toml_project) | `setuptools` | ✅                | ❌                   | ❌          |\n| [`hatch_project`](example/hatch_project)                   | `hatch`      | ✅                | ✅                   | ❌          |\n| [`hatch2_project`](example/hatch2_project)                 | `hatch`      | ✅                | ❌                   | ❌          |\n\n### Setuptools Integration\n\nFor projects using `setuptools`, configure `unidep` in `pyproject.toml` and either specify dependencies in a `requirements.yaml` file or include them in `pyproject.toml` too.\n\n- **Using `pyproject.toml` only**: The `[project.dependencies]` field in `pyproject.toml` gets automatically populated from `requirements.yaml` or from the `[tool.unidep]` section in `pyproject.toml`.\n- **Using `setup.py`**: The `install_requires` field in `setup.py` automatically reflects dependencies specified in `requirements.yaml` or `pyproject.toml`.\n\n**Example `pyproject.toml` Configuration**:\n\n```toml\n[build-system]\nbuild-backend = \"setuptools.build_meta\"\nrequires = [\"setuptools\", \"unidep\"]\n\n[project]\ndynamic = [\"dependencies\"]\n```\n\n### Hatchling Integration\n\nFor projects managed with [Hatch](https://hatch.pypa.io/), `unidep` can be configured in `pyproject.toml` to automatically process the dependencies from `requirements.yaml` or from the `[tool.unidep]` section in `pyproject.toml`.\n\n**Example Configuration for Hatch**:\n\n```toml\n[build-system]\nrequires = [\"hatchling\", \"unidep\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\ndynamic = [\"dependencies\"]\n# Additional project configurations\n\n[tool.hatch.metadata.hooks.unidep]\n# Enable the unidep plugin\n\n[tool.hatch.metadata]\nallow-direct-references = true\n\n[tool.unidep]\n# Your dependencies configuration\n```\n\n## :desktop_computer: As a CLI\n\nSee [example](example/) for more information or check the output of `unidep -h` for the available sub commands:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep [-h]\n              {merge,install,install-all,conda-lock,pixi,pip-compile,pip,conda,version} ...\n\nUnified Conda and Pip requirements management.\n\npositional arguments:\n  {merge,install,install-all,conda-lock,pixi,pip-compile,pip,conda,version}\n                        Subcommands\n    merge               Combine multiple (or a single) `requirements.yaml` or\n                        `pyproject.toml` files into a single Conda installable\n                        `environment.yaml` file.\n    install             Automatically install all dependencies from one or\n                        more `requirements.yaml` or `pyproject.toml` files.\n                        This command first installs dependencies with Conda,\n                        then with Pip. Finally, it installs local packages\n                        (those containing the `requirements.yaml` or\n                        `pyproject.toml` files) using `pip install [-e]\n                        ./project`.\n    install-all         Install dependencies from all `requirements.yaml` or\n                        `pyproject.toml` files found in the current directory\n                        or specified directory. This command first installs\n                        dependencies using Conda, then Pip, and finally the\n                        local packages.\n    conda-lock          Generate a global `conda-lock.yml` file for a\n                        collection of `requirements.yaml` or `pyproject.toml`\n                        files. Additionally, create individual `conda-\n                        lock.yml` files for each `requirements.yaml` or\n                        `pyproject.toml` file consistent with the global lock\n                        file.\n    pixi                Generate a `pixi.toml` file from `requirements.yaml`\n                        or `pyproject.toml` files.\n    pip-compile         Generate a fully pinned `requirements.txt` file from\n                        one or more `requirements.yaml` or `pyproject.toml`\n                        files using `pip-compile` from `pip-tools`. This\n                        command consolidates all pip dependencies defined in\n                        the `requirements.yaml` or `pyproject.toml` files and\n                        compiles them into a single `requirements.txt` file,\n                        taking into account the specific versions and\n                        dependencies of each package.\n    pip                 Get the pip requirements for the current platform\n                        only.\n    conda               Get the conda requirements for the current platform\n                        only.\n    version             Print version information of unidep.\n\noptions:\n  -h, --help            show this help message and exit\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep merge`\n\nUse `unidep merge` to scan directories for `requirements.yaml` file(s) and combine them into an `environment.yaml` file.\nSee `unidep merge -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep merge -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep merge [-h] [-o OUTPUT] [-n NAME] [--stdout]\n                    [--selector {sel,comment}] [-d DIRECTORY] [--depth DEPTH]\n                    [-v]\n                    [-p {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}]\n                    [--skip-dependency SKIP_DEPENDENCY]\n                    [--ignore-pin IGNORE_PIN] [--overwrite-pin OVERWRITE_PIN]\n\nCombine multiple (or a single) `requirements.yaml` or `pyproject.toml` files\ninto a single Conda installable `environment.yaml` file. Example usage:\n`unidep merge --directory . --depth 1 --output environment.yaml` to search for\n`requirements.yaml` or `pyproject.toml` files in the current directory and its\nsubdirectories and create `environment.yaml`. These are the defaults, so you\ncan also just run `unidep merge`. For Pixi support, use `unidep pixi`.\n\noptions:\n  -h, --help            show this help message and exit\n  -o, --output OUTPUT   Output file for the conda environment, by default\n                        `environment.yaml`\n  -n, --name NAME       Name of the conda environment, by default `myenv`\n  --stdout              Output to stdout instead of a file\n  --selector {sel,comment}\n                        The selector to use for the environment markers, if\n                        `sel` then `- numpy # [linux]` becomes `sel(linux):\n                        numpy`, if `comment` then it remains `- numpy #\n                        [linux]`, by default `sel`\n  -d, --directory DIRECTORY\n                        Base directory to scan for `requirements.yaml` or\n                        `pyproject.toml` file(s), by default `.`\n  --depth DEPTH         Maximum depth to scan for `requirements.yaml` or\n                        `pyproject.toml` files, by default 1\n  -v, --verbose         Print verbose output\n  -p, --platform {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}\n                        The platform(s) to get the requirements for. Multiple\n                        platforms can be specified. If omitted, behavior is\n                        command-specific: platforms may be inferred from\n                        requirements files, otherwise the current platform is\n                        used.\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep install`\n\nUse `unidep install` on one or more `requirements.yaml` files and install the dependencies on the current platform using conda, then install the remaining dependencies with pip, and finally install the current package with `pip install [-e] .`.\nSee `unidep install -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep install -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep install [-h] [-v] [-e] [--skip-local] [--skip-pip]\n                      [--skip-conda] [--skip-dependency SKIP_DEPENDENCY]\n                      [--no-dependencies]\n                      [--conda-executable {conda,mamba,micromamba}]\n                      [-n CONDA_ENV_NAME | -p CONDA_ENV_PREFIX] [--dry-run]\n                      [--ignore-pin IGNORE_PIN]\n                      [--overwrite-pin OVERWRITE_PIN] [-f CONDA_LOCK_FILE]\n                      [--no-uv]\n                      files [files ...]\n\nAutomatically install all dependencies from one or more `requirements.yaml` or\n`pyproject.toml` files. This command first installs dependencies with Conda,\nthen with Pip. Finally, it installs local packages (those containing the\n`requirements.yaml` or `pyproject.toml` files) using `pip install [-e]\n./project`. Example usage: `unidep install .` for a single project. For\nmultiple projects: `unidep install ./project1 ./project2`. The command accepts\nboth file paths and directories containing a `requirements.yaml` or\n`pyproject.toml` file. Use `--editable` or `-e` to install the local packages\nin editable mode. See `unidep install-all` to install all `requirements.yaml`\nor `pyproject.toml` files in and below the current folder.\n\npositional arguments:\n  files                 The `requirements.yaml` or `pyproject.toml` file(s) to\n                        parse or folder(s) that contain those file(s), by\n                        default `.`\n\noptions:\n  -h, --help            show this help message and exit\n  -v, --verbose         Print verbose output\n  -e, --editable        Install the project in editable mode\n  --skip-local          Skip installing local dependencies\n  --skip-pip            Skip installing pip dependencies from\n                        `requirements.yaml` or `pyproject.toml`\n  --skip-conda          Skip installing conda dependencies from\n                        `requirements.yaml` or `pyproject.toml`\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --no-dependencies, --no-deps\n                        Skip installing dependencies from `requirements.yaml`\n                        or `pyproject.toml` file(s) and only install local\n                        package(s). Useful after installing a `conda-lock.yml`\n                        file because then all dependencies have already been\n                        installed.\n  --conda-executable {conda,mamba,micromamba}\n                        The conda executable to use\n  -n, --conda-env-name CONDA_ENV_NAME\n                        Name of the conda environment, if not provided, the\n                        currently active environment name is used, unless\n                        `--conda-env-prefix` is provided\n  -p, --conda-env-prefix CONDA_ENV_PREFIX\n                        Path to the conda environment, if not provided, the\n                        currently active environment path is used, unless\n                        `--conda-env-name` is provided\n  --dry-run, --dry      Only print the commands that would be run\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n  -f, --conda-lock-file CONDA_LOCK_FILE\n                        Path to the `conda-lock.yml` file to use for creating\n                        the new environment. Assumes that the lock file\n                        contains all dependencies. Must be used with `--conda-\n                        env-name` or `--conda-env-prefix`.\n  --no-uv               Disables the use of `uv` for pip install. By default,\n                        `uv` is used if it is available in the PATH.\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep install-all`\n\nUse `unidep install-all` on a folder with packages that contain `requirements.yaml` files and install the dependencies on the current platform using conda, then install the remaining dependencies with pip, and finally install the current package with `pip install [-e] ./package1 ./package2`.\nSee `unidep install-all -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep install -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep install [-h] [-v] [-e] [--skip-local] [--skip-pip]\n                      [--skip-conda] [--skip-dependency SKIP_DEPENDENCY]\n                      [--no-dependencies]\n                      [--conda-executable {conda,mamba,micromamba}]\n                      [-n CONDA_ENV_NAME | -p CONDA_ENV_PREFIX] [--dry-run]\n                      [--ignore-pin IGNORE_PIN]\n                      [--overwrite-pin OVERWRITE_PIN] [-f CONDA_LOCK_FILE]\n                      [--no-uv]\n                      files [files ...]\n\nAutomatically install all dependencies from one or more `requirements.yaml` or\n`pyproject.toml` files. This command first installs dependencies with Conda,\nthen with Pip. Finally, it installs local packages (those containing the\n`requirements.yaml` or `pyproject.toml` files) using `pip install [-e]\n./project`. Example usage: `unidep install .` for a single project. For\nmultiple projects: `unidep install ./project1 ./project2`. The command accepts\nboth file paths and directories containing a `requirements.yaml` or\n`pyproject.toml` file. Use `--editable` or `-e` to install the local packages\nin editable mode. See `unidep install-all` to install all `requirements.yaml`\nor `pyproject.toml` files in and below the current folder.\n\npositional arguments:\n  files                 The `requirements.yaml` or `pyproject.toml` file(s) to\n                        parse or folder(s) that contain those file(s), by\n                        default `.`\n\noptions:\n  -h, --help            show this help message and exit\n  -v, --verbose         Print verbose output\n  -e, --editable        Install the project in editable mode\n  --skip-local          Skip installing local dependencies\n  --skip-pip            Skip installing pip dependencies from\n                        `requirements.yaml` or `pyproject.toml`\n  --skip-conda          Skip installing conda dependencies from\n                        `requirements.yaml` or `pyproject.toml`\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --no-dependencies, --no-deps\n                        Skip installing dependencies from `requirements.yaml`\n                        or `pyproject.toml` file(s) and only install local\n                        package(s). Useful after installing a `conda-lock.yml`\n                        file because then all dependencies have already been\n                        installed.\n  --conda-executable {conda,mamba,micromamba}\n                        The conda executable to use\n  -n, --conda-env-name CONDA_ENV_NAME\n                        Name of the conda environment, if not provided, the\n                        currently active environment name is used, unless\n                        `--conda-env-prefix` is provided\n  -p, --conda-env-prefix CONDA_ENV_PREFIX\n                        Path to the conda environment, if not provided, the\n                        currently active environment path is used, unless\n                        `--conda-env-name` is provided\n  --dry-run, --dry      Only print the commands that would be run\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n  -f, --conda-lock-file CONDA_LOCK_FILE\n                        Path to the `conda-lock.yml` file to use for creating\n                        the new environment. Assumes that the lock file\n                        contains all dependencies. Must be used with `--conda-\n                        env-name` or `--conda-env-prefix`.\n  --no-uv               Disables the use of `uv` for pip install. By default,\n                        `uv` is used if it is available in the PATH.\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep conda-lock`\n\nUse `unidep conda-lock` on one or multiple `requirements.yaml` files and output the conda-lock file.\nOptionally, when using a monorepo with multiple subpackages (with their own `requirements.yaml` files), generate a lock file for each subpackage.\nSee `unidep conda-lock -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep conda-lock -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep conda-lock [-h] [--only-global] [--lockfile LOCKFILE]\n                         [--check-input-hash] [-d DIRECTORY] [--depth DEPTH]\n                         [-f FILE] [-v]\n                         [-p {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}]\n                         [--skip-dependency SKIP_DEPENDENCY]\n                         [--ignore-pin IGNORE_PIN]\n                         [--overwrite-pin OVERWRITE_PIN]\n                         ...\n\nGenerate a global `conda-lock.yml` file for a collection of\n`requirements.yaml` or `pyproject.toml` files. Additionally, create individual\n`conda-lock.yml` files for each `requirements.yaml` or `pyproject.toml` file\nconsistent with the global lock file. Example usage: `unidep conda-lock\n--directory ./projects` to generate conda-lock files for all\n`requirements.yaml` or `pyproject.toml` files in the `./projects` directory.\nUse `--only-global` to generate only the global lock file. The `--check-input-\nhash` option can be used to avoid regenerating lock files if the input hasn't\nchanged.\n\npositional arguments:\n  extra_flags           Extra flags to pass to `conda-lock lock`. These flags\n                        are passed directly and should be provided in the\n                        format expected by `conda-lock lock`. For example,\n                        `unidep conda-lock -- --micromamba`. Note that the\n                        `--` is required to separate the flags for `unidep\n                        conda-lock` from the flags for `conda-lock lock`.\n\noptions:\n  -h, --help            show this help message and exit\n  --only-global         Only generate the global lock file\n  --lockfile LOCKFILE   Specify a path for the global lockfile (default:\n                        `conda-lock.yml` in current directory). Path should be\n                        relative, e.g., `--lockfile ./locks/example.conda-\n                        lock.yml`.\n  --check-input-hash    Check existing input hashes in lockfiles before\n                        regenerating lock files. This flag is directly passed\n                        to `conda-lock`.\n  -d, --directory DIRECTORY\n                        Base directory to scan for `requirements.yaml` or\n                        `pyproject.toml` file(s), by default `.`\n  --depth DEPTH         Maximum depth to scan for `requirements.yaml` or\n                        `pyproject.toml` files, by default 1\n  -f, --file FILE       A single `requirements.yaml` or `pyproject.toml` file\n                        to use, or folder that contains that file. This is an\n                        alternative to using `--directory` which searches for\n                        all `requirements.yaml` or `pyproject.toml` files in\n                        the directory and its subdirectories.\n  -v, --verbose         Print verbose output\n  -p, --platform {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}\n                        The platform(s) to get the requirements for. Multiple\n                        platforms can be specified. If omitted, behavior is\n                        command-specific: platforms may be inferred from\n                        requirements files, otherwise the current platform is\n                        used.\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep pixi`\n\nUse `unidep pixi` to generate a `pixi.toml` file from your `requirements.yaml` or `pyproject.toml` files.\nThis enables using [Pixi](https://pixi.sh/) for solving/locking/installing while keeping UniDep as your source of truth.\n\nThe philosophy is **\"Let UniDep translate, let Pixi resolve\"**.\n\n**Workflow:**\n```bash\n# 1. Generate pixi.toml from your requirements\nunidep pixi\n\n# 2. Use pixi directly\npixi install\npixi lock\npixi run \u003ccmd\u003e\n```\n\n#### What `unidep pixi` generates\n\n- A `[workspace]` section with `name`, `channels`, and `platforms`\n- Conda deps in `[dependencies]`\n- PyPI deps in `[pypi-dependencies]`\n- Selector/platform-specific deps in `[target.\u003cplatform\u003e.dependencies]` and/or `[target.\u003cplatform\u003e.pypi-dependencies]`\n- Optional dependency groups as Pixi features (`[feature.\u003cgroup\u003e.*]`)\n- Local installable projects as editable path deps:\n  ```toml\n  [pypi-dependencies]\n  my_pkg = { path = \"./relative/path\", editable = true }\n  ```\n\nIn monorepo mode (multiple input files), UniDep builds feature sections per discovered project and composes environments from those features.\n\n#### Dependency reconciliation rules (important)\n\nWhen the same package appears from both conda and pip, UniDep applies deterministic rules before writing `pixi.toml`:\n\n1. If pip has extras (`foo[bar]`), pip wins.\n2. If only one side is pinned, pinned wins.\n3. On ties (both pinned or both unpinned), conda wins.\n4. For **universal conda vs target-specific pip** where both are pinned, target-specific pip intent is preserved on that target; the demoted universal entry is restored to other platforms as explicit target deps.\n\nVersion pins from repeated entries are merged when possible (for example `\u003e=1.7,\u003c2` + `\u003c1.16` → `\u003e=1.7,\u003c1.16`).\n\n#### Channels/platforms precedence\n\n- **Channels**\n  - If `--channel` is passed: use only CLI-provided channels.\n  - Else: collect channels from requirement files.\n  - Else fallback: `conda-forge`.\n- **Platforms**\n  - If `--platform` is passed: use CLI-provided platforms.\n  - Else: use platforms declared in files.\n  - Else: infer from selectors in dependencies.\n  - Else fallback: current platform.\n\n#### Example (single-file)\n\nInput (`requirements.yaml`):\n\n```yaml\nchannels:\n  - conda-forge\ndependencies:\n  - numpy \u003e=1.26\n  - pip: rich\n  - pip: uvloop  # [linux64]\noptional_dependencies:\n  dev:\n    - pytest\nplatforms:\n  - linux-64\n  - osx-64\n```\n\nRepresentative output shape (`pixi.toml`):\n\n```toml\n[workspace]\nname = \"my-project\"\nchannels = [\"conda-forge\"]\nplatforms = [\"linux-64\", \"osx-64\"]\n\n[dependencies]\nnumpy = \"\u003e=1.26\"\n\n[pypi-dependencies]\nrich = \"*\"\n\n[target.linux-64.pypi-dependencies]\nuvloop = \"*\"\n\n[feature.dev.dependencies]\npytest = \"*\"\n\n[environments]\ndefault = []\ndev = [\"dev\"]\n```\n\nSee `unidep pixi -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep pixi -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep pixi [-h] [-o OUTPUT] [-n NAME] [--stdout] [-c CHANNEL]\n                   [-d DIRECTORY] [--depth DEPTH] [-f FILE] [-v]\n                   [-p {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}]\n                   [--skip-dependency SKIP_DEPENDENCY]\n                   [--ignore-pin IGNORE_PIN] [--overwrite-pin OVERWRITE_PIN]\n\nGenerate a `pixi.toml` file from `requirements.yaml` or `pyproject.toml`\nfiles. Example usage: `unidep pixi` to generate a pixi.toml file. Use\n`--output` to specify a different output path. Use `--name` to set the project\nname. After generating, use `pixi lock` and `pixi install` directly.\n\noptions:\n  -h, --help            show this help message and exit\n  -o, --output OUTPUT   Output path for pixi.toml (default: pixi.toml in\n                        current directory)\n  -n, --name NAME       Name of the project (default: current directory name)\n  --stdout              Output to stdout instead of a file\n  -c, --channel CHANNEL\n                        Conda channel to include. Can be repeated. Overrides\n                        channels declared in requirements files. If omitted,\n                        channels are read from the requirements files\n                        (defaulting to conda-forge).\n  -d, --directory DIRECTORY\n                        Base directory to scan for `requirements.yaml` or\n                        `pyproject.toml` file(s), by default `.`\n  --depth DEPTH         Maximum depth to scan for `requirements.yaml` or\n                        `pyproject.toml` files, by default 1\n  -f, --file FILE       A single `requirements.yaml` or `pyproject.toml` file\n                        to use, or folder that contains that file. This is an\n                        alternative to using `--directory` which searches for\n                        all `requirements.yaml` or `pyproject.toml` files in\n                        the directory and its subdirectories.\n  -v, --verbose         Print verbose output\n  -p, --platform {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}\n                        The platform(s) to get the requirements for. Multiple\n                        platforms can be specified. If omitted, behavior is\n                        command-specific: platforms may be inferred from\n                        requirements files, otherwise the current platform is\n                        used.\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n\u003e [!TIP]\n\u003e Install Pixi-related optional dependencies with: `pip install \"unidep[pixi]\"`\n\n### `unidep pip-compile`\n\nUse `unidep pip-compile` on one or multiple `requirements.yaml` files and output a fully locked `requirements.txt` file using `pip-compile` from [`pip-tools`](https://pip-tools.readthedocs.io/en/latest/).\nSee `unidep pip-compile -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep pip-compile -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep pip-compile [-h] [-o OUTPUT_FILE] [-d DIRECTORY] [--depth DEPTH]\n                          [-v]\n                          [-p {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}]\n                          [--skip-dependency SKIP_DEPENDENCY]\n                          [--ignore-pin IGNORE_PIN]\n                          [--overwrite-pin OVERWRITE_PIN]\n                          ...\n\nGenerate a fully pinned `requirements.txt` file from one or more\n`requirements.yaml` or `pyproject.toml` files using `pip-compile` from `pip-\ntools`. This command consolidates all pip dependencies defined in the\n`requirements.yaml` or `pyproject.toml` files and compiles them into a single\n`requirements.txt` file, taking into account the specific versions and\ndependencies of each package. Example usage: `unidep pip-compile --directory\n./projects` to generate a `requirements.txt` file for all `requirements.yaml`\nor `pyproject.toml` files in the `./projects` directory. Use `--output-file\nrequirements.txt` to specify a different output file.\n\npositional arguments:\n  extra_flags           Extra flags to pass to `pip-compile`. These flags are\n                        passed directly and should be provided in the format\n                        expected by `pip-compile`. For example, `unidep pip-\n                        compile -- --generate-hashes --allow-unsafe`. Note\n                        that the `--` is required to separate the flags for\n                        `unidep pip-compile` from the flags for `pip-compile`.\n\noptions:\n  -h, --help            show this help message and exit\n  -o, --output-file OUTPUT_FILE\n                        Output file for the pip requirements, by default\n                        `requirements.txt`\n  -d, --directory DIRECTORY\n                        Base directory to scan for `requirements.yaml` or\n                        `pyproject.toml` file(s), by default `.`\n  --depth DEPTH         Maximum depth to scan for `requirements.yaml` or\n                        `pyproject.toml` files, by default 1\n  -v, --verbose         Print verbose output\n  -p, --platform {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}\n                        The platform(s) to get the requirements for. Multiple\n                        platforms can be specified. If omitted, behavior is\n                        command-specific: platforms may be inferred from\n                        requirements files, otherwise the current platform is\n                        used.\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep pip`\n\nUse `unidep pip` on a `requirements.yaml` file and output the pip installable dependencies on the current platform (default).\nSee `unidep pip -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep pip -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep pip [-h] [-f FILE] [-v]\n                  [-p {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}]\n                  [--skip-dependency SKIP_DEPENDENCY]\n                  [--ignore-pin IGNORE_PIN] [--overwrite-pin OVERWRITE_PIN]\n                  [--separator SEPARATOR]\n\nGet the pip requirements for the current platform only. Example usage: `unidep\npip --file folder1 --file folder2/requirements.yaml --separator ' ' --platform\nlinux-64` to extract all the pip dependencies specific to the linux-64\nplatform. Note that the `--file` argument can be used multiple times to\nspecify multiple `requirements.yaml` or `pyproject.toml` files and that --file\ncan also be a folder that contains a `requirements.yaml` or `pyproject.toml`\nfile.\n\noptions:\n  -h, --help            show this help message and exit\n  -f, --file FILE       The `requirements.yaml` or `pyproject.toml` file to\n                        parse, or folder that contains that file, by default\n                        `.`\n  -v, --verbose         Print verbose output\n  -p, --platform {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}\n                        The platform(s) to get the requirements for. Multiple\n                        platforms can be specified. If omitted, behavior is\n                        command-specific: platforms may be inferred from\n                        requirements files, otherwise the current platform is\n                        used.\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n  --separator SEPARATOR\n                        The separator between the dependencies, by default ` `\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n### `unidep conda`\n\nUse `unidep conda` on a `requirements.yaml` file and output the conda installable dependencies on the current platform (default).\nSee `unidep conda -h` for more information:\n\n\u003c!-- CODE:BASH:START --\u003e\n\u003c!-- echo '```bash' --\u003e\n\u003c!-- unidep conda -h --\u003e\n\u003c!-- echo '```' --\u003e\n\u003c!-- CODE:END --\u003e\n\u003c!-- OUTPUT:START --\u003e\n\u003c!-- ⚠️ This content is auto-generated by `markdown-code-runner`. --\u003e\n```bash\nusage: unidep conda [-h] [-f FILE] [-v]\n                    [-p {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}]\n                    [--skip-dependency SKIP_DEPENDENCY]\n                    [--ignore-pin IGNORE_PIN] [--overwrite-pin OVERWRITE_PIN]\n                    [--separator SEPARATOR]\n\nGet the conda requirements for the current platform only. Example usage:\n`unidep conda --file folder1 --file folder2/requirements.yaml --separator ' '\n--platform linux-64` to extract all the conda dependencies specific to the\nlinux-64 platform. Note that the `--file` argument can be used multiple times\nto specify multiple `requirements.yaml` or `pyproject.toml` files and that\n--file can also be a folder that contains a `requirements.yaml` or\n`pyproject.toml` file.\n\noptions:\n  -h, --help            show this help message and exit\n  -f, --file FILE       The `requirements.yaml` or `pyproject.toml` file to\n                        parse, or folder that contains that file, by default\n                        `.`\n  -v, --verbose         Print verbose output\n  -p, --platform {linux-64,linux-aarch64,linux-ppc64le,osx-64,osx-arm64,win-64}\n                        The platform(s) to get the requirements for. Multiple\n                        platforms can be specified. If omitted, behavior is\n                        command-specific: platforms may be inferred from\n                        requirements files, otherwise the current platform is\n                        used.\n  --skip-dependency SKIP_DEPENDENCY\n                        Skip installing a specific dependency that is in one\n                        of the `requirements.yaml` or `pyproject.toml` files.\n                        This option can be used multiple times, each time\n                        specifying a different package to skip. For example,\n                        use `--skip-dependency pandas` to skip installing\n                        pandas.\n  --ignore-pin IGNORE_PIN\n                        Ignore the version pin for a specific package, e.g.,\n                        `--ignore-pin numpy`. This option can be repeated to\n                        ignore multiple packages.\n  --overwrite-pin OVERWRITE_PIN\n                        Overwrite the version pin for a specific package,\n                        e.g., `--overwrite-pin 'numpy=1.19.2'`. This option\n                        can be repeated to overwrite the pins of multiple\n                        packages.\n  --separator SEPARATOR\n                        The separator between the dependencies, by default ` `\n```\n\n\u003c!-- OUTPUT:END --\u003e\n\n## ❓ FAQ\n\nHere is a list of questions we have either been asked by users or potential pitfalls we hope to help users avoid:\n\n### **Q: When to use UniDep?**\n\n**A:** UniDep is particularly useful for setting up full development environments that require both Python *and* non-Python dependencies (e.g., CUDA, compilers, etc.) with a single command.\n\nIn fields like research, data science, robotics, AI, and ML projects, it is common to work from a locally cloned Git repository.\n\nSetting up a full development environment can be a pain, especially if you need to install non Python dependencies like compilers, low-level numerical libraries, or CUDA (luckily Conda has all of them).\nTypically, instructions are different for each OS and their corresponding package managers (`apt`, `brew`, `yum`, `winget`, etc.).\n\nWith UniDep, you can specify all your Pip and Conda dependencies in a single file.\nTo get set up on a new machine, you just need to install Conda (we recommend [micromamba](https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html)) and run `pip install unidep; unidep install-all -e` in your project directory, to install all dependencies and local packages in editable mode in the current Conda environment.\n\nFor fully reproducible environments, you can run `unidep conda-lock` to generate a `conda-lock.yml` file.\nThen, run `conda env create -f conda-lock.yml -n myenv` to create a new Conda environment with all the third-party dependencies.\nFinally, run `unidep install-all -e --no-dependencies` to install all your local packages in editable mode.\n\nFor those who prefer not to use Conda, you can simply run `pip install -e .` on a project using UniDep.\nYou'll need to install the non-Python dependencies yourself, but you'll have a list of them in the `requirements.yaml` file.\n\nIn summary, use UniDep if you:\n\n- Prefer installing packages with conda but still want your package to be pip installable.\n- Are tired of synchronizing your Pip requirements (`requirements.txt`) and Conda requirements (`environment.yaml`).\n- Want a low-effort, comprehensive development environment setup.\n\n### **Q: Just show me a full example!**\n\n**A:** Check out the [`example` folder](https://github.com/basnijholt/unidep/tree/main/example).\n\n### **Q: Uses of UniDep in the wild?**\n\n**A:** UniDep really shines when used in a monorepo with multiple dependent projects, however, since these are typically private, we cannot share them.\n\nHowever, an example of a single package that is public is [`home-assistant-streamdeck-yaml`](https://github.com/basnijholt/home-assistant-streamdeck-yaml/).\nThis is a Python package that allows to interact with [Home Assistant](https://www.home-assistant.io/) from an Elgato Stream Deck connected via USB to e.g., a Raspberry Pi.\nIt requires a couple of system dependencies (e.g., `libusb` and `hidapi`), which are typically installed with `apt` or `brew`.\nThe [`README.md`](https://github.com/basnijholt/home-assistant-streamdeck-yaml/blob/main/README.md) shows different installation instructions on Linux, MacOS, and Windows for non-Conda installs, however, with UniDep, we can just use `unidep install .` on all platforms.\nIt is fully configured via [`pyproject.toml`](https://github.com/basnijholt/home-assistant-streamdeck-yaml/blob/main/pyproject.toml).\nThe 2 `Dockerfile`s show 2 different ways of using UniDep:\n\n1. [`Dockerfile.locked`](https://github.com/basnijholt/home-assistant-streamdeck-yaml/blob/a1b9966398dfe748804f058f82d546e47cd7f722/Dockerfile.locked): Installing `conda-lock.yml` (generated with `unidep conda-lock`) and then `pip install .` the local package.\n2. [`Dockerfile.latest`](https://github.com/basnijholt/home-assistant-streamdeck-yaml/blob/a1b9966398dfe748804f058f82d546e47cd7f722/Dockerfile.latest): Using `unidep install .` to install all dependencies, first with conda, then pip, then the local package.\n\n### **Q: How do I force PyPI instead of a local path for one dependency?**\n\n**A:** Use `use: pypi` to force the PyPI package even during development (see [Overriding Nested Vendor Copies](#overriding-nested-vendor-copies-with-use)). This is especially useful for overriding nested vendor copies while keeping other local dependencies editable.\n\n```yaml\nlocal_dependencies:\n  - local: ./path/to/dep\n    pypi: my-package\u003e=1.0\n    use: pypi  # Force PyPI, skip local path\n```\n\n### **Q: How do I ignore a local dependency entirely?**\n\n**A:** Set `use: skip` on that entry. It won't be installed and UniDep won't recurse into it. See [Overriding Nested Vendor Copies](#overriding-nested-vendor-copies-with-use) for details.\n\n### **Q: A submodule brings its own copy of package X. How do I avoid conflicts?**\n\n**A:** Use `use: pypi` as shown in [Overriding Nested Vendor Copies](#overriding-nested-vendor-copies-with-use). In short:\n\n```yaml\nlocal_dependencies:\n  - ./third_party/foo              # Keep foo editable\n  - local: ./third_party/foo/third_party/bar\n    pypi: my-bar\u003e=2.0\n    use: pypi                      # Force YOUR PyPI build of bar\n```\n\nThis propagates to **every** nested reference, so foo's bundled bar gets replaced with your PyPI package.\n\n### **Q: How is this different from conda/mamba/pip?**\n\n**A:** UniDep uses pip and conda under the hood to install dependencies, but it is not a replacement for them. UniDep will print the commands it runs, so you can see exactly what it is doing.\n\n### **Q: I found a project using unidep, now what?**\n\n**A:** You can install it like *any other Python package* using `pip install`.\nHowever, to take full advantage of UniDep's functionality, clone the repository and run `unidep install-all -e` in the project directory.\nThis installs all dependencies in editable mode in the current Conda environment.\n\n### **Q: How to handle local dependencies that do not use UniDep?**\n\n**A:** You can use the `local_dependencies` field in the `requirements.yaml` or `pyproject.toml` file to specify local dependencies.\nHowever, *if* a local dependency is *not* managed by UniDep, it will skip installing its dependencies!\n\nTo include all its dependencies, either convert the package to use UniDep (🏆), or maintain a separate `requirements.yaml` file, e.g., for a package called `foo` create, `foo-requirements.yaml`:\n\n```yaml\ndependencies:\n  # List the dependencies of foo here\n  - numpy\n  - scipy\n  - matplotlib\n  - bar\nlocal_dependencies:\n  - ./path/to/foo  # This is the path to the package\n```\n\nThen, in the `requirements.yaml` or `pyproject.toml` file of the package that uses `foo`, list `foo-requirements.yaml` as a local dependency:\n\n```yaml\nlocal_dependencies:\n  - ./path/to/foo-requirements.yaml\n```\n\n### **Q: Can't Conda already do this?**\n\n**A:** Not quite. Conda can indeed install both Conda and Pip dependencies via an `environment.yaml` file, however, it does not work the other way around.\nPip cannot install the `pip` dependencies from an `environment.yaml` file.\nThis means, that if you want your package to be installable with `pip install -e .` *and* support Conda, you need to maintain two separate files: `environment.yaml` and `requirements.txt` (or specify these dependencies in `pyproject.toml` or `setup.py`).\n\n### **Q: What is the difference between `conda-lock` and `unidep conda-lock`?**\n\n**A:** [`conda-lock`](https://github.com/conda/conda-lock) is a standalone tool that creates a `conda-lock.yml` file from a `environment.yaml` file.\nOn the other hand, `unidep conda-lock` is a command within the UniDep tool that also generates a `conda-lock.yml` file (leveraging `conda-lock`), but it does so from one or more `requirements.yaml` or `pyproject.toml` files.\nWhen managing multiple dependent projects (e.g., in a monorepo), a unique feature of `unidep conda-lock` is its ability to create **_consistent_** individual `conda-lock.yml` files for each `requirements.yaml` or `pyproject.toml` file, ensuring consistency with a global `conda-lock.yml` file.\nThis feature is not available in the standalone `conda-lock` tool.\n\n### **Q: What is the difference between `hatch-conda` / `pdm-conda` and `unidep`?**\n\n**A:** [`hatch-conda`](https://github.com/OldGrumpyViking/hatch-conda) is a plugin for [`hatch`](https://hatch.pypa.io/latest/) that integrates Conda environments into `hatch`.\nA key difference is that `hatch-conda` keeps Conda and Pip dependencies separate, choosing to install packages with either Conda *or* Pip.\nThis results in Conda being a hard requirement, for example, if `numba` is specified for Conda, it cannot be installed with Pip despite its availability on PyPI.\n\nIn contrast, [UniDep](https://github.com/basnijholt/unidep/) does not require Conda.\nWithout Conda, it can still install any dependency that is available on PyPI (e.g., `numba` is both Conda and Pip installable).\nHowever, without Conda, UniDep will not install dependencies exclusive to Conda.\nThese Conda-specific dependencies can often be installed through alternative package managers like `apt`, `brew`, `yum`, or by building them from source.\n\nAnother key difference is that `hatch-conda` is managing [Hatch environments](https://hatch.pypa.io/latest/environment/) whereas `unidep` can install Pip dependencies in the current Python environment (venv, Conda, Hatch, etc.), however, to optimally use UniDep, we recommend using Conda environments to additionally install non-Python dependencies.\n\nSimilar to `hatch-conda`, `unidep` also integrates with Hatchling, but it works in a slightly different way.\n\n**A:** [`pdm-conda`](https://github.com/macro128/pdm-conda) is a plugin for [`pdm`](https://pdm-project.org/) designed to facilitate the use of Conda environments in conjunction with `pdm`.\nLike `hatch-conda`, `pdm-conda` opts to install packages either with Conda or Pip.\nIt is closely integrated with `pdm`, primarily enabling the inclusion of Conda packages in `pdm`'s lock file (`pdm.lock`).\nHowever, `pdm-conda` lacks extensive cross-platform support.\nFor instance, when adding a package like Numba using `pdm-conda`, it gets locked to the current platform (e.g., osx-arm64) without the flexibility to specify compatibility for other platforms such as linux64.\nIn contrast, UniDep allows for cross-platform compatibility, enabling the user to specify dependencies for multiple platforms.\nUniDep currently does not support `pdm`, but it does support Hatchling and Setuptools.\n\nUniDep stands out from both `pdm-conda` and `hatch-conda` with its additional functionalities, particularly beneficial for monorepos and projects spanning multiple operating systems. For instance:\n\n1. **Conda Lock Files**: Create `conda-lock.yml` files for all packages with consistent sub-lock files per package.\n2. **CLI tools**: Provides tools like `unidep install-all -e` which will install multiple local projects (e.g., in monorepo) and all its dependencies first with Conda, then remaining ones with Pip, and finally the local dependencies in editable mode with Pip.\n3. **Conda Environment Files**: Can create standard Conda `environment.yaml` files by combining the dependencies from many `requirements.yaml` or `pyproject.toml` files.\n4. **Platform-Specific Dependencies**: Allows specifying dependencies for certain platforms (e.g., linux64, osx-arm64), enhancing cross-platform compatibility.\n\n## :hammer_and_wrench: Troubleshooting\n\n### `pip install` fails with `FileNotFoundError`\n\nWhen using a project that uses `local_dependencies: [../not/current/dir]` in the `requirements.yaml` file:\n\n```yaml\nlocal_dependencies:\n  # File in a different directory than the pyproject.toml file\n  - ../common-requirements.yaml\n```\n\nYou might get an error like this when using a `pip` version older than `22.0`:\n\n```bash\n$ pip install /path/to/your/project/using/unidep\n  ...\n  File \"/usr/lib/python3.8/pathlib.py\", line 1222, in open\n    return io.open(self, mode, buffering, encoding, errors, newline,\n  File \"/usr/lib/python3.8/pathlib.py\", line 1078, in _opener\n    return self._accessor.open(self, flags, mode)\nFileNotFoundError: [Errno 2] No such file or directory: '/tmp/common-requirements.yaml'\n```\n\nThe solution is to upgrade `pip` to version `22.0` or newer:\n\n```bash\npip install --upgrade pip\n```\n\n## :warning: Limitations\n\n- **Conda-Focused**: Best suited for Conda environments. However, note that having `conda` is not a requirement to install packages that use UniDep.\n- **Setuptools and Hatchling only**: Currently only works with setuptools and Hatchling, not flit, poetry, or other build systems. Open an issue if you'd like to see support for other build systems.\n- No [logic operators in platform selectors](https://github.com/basnijholt/unidep/issues/5) and [no Python selectors](https://github.com/basnijholt/unidep/issues/7).\n\n* * *\n\nTry `unidep` today for a streamlined approach to managing your Conda environment dependencies across multiple projects! 🎉👏\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasnijholt%2Funidep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbasnijholt%2Funidep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasnijholt%2Funidep/lists"}