{"id":13492845,"url":"https://github.com/jaraco/pip-run","last_synced_at":"2025-12-13T21:04:15.645Z","repository":{"id":42789765,"uuid":"50319078","full_name":"jaraco/pip-run","owner":"jaraco","description":"pip-run - dynamic dependency loader for Python","archived":false,"fork":false,"pushed_at":"2025-05-14T06:53:26.000Z","size":931,"stargazers_count":138,"open_issues_count":11,"forks_count":19,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-14T07:48:45.214Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaraco.png","metadata":{"files":{"readme":"README.rst","changelog":"NEWS.rst","contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"tidelift":"pypi/pip-run"}},"created_at":"2016-01-25T01:59:13.000Z","updated_at":"2025-05-14T06:53:29.000Z","dependencies_parsed_at":"2024-01-07T17:11:15.849Z","dependency_job_id":"a7adaf22-72ff-4990-a363-8ac24baf15ed","html_url":"https://github.com/jaraco/pip-run","commit_stats":{"total_commits":713,"total_committers":20,"mean_commits":35.65,"dds":0.04207573632538575,"last_synced_commit":"1a489d26ee58b317ad79cecd09f0d96e595bc583"},"previous_names":["jaraco/rwt"],"tags_count":105,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaraco%2Fpip-run","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaraco%2Fpip-run/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaraco%2Fpip-run/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaraco%2Fpip-run/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaraco","download_url":"https://codeload.github.com/jaraco/pip-run/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436944,"owners_count":22070946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-07-31T19:01:09.802Z","updated_at":"2025-12-13T21:04:15.636Z","avatar_url":"https://github.com/jaraco.png","language":"Python","readme":".. image:: https://img.shields.io/pypi/v/pip-run.svg\n   :target: https://pypi.org/project/pip-run\n\n.. image:: https://img.shields.io/pypi/pyversions/pip-run.svg\n\n.. image:: https://github.com/jaraco/pip-run/actions/workflows/main.yml/badge.svg\n   :target: https://github.com/jaraco/pip-run/actions?query=workflow%3A%22tests%22\n   :alt: tests\n\n.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\n    :target: https://github.com/astral-sh/ruff\n    :alt: Ruff\n\n.. image:: https://readthedocs.org/projects/pip-run/badge/?version=latest\n   :target: https://pip-run.readthedocs.io/en/latest/?badge=latest\n\n.. image:: https://img.shields.io/badge/skeleton-2025-informational\n   :target: https://blog.jaraco.com/skeleton\n\n.. image:: https://tidelift.com/badges/package/pypi/pip-run\n   :target: https://tidelift.com/subscription/pkg/pypi-pip-run?utm_source=pypi-pip-run\u0026utm_medium=readme\n\n``pip-run`` provides on-demand temporary package installation\nfor a single execution run.\n\nIt replaces this series of commands (or their Windows equivalent)::\n\n    $ virtualenv --python pythonX.X --system-site-packages $temp/env\n    $ $temp/env/bin/pip install pkg1 pkg2 -r reqs.txt\n    $ $temp/env/bin/python ...\n    $ rm -rf $temp/env\n\nWith this single-line command::\n\n    $ py -X.X -m pip-run pkg1 pkg2 -r reqs.txt -- ...\n\n.. note:: ``py`` is the Python Launcher for\n   `Windows \u003chttps://docs.python.org/3/using/windows.html#launcher\u003e`_\n   or `Unix \u003chttps://python-launcher.app/\u003e`_ and isn't required to use\n   pip-run, but is used in this guide and recommended for anyone to get\n   a portable, cruft-free Python invocation.\n\nFeatures include\n\n- Automatically infers dependencies from imports.\n- Downloads missing dependencies and makes their packages available for import.\n- Installs packages to a special staging location such that they're not installed after the process exits.\n- Relies on pip to cache downloads of such packages for reuse.\n- Leaves no trace of its invocation (except files in pip's cache).\n- Supersedes installed packages when required.\n- Re-uses the pip tool chain for package installation.\n\n``pip-run`` is not intended to solve production dependency management, but does aim to address the other, one-off scenarios around dependency management:\n\n- running scripts with dependencies\n- trials and experiments\n- build setup\n- test runners\n- interactive development\n- bug triage\n\n``pip-run`` is a complement to Pip and Virtualenv, intended to more\nreadily address the on-demand needs.\n\nInstallation\n============\n\n``pip-run`` is meant to be installed in the system site packages\nalongside pip, though it can also be installed in a virtualenv.\n\nUsage\n=====\n\n- as script launcher\n- as runtime dependency context manager\n- as interactive interpreter in dependency context\n- as module launcher (akin to `python -m`)\n- as a shell shebang (``#!/usr/bin/env pip-run``), to create single-file Python tools\n\nInvoke ``pip-run`` from the command-line using the console entry\nscript (simply ``pip-run``) or using the module executable (\n``python -m pip-run``). This latter usage is particularly convenient\nfor testing a command across various Python versions.\n\nParameters following pip-run are passed directly to ``pip install``,\nso ``pip-run numpy`` will install ``numpy`` (reporting any work done\nduring the install) and ``pip-run -v -r requirements.txt`` will verbosely\ninstall all the requirements listed in a file called requirements.txt\n(quiet is the default).\nAny `environment variables honored by pip\n\u003chttps://pip.pypa.io/en/stable/user_guide/#environment-variables\u003e`_\nare also honored.\n\nFollowing the parameters to ``pip install``, one may optionally\ninclude a ``--`` after which any parameters will be executed\nby a Python interpreter in the context or directly if prefixed by\n``!``.\n\nSee ``pip-run --help`` for more details.\n\nExamples\n========\n\nThe `examples folder in this project\n\u003chttps://github.com/jaraco/pip-run/tree/master/examples\u003e`_\nincludes some examples demonstrating\nthe power and usefulness of the project. Read the docs on those examples\nfor instructions.\n\nModule Script Runner\n--------------------\n\nPerhaps the most powerful usage of ``pip-run`` is its ability to invoke\nexecutable modules and packages via\n`runpy \u003chttps://docs.python.org/3/library/runpy.html\u003e`_ (aka\n``python -m``)::\n\n    $ pip-run cowsay -- -m cowsay \"moove over, pip-run\"\n\n      -------------------\n    \u003c moove over, pip-run \u003e\n      -------------------\n       \\   ^__^\n        \\  (oo)\\_______\n           (__)\\       )\\/\\\n               ||----w |\n               ||     ||\n\n.. image:: docs/cowsay.svg\n   :alt: cowsay example animation\n\nModule Executable Runner\n------------------------\n\nSome package tools, like `ranger \u003chttps://github.com/ranger/ranger\u003e`_, are\ninvoked with a unique executable instead of a module. ``pip-run`` can\nrun an executable from a package if it is prependend by a ``!``::\n\n    $ pip-run ranger-fm -- '!ranger'\n\nCommand Runner\n--------------\n\nNote that everything after the -- is passed to the python invocation,\nso it's possible to have a one-liner that runs under a dependency\ncontext::\n\n    $ python -m pip-run requests -- -c \"import requests; print(requests.get('https://pypi.org/project/pip-run').status_code)\"\n    200\n\nAs long as ``pip-run`` is installed in each of Python environments\non the system, this command can be readily repeated on the other\npython environments by specifying the relevant interpreter::\n\n    $ py -3.7 -m pip-run ...\n\nScript Runner\n-------------\n\n``pip-run`` can run a Python file with indicated dependencies. Because\narguments after ``--`` are passed directly to the Python interpreter\nand because the Python interpreter will run any script, invoking a script\nwith dependencies is easy. Consider this script \"myscript.py\":\n\n.. code-block:: python\n\n    #!/usr/bin/env python\n\n    import requests\n\n    req = requests.get('https://pypi.org/project/pip-run')\n    print(req.status_code)\n\nTo invoke it while making sure requests is present:\n\n    $ pip-run requests -- myscript.py\n\n``pip-run`` will make sure that requests is installed then invoke\nthe script in a Python interpreter configured with requests and its\ndependencies.\n\nFor added convenience when running scripts, ``pip-run`` will infer\nthe beginning of Python parameters if it encounters a filename\nof a Python script that exists, allowing for omission of the ``--``\nfor script invocation:\n\n    $ pip-run requests myscript.py\n\nScript-declared Dependencies\n----------------------------\n\nBuilding on Script Runner above, ``pip-run`` also allows\ndependencies to be declared in the script itself so that\nthe user need not specify them at each invocation.\n\nTo declare dependencies in a script, add a ``__requires__``\nvariable or `Inline Script Metadata \u003chttps://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata\u003e`_ section to the script:\n\n.. code-block:: python\n\n    #!/usr/bin/env python\n\n    __requires__ = ['requests']\n\n    # or inline script\n\n    # /// script\n    # dependencies = ['requests']\n    # ///\n\n    import requests\n\n    req = requests.get('https://pypi.org/project/pip-run')\n    print(req.status_code)\n\nWith that declaration in place, one can now invoke ``pip-run`` without\ndeclaring any parameters to pip::\n\n    $ pip-run myscript.py\n    200\n\nThe format for requirements must follow `PEP 508 \u003chttps://www.python.org/dev/peps/pep-0508/\u003e`_.\n\nInferred Script Dependencies\n----------------------------\n\nIf no dependencies are declared, or if an ellipsis is used in a Python-based ``__requires__`` directive, ``pip-run`` will infer the dependencies from a script based on the imports using `coherent.deps \u003chttps://pypi.org/project/coherent.deps\u003e`_.\n\n.. code-block:: python\n\n    import requests\n\n    req = requests.get('https://pypi.org/project/coherent.deps')\n    print(req.status_code)\n\nIn some cases, a dependency is needed that's not implied by an import. In that case, use an ellipsis to infer in addition to the explicit requirements:\n\n.. code-block:: python\n\n    __requires__ = ['pytest', ...]\n\n    import requests\n\n    def test_something():\n        req = requests.get('https://pypi.org/project/coherent.deps')\n        assert req.status_code == 200\n\n\nSingle-script Tools and Shebang Support\n---------------------------------------\n\nCombined with in-script dependencies, ``pip-run`` can be used as a shebang to\ncreate fully self-contained scripts that install and run their own\ndependencies, as long as ``pip-run`` is installed on the system ``PATH``.\nConsider, for example, the ``pydragon`` script:\n\n.. code-block:: shell\n\n    #!/usr/bin/env pip-run\n    __requires__ = ['requests', 'beautifulsoup4', 'cowsay']\n    import requests\n    from bs4 import BeautifulSoup as BS\n    import cowsay\n    res = requests.get('https://python.org')\n    b = BS(res.text, 'html.parser')\n    cowsay.dragon(b.find(\"div\", class_=\"introduction\").get_text())\n\nThis executable script is available in the repo as ``examples/pydragon`` (for\nUnix) and ``examples/pydragon.py`` (for Windows [2]_). Executing this script is\nequivalent to executing ``pip-run pydragon``.\n\nBy default, the script will assemble the dependencies on each invocation,\nwhich may be inconvenient for a script. See `Environment Persistence\n\u003c#Environment-Persistence\u003e`_ for a technique to persist the assembled\ndependencies across invocations. One may inject ``PIP_RUN_RETENTION_STRATEGY=persist``\nin the shebang, but be aware that doing so breaks Windows portability.\n\n.. [2] ``.PY`` must exist in the PATHEXT for Python scripts to be executable. See `this documentation \u003chttps://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#path-information\u003e`_ for more background.\n\nOther Script Directives\n-----------------------\n\n``pip-run`` also recognizes a global ``__index_url__`` attribute. If present,\nthis value will supply ``--index-url`` to pip with the attribute value,\nallowing a script to specify a custom package index:\n\n.. code-block:: python\n\n    #!/usr/bin/env python\n\n    __requires__ = ['my_private_package']\n    __index_url__ = 'https://my.private.index/'\n\n    import my_private_package\n    ...\n\nExtracting Requirements\n-----------------------\n\nAfter having used ``pip-run`` to run scripts, it may be desirable to extract the requirements from the ``__requires__`` variable or Inline Script Metadata section of a\nscript to install those more permanently. pip-run provides a routine to facilitate\nthis case::\n\n    $ py -m pip_run.read-deps examples/pydragon\n    requests beautifulsoup4 cowsay\n\nOn Unix, it is possible to pipe this result directly to pip::\n\n    $ pip install $(py -m pip_run.read-deps examples/pydragon)\n\nTo generate a requirements.txt file, specify a newline separator::\n\n    $ py -m pip_run.read-deps --separator newline examples/pydragon \u003e requirements.txt\n\nAnd since `pipenv \u003chttps://docs.pipenv.org/\u003e`_ uses the same syntax,\nthe same technique works for pipenv::\n\n    $ pipenv install $(python -m pip_run.read-deps script.py)\n\nInteractive Interpreter\n-----------------------\n\n``pip-run`` also offers a painless way to run a Python interactive\ninterpreter in the context of certain dependencies::\n\n    $ /clean-install/python -m pip-run boto\n    \u003e\u003e\u003e import boto\n    \u003e\u003e\u003e\n\nExperiments and Testing\n-----------------------\n\nBecause ``pip-run`` provides a single-command invocation, it\nis great for experiments and rapid testing of various package\nspecifications.\n\nConsider a scenario in which one wishes to create an environment\nwhere two different versions of the same package are installed,\nsuch as to replicate a broken real-world environment. Stack two\ninvocations of pip-run to get two different versions installed::\n\n    $ pip-run keyring==21.8.0 -- -m pip-run keyring==22.0.0 -- -c \"import importlib.metadata, pprint; pprint.pprint([dist._path for dist in importlib.metadata.distributions() if dist.metadata['name'] == 'keyring'])\"\n    [PosixPath('/var/folders/03/7l0ffypn50b83bp0bt07xcch00n8zm/T/pip-run-a3xvd267/keyring-22.0.0.dist-info'),\n    PosixPath('/var/folders/03/7l0ffypn50b83bp0bt07xcch00n8zm/T/pip-run-1fdjsgfs/keyring-21.8.0.dist-info')]\n\n.. todo: illustrate example here\n\nIPython Inference\n-----------------\n\nIf IPython is specified as one of the dependencies, the Python\ninterpreter will be launched via IPython (using ``-m IPython``)\nfor interactive mode. This behaviour may be toggled off by\nsetting the environment variable ``PIP_RUN_IPYTHON_MODE=ignore``.\n\nHow Does It Work\n================\n\n``pip-run`` effectively does the following:\n\n- ``pip install -t $TMPDIR``\n- ``PYTHONPATH=$TMPDIR python``\n- cleanup\n\nFor specifics, see `pip_run.run()\n\u003chttps://github.com/jaraco/pip-run/blob/master/pip_run/__init__.py#L9-L16\u003e`_.\n\n\nEnvironment Persistence\n=======================\n\n``pip-run`` honors the ``PIP_RUN_RETENTION_STRATEGY`` variable. If unset or\nset to ``destroy``, dependencies are installed to a temporary directory on\neach invocation (and deleted after). Setting this variable to ``persist`` will\ninstead create or re-use a directory in the user's cache, only installing the\ndependencies if the directory doesn't already exist. A separate cache is\nmaintained for each combination of requirements specified.\n\n``persist`` strategy can greatly improve startup performance at the expense of\nstaleness and accumulated cruft.\n\n``persist`` also accepts a parameter \"max age\". Setting the max age will\ndelete any cached environments older than the indicated age. For example,\n``PIP_RUN_RETENTION_STRATEGY=persist {\"max age\": \"1 day\"}`` (or\n``86400``) will retain the environment for only one day or\n``PIP_RUN_RETENTION_STRATEGY=persist {\"max age\": \"6 months\"}`` will\ndo the same for half a year.\n\nWithout ``PIP_RUN_RETENTION_STRATEGY=persist`` (or with ``=destroy``),\n``pip-run`` will re-install dependencies every time a script runs, silently\nadding to the startup time while dependencies are installed into an ephemeral\nenvironment, depending on how many dependencies there are and whether the\ndependencies have been previously downloaded to the local pip cache. Use\n``pip-run -v ...`` to see the installation activity.\n\nThe location of the cache can be revealed with this command::\n\n    py -c 'import importlib; print(importlib.import_module(\"pip_run.retention.persist\").paths.user_cache_path)'\n\n\nLimitations\n===========\n\n- Due to limitations with ``pip``, ``pip-run`` cannot run with \"editable\"\n  (``-e``) requirements.\n\n- ``pip-run`` uses a ``sitecustomize`` module to ensure that ``.pth`` files\n  in the requirements are installed. As a result, any environment\n  that has a ``sitecustomize`` module will find that module masked\n  when running under ``pip-run``.\n\nComparison with pipx\n====================\n\nThe `pipx project \u003chttps://pypi.org/project/pipx/\u003e`_ is another mature\nproject with similar goals. Both projects expose a project and its\ndependencies in ephemeral environments. The main difference is pipx\nprimarily exposes Python binaries (console scripts) from those\nenvironments whereas pip-run exposes a Python context (including\nrunpy scripts).\n\n.. list-table::\n   :widths: 30 10 10\n   :header-rows: 1\n\n   * - Feature\n     - pip-run\n     - pipx\n   * - user-mode operation\n     - ✓\n     - ✓\n   * - invoke console scripts\n     - ✓\n     - ✓\n   * - invoke runpy modules\n     - ✓\n     -\n   * - run standalone scripts\n     - ✓\n     -\n   * - interactive interpreter with deps\n     - ✓\n     -\n   * - dependency inference\n     - ✓\n     -\n   * - re-use existing environment\n     - ✓\n     -\n   * - ephemeral environments\n     - ✓\n     - ✓\n   * - persistent environments\n     - ✓\n     - ✓\n   * - PEP 582 support\n     -\n     - ✓\n   * - Specify optional dependencies\n     - ✓\n     -\n   * - Python 2 support\n     - ✓\n     -\n\nComparison with virtualenvwrapper mktmpenv\n==========================================\n\nThe `virtualenvwrapper project \u003chttps://pypi.org/project/virtualenvwrapper/\u003e`_\nattempts to address some of the use-cases that pip-run solves,\nespecially with the ``mktmpenv`` command, which destroys the\nvirtualenv after deactivation. The main difference is that ``pip-run``\nis transient only for the invocation of a single command, while\n``mktmpenv`` lasts for a session.\n\n.. list-table::\n   :widths: 40 10 10\n   :header-rows: 1\n\n   * - Feature\n     - pip-run\n     - mktmpenv\n   * - create temporary package environment\n     - ✓\n     - ✓\n   * - re-usable across python invocations\n     - ✓\n     - ✓\n   * - portable\n     - ✓\n     -\n   * - one-line invocation\n     - ✓\n     -\n   * - multiple interpreters in session\n     - ✓\n     -\n   * - dependency inference\n     - ✓\n     -\n   * - run standalone scripts\n     - ✓\n     - ✓\n   * - interactive interpreter with deps\n     - ✓\n     - ✓\n   * - re-use existing environment\n     - ✓\n     -\n   * - ephemeral environments\n     - ✓\n     - ✓\n   * - persistent environments\n     - ✓\n     - ✓\n\nVersioning\n==========\n\n``pip-run`` uses semver, so you can use this library with\nconfidence about the stability of the interface, even\nduring periods of great flux.\n\nTesting\n=======\n\nInvoke tests with ``tox``.\n\nFor Enterprise\n==============\n\nAvailable as part of the Tidelift Subscription.\n\nThis project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.\n\n`Learn more \u003chttps://tidelift.com/subscription/pkg/pypi-pip-run?utm_source=pypi-pip-run\u0026utm_medium=referral\u0026utm_campaign=github\u003e`_.\n","funding_links":["https://tidelift.com/funding/github/pypi/pip-run","https://tidelift.com/badges/package/pypi/pip-run","https://tidelift.com/subscription/pkg/pypi-pip-run?utm_source=pypi-pip-run\u0026utm_medium=readme","https://tidelift.com/subscription/pkg/pypi-pip-run?utm_source=pypi-pip-run\u0026utm_medium=referral\u0026utm_campaign=github"],"categories":["Python","Dependency \u0026 Package Managers"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaraco%2Fpip-run","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaraco%2Fpip-run","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaraco%2Fpip-run/lists"}