From 86c64aea4d07ad1fc0e581114c7d206a1643a810 Mon Sep 17 00:00:00 2001 From: houbie Date: Wed, 13 Nov 2024 15:08:18 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20main=20from=20@=20pyprojectx/p?= =?UTF-8?q?yprojectx@2c94ab09b66c60401a7c165c66b1054b619ebebb=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 404.html | 2 +- config/aliases/index.html | 2 +- config/defaults/index.html | 2 +- config/scripts/index.html | 15 ++++++++++--- config/tools/index.html | 2 +- dev-dependencies/index.html | 2 +- index.html | 2 +- recipes/index.html | 41 ++++++++++++++++++++++++++++++------ search/search_index.json | 2 +- sitemap.xml.gz | Bin 127 -> 127 bytes usage/index.html | 2 +- 11 files changed, 54 insertions(+), 18 deletions(-) diff --git a/404.html b/404.html index 56a86b7..8f75bf9 100644 --- a/404.html +++ b/404.html @@ -12,7 +12,7 @@ - + diff --git a/config/aliases/index.html b/config/aliases/index.html index 8ab8111..2c27a2a 100644 --- a/config/aliases/index.html +++ b/config/aliases/index.html @@ -16,7 +16,7 @@ - + diff --git a/config/defaults/index.html b/config/defaults/index.html index ce8d2bf..424de51 100644 --- a/config/defaults/index.html +++ b/config/defaults/index.html @@ -16,7 +16,7 @@ - + diff --git a/config/scripts/index.html b/config/scripts/index.html index 49fbc6e..9b2a5c6 100644 --- a/config/scripts/index.html +++ b/config/scripts/index.html @@ -16,7 +16,7 @@ - + @@ -490,12 +490,21 @@

Run Python scripts
[tool.pyprojectx.aliases]
 # run the generate-data script in the 'jupyter' tool context
 generate-data = { cmd = 'generate-data', ctx = 'jupyter' }
 
-

The script directory can be changed with the scripts_dir option in pyproject.toml:

+
+
[tool.pyprojectx]
+scripts_ctx = "scripts"
+
+

The default script directory can be changed by specifying the scripts_dir in pyproject.toml:

[tool.pyprojectx]
 scripts_dir = "scripts"
 
diff --git a/config/tools/index.html b/config/tools/index.html index 235d746..23f608d 100644 --- a/config/tools/index.html +++ b/config/tools/index.html @@ -16,7 +16,7 @@ - + diff --git a/dev-dependencies/index.html b/dev-dependencies/index.html index 0e0f2e7..6c8ad7c 100644 --- a/dev-dependencies/index.html +++ b/dev-dependencies/index.html @@ -16,7 +16,7 @@ - + diff --git a/index.html b/index.html index 918505c..64e0f4c 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@ - + diff --git a/recipes/index.html b/recipes/index.html index 7e0d85e..268522e 100644 --- a/recipes/index.html +++ b/recipes/index.html @@ -14,7 +14,7 @@ - + @@ -498,7 +498,16 @@
  • - Github actions + GitHub actions + + + +
  • + +
  • + + + Run scripts that use the project's packages @@ -577,7 +586,16 @@
  • - Github actions + GitHub actions + + + +
  • + +
  • + + + Run scripts that use the project's packages @@ -757,11 +775,11 @@

    Build scripts.venv in your project directory instead of somewhere in your home directory. It makes it easier to locate files and to keep your system clean when removing the project.

    -

    Github actions#

    -

    By using the pw wrapper script, you can simplify your github actions:

    +

    GitHub actions#

    +

    By using the pw wrapper script, you can simplify your GitHub actions:

    • no explicitly tool installations or docker images (for Python tools)
    • -
    • use the same commands and scripts in github actions as on your laptop
    • +
    • use the same commands and scripts in GitHub actions as on your laptop

    Some tips:

      @@ -790,10 +808,19 @@

      Github actionsbuild and release workflows for a full example.

      +

      Run scripts that use the project's packages#

      +

      You can set up a tool context that includes the project code and dependencies by using an editable install. +Then you can make that context the default one for running scripts.

      +

      [tool.pyprojectx]
      +scripts_ctx = "project"
      +# install the current project in editable mode; this requires that your project is installable
      +project = ["-e ."] # you can add more dependencies here but editable installs are not locked (see note below)
      +
      +Having a script my-script.py in the scripts directory, you can just run px my-script or even px mS.

      Experiment with your project in a Jupyter notebook#

      You can launch a notebook that has access to your project packages without the need to install anything upfront.

      [tool.pyprojectx]
      -# install the current project in editable mode, together with jupyter
      +# install the current project in editable mode, together with jupyter; this requires that your project is installable
       jupyter = ["jupyterlab", "-e ."]
       
       [tool.pyprojectx.aliases]
      diff --git a/search/search_index.json b/search/search_index.json
      index 016fecc..11af4cb 100644
      --- a/search/search_index.json
      +++ b/search/search_index.json
      @@ -1 +1 @@
      -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"

      ALL-INCLUSIVE PYTHON PROJECTS

      "},{"location":"#introduction","title":"Introduction","text":"

      Pyprojectx makes it easy to create all-inclusive Python projects; no need to install any tools upfront, not even Pyprojectx itself!

      "},{"location":"#feature-highlights","title":"Feature highlights","text":"
      • Reproducible builds by treating tools and utilities as (versioned) dev-dependencies
      • No global installs, everything is stored inside your project directory (like npm's node_modules)
      • Bootstrap your entire build process with a small wrapper script (like Gradle's gradlew wrapper)
      • Configure shortcuts for routine tasks
      • Simple configuration in pyproject.toml

      Projects can be build/tested/used immediately without explicit installation nor initialization:

      Linux/MacWindows
      git clone https://github.com/pyprojectx/px-demo.git\n# for the poetry version: git checkout poetry\ncd px-demo\n./pw build\n
      git clone https://github.com/pyprojectx/px-demo.git\n# for the poetry version: git checkout poetry\ncd px-demo\npw build\n

      "},{"location":"#installation","title":"Installation","text":"

      One of the key features is that there is no need to install anything explicitly (except a Python 3.8+ interpreter).

      cd into your project directory and download the wrapper scripts:

      Linux/MacWindows
      curl -LO https://github.com/pyprojectx/pyprojectx/releases/latest/download/wrappers.zip && unzip -o wrappers.zip && rm -f wrappers.zip\n
      Invoke-WebRequest https://github.com/pyprojectx/pyprojectx/releases/latest/download/wrappers.zip -OutFile wrappers.zip; Expand-Archive -Force -Path wrappers.zip -DestinationPath .; Remove-Item -Path wrappers.zip\n

      With the wrapper scripts in place, you can start adding tools:

      Linux/MacWindows
      # initialize a PDM project\n./pw --add pdm,ruff,pre-commit,px-utils\n./pw pdm init\n# omit './pw' by activating the tool context\nsource .pyprojectx/main/activate\npdm --version\nruff check src\n# initialize a poetry project\n./pw --add poetry\n./pw poetry init\n
      # initialize a PDM project\npw --add pdm,ruff,pre-commit,px-utils\npw pdm init\n# omit 'pw' by activating the tool context\nsource .pyprojectx/main/activate\npdm --version\nruff check src\n# initialize a poetry project\npw --add poetry\npw poetry init\n

      Tip: Add the wrapper scripts to version control

      When using Git:

      git add pw pw.bat\ngit update-index --chmod=+x pw\necho .pyprojectx/ >> .gitignore\n

      Tip: Install the px utility script

      You can copy a small script to .pyprojectx in your home directory. When added to your PATH, you can replace ./pw with the shorter px. This also works from subdirectories: ../../pw can also be replaced with px

      Linux/MacWindows
      ./pw --install-px\n
      pw --install-px\n

      If you don't want to prefix every command with px or ./pw, you can activate a tool context.

      "},{"location":"dev-dependencies/","title":"A Note about Dev-Dependencies","text":"

      Poetry and PDM let you define dev-dependencies similar to npm's devDependencies. There is however a major difference between Python and npm dependencies: npm can install multiple versions of the same package, meaning that devDependencies do not interfere with main dependencies. Python, on the other hand, can only install one version of a package. This means that all dependencies will have to meet both the main dependency constraints and all the dev-dependency constraints.

      If you install all your development tools as dev-dependencies, some packages that your production code depends on, will likely be downgraded to older versions. Or worse: your project fails to install because of dependency conflicts.

      Tip: Only install test packages as dev-dependencies

      pytest and friends need to be installed together with your code, so you will need to add them as Poetry or PDM dev-dependencies. Other tools and utilities can be managed by Pyprojectx in order to get reproducible builds.

      "},{"location":"dev-dependencies/#the-unreliable-pip-install","title":"The unreliable pip install","text":"

      One would expect that pip install tool-x==1.2.3 always installs exactly the same version of tool-x. Unfortunately, this is not the case because a most python packages do not pin the versions of their dependencies.

      This means that released versions of tools can be broken at any time by a new release of one of their dependencies.

      This is exactly what happened with PDM 2.5.3.

      For this reason, all the dependencies of pyprojectx are locked when publishing to PyPI.

      "},{"location":"recipes/","title":"Recipes","text":""},{"location":"recipes/#create-a-new-project","title":"Create a new project","text":"

      Install common tools: - pdm or poetry: dependency management (see simple projects if not required). - ruff: linter/formatter - pre-commit: git hooks for formatting and linting - px-utils: cross-platform file operations

      Linux/Mac
      # initialize a PDM project\n./pw --add pdm,ruff,pre-commit,px-utils\n./pw pdm init\n# initialize a poetry project\n./pw --add poetry,ruff,pre-commit,px-utils\n./pw poetry init\n
      Windows
      # initialize a PDM project\npw --add pdm,ruff,pre-commit,px-utils\npw pdm init\n# initialize a poetry project\npw --add poetry,ruff,pre-commit,px-utils\npw poetry init\n
      "},{"location":"recipes/#simple-projects","title":"Simple projects","text":"

      If you don't need dependency management (f.e. when you don't have any dependencies), Pyprojectx can create your virtual environment and install test dependencies.

      [tool.pyprojectx.venv]\n# venv and .venv don't have any special meaning, you can choose any name\nrequirements = [\n    \"-r pyproject.toml\", # install project.dependencies from pyproject.toml\n    \"pytest\" # test dependencies (keep your other dev dependencies in the main requirements)\n]\ndir = \".venv\"\n\n[tool.pyprojectx.main]\nrequirements = [\"ruff\", \"pre-commit\", \"px-utils\", \"httpie\", \"build\"]\npost-install = \"pre-commit install\"\n\ninstall = \"pw@ --install-context venv\"\ntest = { cmd = \"pytest\", ctx = \"venv\" }\nformat = [\"ruff format\", \"ruff check --select I --fix\"]\nlint = [\"ruff check\"]\ncheck = [\"@lint\", \"@test\"]\nbuild = [\"@install\", \"@check\", \"python -m build\"]\n\n[build-system]\nrequires = [\"setuptools\"]\nbuild-backend = \"setuptools.build_meta\"\n

      After running any alias (f.e. ./pw test), you can activate the virtual environment with source .venv/bin/activate. See also px-demo for a full example.

      "},{"location":"recipes/#build-scripts","title":"Build scripts","text":"

      Script your development and build flow with aliases:

      • use pre-commit hooks
      • configure code formatting and linting
      • package and publish to pypi
      • ...

      Use Poetry or PDM to further streamline your development flow with:

      • better dependency management and version locking compared with pip requirement files
      • virtual environment management (or skip a virtual environment all together when using PDM)
      • packaging and publishing

      With this combination, you can most likely skip makefiles altogether.

      Example:

      PDMPoetry
      [tool.pyprojectx]\n[tool.pyprojectx.main]\nrequirements = [ \"pdm\", \"ruff\", \"pre-commit\", \"px-utils\", \"mkdocs\" ]\n# the first time that a pdm command is invoked, we make sure that pre-commit hooks are installed, so we can't forget it\npost-install = \"pre-commit install\"\n[tool.pyprojectx.aliases]\n# create the virtual environment and install all dependencies\ninstall = \"pdm install\"\n# run a command in the project's virtual environment\nrun = \"pdm run\"\n# show outdated dependencies\noutdated = \"pdm update --outdated\"\nclean = \"pxrm .venv .pytest_cache dist .pdm-build .ruff_cache\"\nfull-clean = [\"@clean\", \"pxrm .pyprojectx\"]\n# format code and sort imports\nformat = [\"ruff format\", \"ruff check --select I --fix\"]\nlint = [\"ruff check\"]\ntest = \"pdm run pytest\"\n# run check before pushing to git and your build will never break\ncheck = [\"@lint\", \"@test\"]\n# run the same build command on your laptop or CI/CD server\nbuild = [ \"@install\", \"@check\", \"pdm build\" ]\n# extract complexity from your CI/CD flows to test/run them locally\n# use comprehensible python scripts (bin/prep-release) instead of complex shell scripts\nrelease = [\"prep-release\", \"pdm publish --username __token__\"]\n
      [tool.pyprojectx]\n[tool.pyprojectx.main]\nrequirements = [ \"poetry\", \"ruff\", \"pre-commit\", \"px-utils\", \"mkdocs\" ]\n# the first time that a poetry command is invoked, we make sure that pre-commit hooks are installed, so we can't forget it\npost-install = \"pre-commit install\"\n[tool.pyprojectx.aliases]\n# create the virtual environment and install all dependencies\ninstall = \"poetry install\"\n# run a command in the project's virtual environment\nrun = \"poetry run\"\n# show outdated dependencies\noutdated = \"poetry show --outdated --top-level\"\nclean = \"pxrm .venv .pytest_cache dist .ruff_cache\"\nfull-clean = [\"@clean\", \"pxrm .pyprojectx\"]\n# format code and sort imports\nformat = [\"ruff format\", \"ruff check --select I --fix\"]\nlint = [\"ruff check\"]\ntest = \"poetry run pytest\"\n# run check before pushing to git and your build will never break\ncheck = [\"@lint\", \"@test\"]\n# run the same build command on your laptop or CI/CD server\nbuild = [ \"@install\", \"@check\", \"poetry build\" ]\n# extract complexity from your CI/CD flows to test/run them locally\n# use comprehensible python scripts (bin/prep-release) instead of complex shell scripts\nrelease = [\"prep-release\", \"poetry publish --username __token__\"]\n

      See Pyprojectx own pyproject.toml for a full example with PDM, or px-demo for another example project with PDM or the poetry variant.

      Tip: Keep the poetry virtual environment inside your project directory

      Add poetry.toml to your project:

      [virtualenvs]\nin-project = true\n
      This makes Poetry create a .venv in your project directory instead of somewhere in your home directory. It makes it easier to locate files and to keep your system clean when removing the project.

      "},{"location":"recipes/#github-actions","title":"Github actions","text":"

      By using the pw wrapper script, you can simplify your github actions:

      • no explicitly tool installations or docker images (for Python tools)
      • use the same commands and scripts in github actions as on your laptop

      Some tips:

      • Use the same scripts on Linux and Windows by replacing ./pw (resp. pw) with python pw
      • Speed up builds by caching .pyprojectx

      Example:

      jobs:\n  build:\n    steps:\n      - name: Cache .pyprojectx\n        uses: actions/cache@v2\n        env:\n          cache-name: .pyprojectx\n        with:\n          path: .pyprojectx\n          key: ${{ runner.os }}-pyprojectx\n\n      - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python-version }}\n\n      - name: Test and build\n        run: python pw build\n
      See Pyprojectx own build and release workflows for a full example.

      "},{"location":"recipes/#experiment-with-your-project-in-a-jupyter-notebook","title":"Experiment with your project in a Jupyter notebook","text":"

      You can launch a notebook that has access to your project packages without the need to install anything upfront.

      [tool.pyprojectx]\n# install the current project in editable mode, together with jupyter\njupyter = [\"jupyterlab\", \"-e .\"]\n\n[tool.pyprojectx.aliases]\n# -y is there to automatically answer 'yes' after quitting with ctrl+c\nnotebook = \"jupyter lab -y\"\n
      Just run px notebook or even px n

      Editable installs are not locked

      When a tool context contains an editable install, it won't be locked when running ./pw --lock. Therefore, it is recommended to add editable install to a separate tool context and lock the main context for reproducible builds.

      "},{"location":"usage/","title":"Usage","text":""},{"location":"usage/#cli","title":"CLI","text":"
      usage: pw.py [-h] [--version] [--toml TOML] [--install-dir INSTALL_DIR]\n             [--force-install] [--clean] [--install-context tool-context]\n             [--verbose] [--quiet] [--info]\n             [--add [context:]<package>,<package>...] [--lock] [--install-px]\n             [--upgrade]\n             ...\n\nExecute commands or aliases defined in the [tool.pyprojectx] section of\npyproject.toml. Use the -i or --info option to see available tools and\naliases.\n\npositional arguments:\n  command               The command/alias with optional arguments to execute.\n\noptions:\n  -h, --help            show this help message and exit\n  --version             show program's version number and exit\n  --toml TOML, -t TOML  The toml config file. Defaults to 'pyproject.toml' in\n                        the same directory as the pw script.\n  --install-dir INSTALL_DIR\n                        The directory where all tools (including pyprojectx)\n                        are installed; defaults to the PYPROJECTX_INSTALL_DIR\n                        environment value if set, else '.pyprojectx' in the\n                        same directory as the invoked pw script.\n  --force-install, -f   Force clean installation of the virtual environment\n                        used to run cmd, if any.\n  --clean, -c           Clean .pyprojectx directory by removing all but the\n                        current versions of pyprojectx and context virtual\n                        environments.\n  --install-context tool-context\n                        Install a tool context without actually running any\n                        command.\n  --verbose, -v         Give more output. This option is additive and can be\n                        used up to 2 times.\n  --quiet, -q           Suppress output.\n  --info, -i            Show the configuration details of a command instead of\n                        running it. If no command is specified, a list with\n                        all available tools and aliases is shown.\n  --add [context:]<package>,<package>...\n                        Add one or more packages to a tool context. If no\n                        context is specified, the packages are added to the\n                        main context. Packages can be specified as in 'pip\n                        install', except that a ',' can't be used in the\n                        version specification.\n  --lock                Write all dependencies of all tool contexts to\n                        'pw.lock' to guarantee reproducible outcomes.\n  --install-px          Install the px and pxg scripts in your home directory.\n  --upgrade             Print instructions to download the latest pyprojectx\n                        wrapper scripts.\n
      "},{"location":"usage/#install-the-global-px-script","title":"Install the global px script","text":"

      Pyprojectx provides a small px script that delegates everything to the pw wrapper script. The pw script is searched for in the current working directory and its parents.

      When added to your PATH, you can replace ./pw with the shorter px. This also works from subdirectories: ../../pw can also be replaced with px

      To install:

      Linux/MacWindows
      ./pw --install-px\n
      pw --install-px\n
      "},{"location":"usage/#global-tools","title":"Global tools","text":"

      Besides the px script, pw --install-px also copies adds the pxg.

      pxg can be used as a lightweight pipx to install/run tools globally.

      Example: make http requests with httpie:

      pxg --add httpie\npxg http POST pie.dev/post hello=world\n

      The global setup can be configured in ~/.pyprojectx/global/pyproject.toml.

      Uninstalling all global tools is just a matter of removing the global directory:

      rm -rf ~/.pyprojectx/global/.pyprojectx\n

      "},{"location":"config/aliases/","title":"Shortcut common commands with aliases","text":"

      Aliases allow you to define shortcuts for common commands and simple shell scripts.

      px or pw?

      This section assumes that you installed the px utility script. Otherwise, you need to replace px with ./pw (Linux, Mac) or pw (Windows PowerShell).

      "},{"location":"config/aliases/#defining-shortcuts","title":"Defining shortcuts","text":"

      You can avoid a lot of typing by aliasing commands that you use a lot. Example:

      [tool.pyprojectx.aliases]\ninstall = \"poetry install\"\nrun = \"poetry run\"\n

      With above aliases, you can type px install instead of the usual poetry install. Depending on your other aliases, this can be even shortened to px i (see alias abbreviations).

      All arguments are passed to the underlying command or script, making px run my-script --foo equivalent to poetry run my-script --foo.

      "},{"location":"config/aliases/#shell-scripts","title":"Shell scripts","text":"

      Shell scripts can also be aliased:

      [tool.pyprojectx.aliases]\nprepare = \"mkdir build && mkdir generated\"\nclean = \"rm -rf build generated\"\n

      You can override aliases for a specific OS:

      [tool.pyprojectx.os.win.aliases]\nclean = \"rd /s /q build generated\"\n

      Above clean alias will override the default one on Windows (in fact on all operating systems where sys.platform.startswith(\"win\")==True).

      Tip: use px-utils for common file operations

      Use px-utils to create, copy, move, delete, ... files and directories cross-platform.

      [tool.pyprojectx.os.win.aliases]\nclean = \"pxrm build generated\"\n

      Aliases are interpreted by the OS shell

      The alias show-path = \"echo %PATH%\" will print the PATH environment variable on Windows, but will print literally %PATH% on another OS.

      "},{"location":"config/aliases/#combining-aliases","title":"Combining aliases","text":"

      Use the @ prefix to call an alias or script from another alias.

      [tool.pyprojectx.aliases]\nunit-test = \"pdm run pytest tests/unit\"\nintegration-test = \"pdm run pytest tests/integration\"\ntest = [\"@unit-test && @integration-test\"]\n# a list of commands behaves the same as when combined with '&&'\nbuild = [\n    \"@install\",\n    \"@test\",\n    \"@pdm build\",\n]\n

      [pw]@ is substituted with the initial wrapper command + arguments.

      So running px -v test will expand to

      px -v poetry run pytest tests/unit && px -v  poetry run pytest tests/integration\n
      "},{"location":"config/aliases/#alias-configuration","title":"Alias configuration","text":"

      Besides simple commands, aliases provide some configuration options:

      notebook = { cmd = 'jupyter lab', ctx = 'jupyter', env = { JUPYTERLAB_DIR = \"docs\" } }\n
      • cmd: the command to run
      • ctx: the tool context in which the command is run; defaults to main
      • env: additional environment variables to set
      • cwd: the working directory in which the command is run; defaults to @PROJECT_DIR, the directory containing pyproject.toml. This default ensures that commands can be run from any subdirectory of the project. Use @PROJECT_DIR/subdir to run the command in a subdirectory of the project.
      • shell: the shell used to run the command, overrides the default shell of the tool context

      Default CWD changed in 2.0.0

      Prior to Pyprojectx 2.0.0, aliases where always executed in the current working directory. As of 2.0.0, aliases run by default in the root directory of the project (where pyproject.toml is located), unless explicitly overridden with the cwd option.

      "},{"location":"config/aliases/#abbreviations","title":"Abbreviations","text":"

      To run an alias, you only have to type the portion of the alias name that uniquely identifies the alias within the project. So we don't have to type the complete name if we can use a shorter version. As a bonus Pyprojectx also supports camel case to abbreviate an alias name.

      When you define an alias named either foo-bar or fooBar, then following commands are equivalent (provided they don't match any other alias):

      px foo-bar\npx fooBar\npx fooB\npx fBar\npx fB\npx f\n

      An alias can shadow other commands

      Abbreviations come with the cost that an alias will shadow other non-alias commands when the alias' name starts with that command. For example:

      [tool.pyprojectx]\nmain = [\"black\"]\n[tool.pyprojectx.aliases]\nblack-adder = \"echo 'Field Marshal Haig is about to make yet another gargantuan effort to move his drinks cabinet six inches closer to Berlin.'\"\nblack = \"black\"\n
      Here it would not be possible to use the black formatter without explicitly exposing it with the second alias.

      Tip: Abbreviations as cli hints

      When you don't remember the exact alias to run, just type the first letter(s) and px will refresh your memory \ud83d\ude01

      px c\n# 'c' is ambiguous\n# Candidates are:\n# clean, clean-all, check\n
      Or run px -i to list all available aliases and tools.

      "},{"location":"config/defaults/","title":"Configurable defaults","text":""},{"location":"config/defaults/#current-working-directory","title":"Current working directory","text":"

      You can change the default working directory for all commands by setting the cwd option.

      Sensible values are . (the current directory) or @PROJECT_DIR (the directory containing pyproject.toml).

      [tool.pyprojectx]\ncwd = \".\"\n

      Aliases can override the global cwd.

      "},{"location":"config/defaults/#environment-variables","title":"Environment variables","text":"

      You can set environment variables that will be added to the system environment when running a command:

      [tool.pyprojectx]\nenv = { POETRY_VIRTUALENVS_PATH = \"/data/poetry\" }\n

      Aliases can provide additional environment variables and/or override the global ones.

      "},{"location":"config/defaults/#shell","title":"Shell","text":"

      You can change the os shell used to run commands. The shell can be defined globally, os specific or alias specific.

      [tool.pyprojectx]\nshell = \"bash\n[tool.pyprojectx.os.win]\nshell = \"pwsh.exe\"\n

      Specifying a shell changes variable substitution

      Commands are converted into a single string and passed to the shell with the -c option, example: bash -c \"echo $PATH\". This changes the variable substitution that is done by your os and can lead to unexpected results.

      When you set a shell for os specific file operations, consider using px-utils instead.

      [tool.pyprojectx.alias]\nprepare = \"pxmkdirs build generated\"\ncopy = \"pxcp src/**/*.py build/python\"\nmove = \"pxmv data/**/*.json build/data\"\nclean = \"pxrm build generated\"\n

      "},{"location":"config/scripts/","title":"Run Python scripts","text":"

      Logic that is too complex to embed in pyproject.toml can be written in Python scripts in the bin directory. These can be called from aliases or from the command line with pw <script-name>.

      The scripts run by default in the main tool context and hence can use all libraries installed in the main tool context.

      To run a script in a different tool context, you need to define an alias:

      [tool.pyprojectx.aliases]\n# run the generate-data script in the 'jupyter' tool context\ngenerate-data = { cmd = 'generate-data', ctx = 'jupyter' }\n

      The script directory can be changed with the scripts_dir option in pyproject.toml:

      [tool.pyprojectx]\nscripts_dir = \"scripts\"\n
      "},{"location":"config/tools/","title":"Manage tools as dev dependencies","text":"

      Pyprojectx can manage all the Python tools and utilities that you use for building, testing...

      Adding tools to the [tool.pyprojectx] section in pyproject.toml makes them available inside your project.

      Tool contexts introduced in Pyprojectx 2.0.0

      Prior to Pyprojectx 2.0.0, tools were always installed in a separate virtual environment. As of 2.0.0, tools are by default installed in the virtual environment of the main tool context.

      px or pw?

      This section assumes that you installed the px utility script. Otherwise, you need to replace px with ./pw (Linux, Mac) or pw (Windows PowerShell).

      "},{"location":"config/tools/#tool-contexts","title":"Tool contexts","text":"

      Pyprojectx creates an isolated virtual environment for each tool context (set of tools).

      Inside the [tool.pyprojectx] section of pyproject.toml you specify what needs to be installed.

      pyproject.toml
      [tool.pyprojectx]\n# require a specific poetry version, use the latest version of black\nmain = [\"poetry==1.1.11\", \"black\"]\n

      Above configuration makes the black and poetry commands available inside your project.

      You only need to prefix them with thepx or pw wrapper script:

      Any OS with pxLinux/MacWindows
      px poetry --help\npx black my_package --diff\n
      ./pw poetry --help\n./pw black my_package --diff\n
      pw poetry --help\npw black my_package --diff\n

      Naming your tool context

      When running a command that has the same name as a tool context, the command will be executed by default inside the virtual environment of that tool context. Otherwise, the command will be executed in the virtual environment of the main tool context.

      "},{"location":"config/tools/#tool-context-activation","title":"Tool context activation","text":"

      If you don't want to prefix every command with px or ./pw, you can activate a tool context.

      For example, to activate the main tool context run source .pyprojectx/main/activate. This makes all the tools in the main context available in your shell.

      Alternatively, you can add .pyprojectx/main to your PATH.

      Upgrading from Pyprojectx < 2.1.0

      If the virtual environment of a tool cotext is already present, you will need to re-create it to use the new activation mechanism, either by removing the .pyprojectx directory or by running any command with the --force-install option, f.e. ./pw -f --install-context main.

      "},{"location":"config/tools/#tool-context-configuration","title":"Tool context configuration","text":"

      In its simplest form, a tool context is a multiline string or array of strings that adheres to pip's Requirements File Format

      Example:

      pyproject.toml
      [tool.pyprojectx]\nmain = [\"pdm\",\"ruff\",\"pre-commit\",\"px-utils\"]\nhttp = \"httpie ~= 3.0\"\n

      With above configuration, you can run following commands:

      px pdm --version\n# PDM, version 2.11.2\npx http www.google.com\n# HTTP/1.1 200 OK ...\n

      Tip: Lock your tool requirements

      This makes sure that your build won't break when new versions of a tool are released,or when a tool is broken by a new release of one of its dependencies.

      You can also include requirements from a text file or pyproject.toml file with -r:

      [tool.pyprojectx]\nmain = [\"-r pyproject.toml\", \"-r dev-requirements.txt\"]\n

      If you want to install a prerelease version of a tool, you need to configure it:

      [tool.pyprojectx]\nprerelease = \"allow\"\n

      "},{"location":"config/tools/#post-install-scripts","title":"Post-install scripts","text":"

      In some situations it can be useful to perform additional actions after a tool has been installed. This is achieved by configuring both requirements and post-install scripts for a tool

      [tool.pyprojectx]\n[tool.pyprojectx.main]\nrequirements = [\"pdm\", \"ruff\", \"pre-commit\", \"px-utils\"]\npost-install = \"pre-commit install\"\n

      When creating your project's virtual environment with px pdm install for the first time in the example above, pre-commit is also initialised. This makes sure that pre-commit hooks are always run when committing code.

      Tip: Use toml subsections for better readability

      The example above uses a toml subsection instead of an inline table:

      main = { requirements = [...], post-install=\"...\"}`\n

      "},{"location":"config/tools/#using-an-alternative-package-index","title":"Using an alternative package index","text":"

      You can use pip's --index-url or --extra-index-url to install packages from alternative (private) package indexes:

      [tool.pyprojectx]\nprivate-tool = [\n    \"--extra-index-url https://artifactory.acme.com/artifactory/api/pypi/python-virtual/simple\",\n    \"some-private-package\"\n]\n
      "},{"location":"config/tools/#locking-requirements","title":"Locking requirements","text":"

      To achieve reproducible builds, you can lock the versions of all tools that you use in your project by:

      • creating a pw.lock file
      • pinning tool versions in pyproject.toml
      "},{"location":"config/tools/#creating-a-pwlock-file","title":"Creating a pw.lock file","text":"

      When you run ./pw --lock, a pw.lock file is created in the root directory of your project. This file should be committed to version control.

      This is the recommended way to lock tool versions to guarantee reproducible builds (see why)

      The lock file is automatically updated when the tool context requirements in pyproject.toml change.

      To upgrade all tools to the latest version (respecting the requirements in pyproject.toml), combine the lock option with the force-install option: ./pw --lock -f.

      Supporting multiple Python versions

      When generating the lock file, the version of the current Python interpreter is used as minimum version that should be supported by the resolved requirements. You can override this by configuring the lock-python-version, e.g., 3.8 or 3.8.17:

      [tool.pyprojectx]\nlock-python-version = \"3.8\"\n

      Tip: don't specify tool versions in pyproject.toml when using a pw.lock file

      When there is no version specified for a tool, the latest version will be installed and locked. Updating all tools to the latest version is then as simple as running ./pw --lock again. In case of conflicts or issues with a new version, you can always revert to the previous version of the lock file.

      "},{"location":"config/tools/#pinning-tool-versions-in-pyprojecttoml","title":"Pinning tool versions in pyproject.toml","text":"

      You can also pin tool versions in pyproject.toml:

      [tool.pyprojectx]\nmain = [\"pdm==2.11.2\", \"ruff==0.1.11\", \"pre-commit==3.6.0\", \"px-utils==1.0.1\"]\n
      Be aware that even with a fixed version, tools can break at future installs!

      "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"

      ALL-INCLUSIVE PYTHON PROJECTS

      "},{"location":"#introduction","title":"Introduction","text":"

      Pyprojectx makes it easy to create all-inclusive Python projects; no need to install any tools upfront, not even Pyprojectx itself!

      "},{"location":"#feature-highlights","title":"Feature highlights","text":"
      • Reproducible builds by treating tools and utilities as (versioned) dev-dependencies
      • No global installs, everything is stored inside your project directory (like npm's node_modules)
      • Bootstrap your entire build process with a small wrapper script (like Gradle's gradlew wrapper)
      • Configure shortcuts for routine tasks
      • Simple configuration in pyproject.toml

      Projects can be build/tested/used immediately without explicit installation nor initialization:

      Linux/MacWindows
      git clone https://github.com/pyprojectx/px-demo.git\n# for the poetry version: git checkout poetry\ncd px-demo\n./pw build\n
      git clone https://github.com/pyprojectx/px-demo.git\n# for the poetry version: git checkout poetry\ncd px-demo\npw build\n

      "},{"location":"#installation","title":"Installation","text":"

      One of the key features is that there is no need to install anything explicitly (except a Python 3.8+ interpreter).

      cd into your project directory and download the wrapper scripts:

      Linux/MacWindows
      curl -LO https://github.com/pyprojectx/pyprojectx/releases/latest/download/wrappers.zip && unzip -o wrappers.zip && rm -f wrappers.zip\n
      Invoke-WebRequest https://github.com/pyprojectx/pyprojectx/releases/latest/download/wrappers.zip -OutFile wrappers.zip; Expand-Archive -Force -Path wrappers.zip -DestinationPath .; Remove-Item -Path wrappers.zip\n

      With the wrapper scripts in place, you can start adding tools:

      Linux/MacWindows
      # initialize a PDM project\n./pw --add pdm,ruff,pre-commit,px-utils\n./pw pdm init\n# omit './pw' by activating the tool context\nsource .pyprojectx/main/activate\npdm --version\nruff check src\n# initialize a poetry project\n./pw --add poetry\n./pw poetry init\n
      # initialize a PDM project\npw --add pdm,ruff,pre-commit,px-utils\npw pdm init\n# omit 'pw' by activating the tool context\nsource .pyprojectx/main/activate\npdm --version\nruff check src\n# initialize a poetry project\npw --add poetry\npw poetry init\n

      Tip: Add the wrapper scripts to version control

      When using Git:

      git add pw pw.bat\ngit update-index --chmod=+x pw\necho .pyprojectx/ >> .gitignore\n

      Tip: Install the px utility script

      You can copy a small script to .pyprojectx in your home directory. When added to your PATH, you can replace ./pw with the shorter px. This also works from subdirectories: ../../pw can also be replaced with px

      Linux/MacWindows
      ./pw --install-px\n
      pw --install-px\n

      If you don't want to prefix every command with px or ./pw, you can activate a tool context.

      "},{"location":"dev-dependencies/","title":"A Note about Dev-Dependencies","text":"

      Poetry and PDM let you define dev-dependencies similar to npm's devDependencies. There is however a major difference between Python and npm dependencies: npm can install multiple versions of the same package, meaning that devDependencies do not interfere with main dependencies. Python, on the other hand, can only install one version of a package. This means that all dependencies will have to meet both the main dependency constraints and all the dev-dependency constraints.

      If you install all your development tools as dev-dependencies, some packages that your production code depends on, will likely be downgraded to older versions. Or worse: your project fails to install because of dependency conflicts.

      Tip: Only install test packages as dev-dependencies

      pytest and friends need to be installed together with your code, so you will need to add them as Poetry or PDM dev-dependencies. Other tools and utilities can be managed by Pyprojectx in order to get reproducible builds.

      "},{"location":"dev-dependencies/#the-unreliable-pip-install","title":"The unreliable pip install","text":"

      One would expect that pip install tool-x==1.2.3 always installs exactly the same version of tool-x. Unfortunately, this is not the case because a most python packages do not pin the versions of their dependencies.

      This means that released versions of tools can be broken at any time by a new release of one of their dependencies.

      This is exactly what happened with PDM 2.5.3.

      For this reason, all the dependencies of pyprojectx are locked when publishing to PyPI.

      "},{"location":"recipes/","title":"Recipes","text":""},{"location":"recipes/#create-a-new-project","title":"Create a new project","text":"

      Install common tools: - pdm or poetry: dependency management (see simple projects if not required). - ruff: linter/formatter - pre-commit: git hooks for formatting and linting - px-utils: cross-platform file operations

      Linux/Mac
      # initialize a PDM project\n./pw --add pdm,ruff,pre-commit,px-utils\n./pw pdm init\n# initialize a poetry project\n./pw --add poetry,ruff,pre-commit,px-utils\n./pw poetry init\n
      Windows
      # initialize a PDM project\npw --add pdm,ruff,pre-commit,px-utils\npw pdm init\n# initialize a poetry project\npw --add poetry,ruff,pre-commit,px-utils\npw poetry init\n
      "},{"location":"recipes/#simple-projects","title":"Simple projects","text":"

      If you don't need dependency management (f.e. when you don't have any dependencies), Pyprojectx can create your virtual environment and install test dependencies.

      [tool.pyprojectx.venv]\n# venv and .venv don't have any special meaning, you can choose any name\nrequirements = [\n    \"-r pyproject.toml\", # install project.dependencies from pyproject.toml\n    \"pytest\" # test dependencies (keep your other dev dependencies in the main requirements)\n]\ndir = \".venv\"\n\n[tool.pyprojectx.main]\nrequirements = [\"ruff\", \"pre-commit\", \"px-utils\", \"httpie\", \"build\"]\npost-install = \"pre-commit install\"\n\ninstall = \"pw@ --install-context venv\"\ntest = { cmd = \"pytest\", ctx = \"venv\" }\nformat = [\"ruff format\", \"ruff check --select I --fix\"]\nlint = [\"ruff check\"]\ncheck = [\"@lint\", \"@test\"]\nbuild = [\"@install\", \"@check\", \"python -m build\"]\n\n[build-system]\nrequires = [\"setuptools\"]\nbuild-backend = \"setuptools.build_meta\"\n

      After running any alias (f.e. ./pw test), you can activate the virtual environment with source .venv/bin/activate. See also px-demo for a full example.

      "},{"location":"recipes/#build-scripts","title":"Build scripts","text":"

      Script your development and build flow with aliases:

      • use pre-commit hooks
      • configure code formatting and linting
      • package and publish to pypi
      • ...

      Use Poetry or PDM to further streamline your development flow with:

      • better dependency management and version locking compared with pip requirement files
      • virtual environment management (or skip a virtual environment all together when using PDM)
      • packaging and publishing

      With this combination, you can most likely skip makefiles altogether.

      Example:

      PDMPoetry
      [tool.pyprojectx]\n[tool.pyprojectx.main]\nrequirements = [ \"pdm\", \"ruff\", \"pre-commit\", \"px-utils\", \"mkdocs\" ]\n# the first time that a pdm command is invoked, we make sure that pre-commit hooks are installed, so we can't forget it\npost-install = \"pre-commit install\"\n[tool.pyprojectx.aliases]\n# create the virtual environment and install all dependencies\ninstall = \"pdm install\"\n# run a command in the project's virtual environment\nrun = \"pdm run\"\n# show outdated dependencies\noutdated = \"pdm update --outdated\"\nclean = \"pxrm .venv .pytest_cache dist .pdm-build .ruff_cache\"\nfull-clean = [\"@clean\", \"pxrm .pyprojectx\"]\n# format code and sort imports\nformat = [\"ruff format\", \"ruff check --select I --fix\"]\nlint = [\"ruff check\"]\ntest = \"pdm run pytest\"\n# run check before pushing to git and your build will never break\ncheck = [\"@lint\", \"@test\"]\n# run the same build command on your laptop or CI/CD server\nbuild = [ \"@install\", \"@check\", \"pdm build\" ]\n# extract complexity from your CI/CD flows to test/run them locally\n# use comprehensible python scripts (bin/prep-release) instead of complex shell scripts\nrelease = [\"prep-release\", \"pdm publish --username __token__\"]\n
      [tool.pyprojectx]\n[tool.pyprojectx.main]\nrequirements = [ \"poetry\", \"ruff\", \"pre-commit\", \"px-utils\", \"mkdocs\" ]\n# the first time that a poetry command is invoked, we make sure that pre-commit hooks are installed, so we can't forget it\npost-install = \"pre-commit install\"\n[tool.pyprojectx.aliases]\n# create the virtual environment and install all dependencies\ninstall = \"poetry install\"\n# run a command in the project's virtual environment\nrun = \"poetry run\"\n# show outdated dependencies\noutdated = \"poetry show --outdated --top-level\"\nclean = \"pxrm .venv .pytest_cache dist .ruff_cache\"\nfull-clean = [\"@clean\", \"pxrm .pyprojectx\"]\n# format code and sort imports\nformat = [\"ruff format\", \"ruff check --select I --fix\"]\nlint = [\"ruff check\"]\ntest = \"poetry run pytest\"\n# run check before pushing to git and your build will never break\ncheck = [\"@lint\", \"@test\"]\n# run the same build command on your laptop or CI/CD server\nbuild = [ \"@install\", \"@check\", \"poetry build\" ]\n# extract complexity from your CI/CD flows to test/run them locally\n# use comprehensible python scripts (bin/prep-release) instead of complex shell scripts\nrelease = [\"prep-release\", \"poetry publish --username __token__\"]\n

      See Pyprojectx own pyproject.toml for a full example with PDM, or px-demo for another example project with PDM or the poetry variant.

      Tip: Keep the poetry virtual environment inside your project directory

      Add poetry.toml to your project:

      [virtualenvs]\nin-project = true\n
      This makes Poetry create a .venv in your project directory instead of somewhere in your home directory. It makes it easier to locate files and to keep your system clean when removing the project.

      "},{"location":"recipes/#github-actions","title":"GitHub actions","text":"

      By using the pw wrapper script, you can simplify your GitHub actions:

      • no explicitly tool installations or docker images (for Python tools)
      • use the same commands and scripts in GitHub actions as on your laptop

      Some tips:

      • Use the same scripts on Linux and Windows by replacing ./pw (resp. pw) with python pw
      • Speed up builds by caching .pyprojectx

      Example:

      jobs:\n  build:\n    steps:\n      - name: Cache .pyprojectx\n        uses: actions/cache@v2\n        env:\n          cache-name: .pyprojectx\n        with:\n          path: .pyprojectx\n          key: ${{ runner.os }}-pyprojectx\n\n      - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python-version }}\n\n      - name: Test and build\n        run: python pw build\n
      See Pyprojectx own build and release workflows for a full example.

      "},{"location":"recipes/#run-scripts-that-use-the-projects-packages","title":"Run scripts that use the project's packages","text":"

      You can set up a tool context that includes the project code and dependencies by using an editable install. Then you can make that context the default one for running scripts.

      [tool.pyprojectx]\nscripts_ctx = \"project\"\n# install the current project in editable mode; this requires that your project is installable\nproject = [\"-e .\"] # you can add more dependencies here but editable installs are not locked (see note below)\n
      Having a script my-script.py in the scripts directory, you can just run px my-script or even px mS.

      "},{"location":"recipes/#experiment-with-your-project-in-a-jupyter-notebook","title":"Experiment with your project in a Jupyter notebook","text":"

      You can launch a notebook that has access to your project packages without the need to install anything upfront.

      [tool.pyprojectx]\n# install the current project in editable mode, together with jupyter; this requires that your project is installable\njupyter = [\"jupyterlab\", \"-e .\"]\n\n[tool.pyprojectx.aliases]\n# -y is there to automatically answer 'yes' after quitting with ctrl+c\nnotebook = \"jupyter lab -y\"\n
      Just run px notebook or even px n

      Editable installs are not locked

      When a tool context contains an editable install, it won't be locked when running ./pw --lock. Therefore, it is recommended to add editable install to a separate tool context and lock the main context for reproducible builds.

      "},{"location":"usage/","title":"Usage","text":""},{"location":"usage/#cli","title":"CLI","text":"
      usage: pw.py [-h] [--version] [--toml TOML] [--install-dir INSTALL_DIR]\n             [--force-install] [--clean] [--install-context tool-context]\n             [--verbose] [--quiet] [--info]\n             [--add [context:]<package>,<package>...] [--lock] [--install-px]\n             [--upgrade]\n             ...\n\nExecute commands or aliases defined in the [tool.pyprojectx] section of\npyproject.toml. Use the -i or --info option to see available tools and\naliases.\n\npositional arguments:\n  command               The command/alias with optional arguments to execute.\n\noptions:\n  -h, --help            show this help message and exit\n  --version             show program's version number and exit\n  --toml TOML, -t TOML  The toml config file. Defaults to 'pyproject.toml' in\n                        the same directory as the pw script.\n  --install-dir INSTALL_DIR\n                        The directory where all tools (including pyprojectx)\n                        are installed; defaults to the PYPROJECTX_INSTALL_DIR\n                        environment value if set, else '.pyprojectx' in the\n                        same directory as the invoked pw script.\n  --force-install, -f   Force clean installation of the virtual environment\n                        used to run cmd, if any.\n  --clean, -c           Clean .pyprojectx directory by removing all but the\n                        current versions of pyprojectx and context virtual\n                        environments.\n  --install-context tool-context\n                        Install a tool context without actually running any\n                        command.\n  --verbose, -v         Give more output. This option is additive and can be\n                        used up to 2 times.\n  --quiet, -q           Suppress output.\n  --info, -i            Show the configuration details of a command instead of\n                        running it. If no command is specified, a list with\n                        all available tools and aliases is shown.\n  --add [context:]<package>,<package>...\n                        Add one or more packages to a tool context. If no\n                        context is specified, the packages are added to the\n                        main context. Packages can be specified as in 'pip\n                        install', except that a ',' can't be used in the\n                        version specification.\n  --lock                Write all dependencies of all tool contexts to\n                        'pw.lock' to guarantee reproducible outcomes.\n  --install-px          Install the px and pxg scripts in your home directory.\n  --upgrade             Print instructions to download the latest pyprojectx\n                        wrapper scripts.\n
      "},{"location":"usage/#install-the-global-px-script","title":"Install the global px script","text":"

      Pyprojectx provides a small px script that delegates everything to the pw wrapper script. The pw script is searched for in the current working directory and its parents.

      When added to your PATH, you can replace ./pw with the shorter px. This also works from subdirectories: ../../pw can also be replaced with px

      To install:

      Linux/MacWindows
      ./pw --install-px\n
      pw --install-px\n
      "},{"location":"usage/#global-tools","title":"Global tools","text":"

      Besides the px script, pw --install-px also copies adds the pxg.

      pxg can be used as a lightweight pipx to install/run tools globally.

      Example: make http requests with httpie:

      pxg --add httpie\npxg http POST pie.dev/post hello=world\n

      The global setup can be configured in ~/.pyprojectx/global/pyproject.toml.

      Uninstalling all global tools is just a matter of removing the global directory:

      rm -rf ~/.pyprojectx/global/.pyprojectx\n

      "},{"location":"config/aliases/","title":"Shortcut common commands with aliases","text":"

      Aliases allow you to define shortcuts for common commands and simple shell scripts.

      px or pw?

      This section assumes that you installed the px utility script. Otherwise, you need to replace px with ./pw (Linux, Mac) or pw (Windows PowerShell).

      "},{"location":"config/aliases/#defining-shortcuts","title":"Defining shortcuts","text":"

      You can avoid a lot of typing by aliasing commands that you use a lot. Example:

      [tool.pyprojectx.aliases]\ninstall = \"poetry install\"\nrun = \"poetry run\"\n

      With above aliases, you can type px install instead of the usual poetry install. Depending on your other aliases, this can be even shortened to px i (see alias abbreviations).

      All arguments are passed to the underlying command or script, making px run my-script --foo equivalent to poetry run my-script --foo.

      "},{"location":"config/aliases/#shell-scripts","title":"Shell scripts","text":"

      Shell scripts can also be aliased:

      [tool.pyprojectx.aliases]\nprepare = \"mkdir build && mkdir generated\"\nclean = \"rm -rf build generated\"\n

      You can override aliases for a specific OS:

      [tool.pyprojectx.os.win.aliases]\nclean = \"rd /s /q build generated\"\n

      Above clean alias will override the default one on Windows (in fact on all operating systems where sys.platform.startswith(\"win\")==True).

      Tip: use px-utils for common file operations

      Use px-utils to create, copy, move, delete, ... files and directories cross-platform.

      [tool.pyprojectx.os.win.aliases]\nclean = \"pxrm build generated\"\n

      Aliases are interpreted by the OS shell

      The alias show-path = \"echo %PATH%\" will print the PATH environment variable on Windows, but will print literally %PATH% on another OS.

      "},{"location":"config/aliases/#combining-aliases","title":"Combining aliases","text":"

      Use the @ prefix to call an alias or script from another alias.

      [tool.pyprojectx.aliases]\nunit-test = \"pdm run pytest tests/unit\"\nintegration-test = \"pdm run pytest tests/integration\"\ntest = [\"@unit-test && @integration-test\"]\n# a list of commands behaves the same as when combined with '&&'\nbuild = [\n    \"@install\",\n    \"@test\",\n    \"@pdm build\",\n]\n

      [pw]@ is substituted with the initial wrapper command + arguments.

      So running px -v test will expand to

      px -v poetry run pytest tests/unit && px -v  poetry run pytest tests/integration\n
      "},{"location":"config/aliases/#alias-configuration","title":"Alias configuration","text":"

      Besides simple commands, aliases provide some configuration options:

      notebook = { cmd = 'jupyter lab', ctx = 'jupyter', env = { JUPYTERLAB_DIR = \"docs\" } }\n
      • cmd: the command to run
      • ctx: the tool context in which the command is run; defaults to main
      • env: additional environment variables to set
      • cwd: the working directory in which the command is run; defaults to @PROJECT_DIR, the directory containing pyproject.toml. This default ensures that commands can be run from any subdirectory of the project. Use @PROJECT_DIR/subdir to run the command in a subdirectory of the project.
      • shell: the shell used to run the command, overrides the default shell of the tool context

      Default CWD changed in 2.0.0

      Prior to Pyprojectx 2.0.0, aliases where always executed in the current working directory. As of 2.0.0, aliases run by default in the root directory of the project (where pyproject.toml is located), unless explicitly overridden with the cwd option.

      "},{"location":"config/aliases/#abbreviations","title":"Abbreviations","text":"

      To run an alias, you only have to type the portion of the alias name that uniquely identifies the alias within the project. So we don't have to type the complete name if we can use a shorter version. As a bonus Pyprojectx also supports camel case to abbreviate an alias name.

      When you define an alias named either foo-bar or fooBar, then following commands are equivalent (provided they don't match any other alias):

      px foo-bar\npx fooBar\npx fooB\npx fBar\npx fB\npx f\n

      An alias can shadow other commands

      Abbreviations come with the cost that an alias will shadow other non-alias commands when the alias' name starts with that command. For example:

      [tool.pyprojectx]\nmain = [\"black\"]\n[tool.pyprojectx.aliases]\nblack-adder = \"echo 'Field Marshal Haig is about to make yet another gargantuan effort to move his drinks cabinet six inches closer to Berlin.'\"\nblack = \"black\"\n
      Here it would not be possible to use the black formatter without explicitly exposing it with the second alias.

      Tip: Abbreviations as cli hints

      When you don't remember the exact alias to run, just type the first letter(s) and px will refresh your memory \ud83d\ude01

      px c\n# 'c' is ambiguous\n# Candidates are:\n# clean, clean-all, check\n
      Or run px -i to list all available aliases and tools.

      "},{"location":"config/defaults/","title":"Configurable defaults","text":""},{"location":"config/defaults/#current-working-directory","title":"Current working directory","text":"

      You can change the default working directory for all commands by setting the cwd option.

      Sensible values are . (the current directory) or @PROJECT_DIR (the directory containing pyproject.toml).

      [tool.pyprojectx]\ncwd = \".\"\n

      Aliases can override the global cwd.

      "},{"location":"config/defaults/#environment-variables","title":"Environment variables","text":"

      You can set environment variables that will be added to the system environment when running a command:

      [tool.pyprojectx]\nenv = { POETRY_VIRTUALENVS_PATH = \"/data/poetry\" }\n

      Aliases can provide additional environment variables and/or override the global ones.

      "},{"location":"config/defaults/#shell","title":"Shell","text":"

      You can change the os shell used to run commands. The shell can be defined globally, os specific or alias specific.

      [tool.pyprojectx]\nshell = \"bash\n[tool.pyprojectx.os.win]\nshell = \"pwsh.exe\"\n

      Specifying a shell changes variable substitution

      Commands are converted into a single string and passed to the shell with the -c option, example: bash -c \"echo $PATH\". This changes the variable substitution that is done by your os and can lead to unexpected results.

      When you set a shell for os specific file operations, consider using px-utils instead.

      [tool.pyprojectx.alias]\nprepare = \"pxmkdirs build generated\"\ncopy = \"pxcp src/**/*.py build/python\"\nmove = \"pxmv data/**/*.json build/data\"\nclean = \"pxrm build generated\"\n

      "},{"location":"config/scripts/","title":"Run Python scripts","text":"

      Logic that is too complex to embed in pyproject.toml can be written in Python scripts in the bin directory. These can be called from aliases or from the command line with pw <script-name>.

      The scripts run by default in the main tool context and hence can use all libraries installed in the main tool context.

      To run a script in a different tool context, you either:

      • define an alias:
      [tool.pyprojectx.aliases]\n# run the generate-data script in the 'jupyter' tool context\ngenerate-data = { cmd = 'generate-data', ctx = 'jupyter' }\n
      • or specify the scripts_ctx in pyproject.toml (see recipes) :
      [tool.pyprojectx]\nscripts_ctx = \"scripts\"\n

      The default script directory can be changed by specifying the scripts_dir in pyproject.toml:

      [tool.pyprojectx]\nscripts_dir = \"scripts\"\n
      "},{"location":"config/tools/","title":"Manage tools as dev dependencies","text":"

      Pyprojectx can manage all the Python tools and utilities that you use for building, testing...

      Adding tools to the [tool.pyprojectx] section in pyproject.toml makes them available inside your project.

      Tool contexts introduced in Pyprojectx 2.0.0

      Prior to Pyprojectx 2.0.0, tools were always installed in a separate virtual environment. As of 2.0.0, tools are by default installed in the virtual environment of the main tool context.

      px or pw?

      This section assumes that you installed the px utility script. Otherwise, you need to replace px with ./pw (Linux, Mac) or pw (Windows PowerShell).

      "},{"location":"config/tools/#tool-contexts","title":"Tool contexts","text":"

      Pyprojectx creates an isolated virtual environment for each tool context (set of tools).

      Inside the [tool.pyprojectx] section of pyproject.toml you specify what needs to be installed.

      pyproject.toml
      [tool.pyprojectx]\n# require a specific poetry version, use the latest version of black\nmain = [\"poetry==1.1.11\", \"black\"]\n

      Above configuration makes the black and poetry commands available inside your project.

      You only need to prefix them with thepx or pw wrapper script:

      Any OS with pxLinux/MacWindows
      px poetry --help\npx black my_package --diff\n
      ./pw poetry --help\n./pw black my_package --diff\n
      pw poetry --help\npw black my_package --diff\n

      Naming your tool context

      When running a command that has the same name as a tool context, the command will be executed by default inside the virtual environment of that tool context. Otherwise, the command will be executed in the virtual environment of the main tool context.

      "},{"location":"config/tools/#tool-context-activation","title":"Tool context activation","text":"

      If you don't want to prefix every command with px or ./pw, you can activate a tool context.

      For example, to activate the main tool context run source .pyprojectx/main/activate. This makes all the tools in the main context available in your shell.

      Alternatively, you can add .pyprojectx/main to your PATH.

      Upgrading from Pyprojectx < 2.1.0

      If the virtual environment of a tool cotext is already present, you will need to re-create it to use the new activation mechanism, either by removing the .pyprojectx directory or by running any command with the --force-install option, f.e. ./pw -f --install-context main.

      "},{"location":"config/tools/#tool-context-configuration","title":"Tool context configuration","text":"

      In its simplest form, a tool context is a multiline string or array of strings that adheres to pip's Requirements File Format

      Example:

      pyproject.toml
      [tool.pyprojectx]\nmain = [\"pdm\",\"ruff\",\"pre-commit\",\"px-utils\"]\nhttp = \"httpie ~= 3.0\"\n

      With above configuration, you can run following commands:

      px pdm --version\n# PDM, version 2.11.2\npx http www.google.com\n# HTTP/1.1 200 OK ...\n

      Tip: Lock your tool requirements

      This makes sure that your build won't break when new versions of a tool are released,or when a tool is broken by a new release of one of its dependencies.

      You can also include requirements from a text file or pyproject.toml file with -r:

      [tool.pyprojectx]\nmain = [\"-r pyproject.toml\", \"-r dev-requirements.txt\"]\n

      If you want to install a prerelease version of a tool, you need to configure it:

      [tool.pyprojectx]\nprerelease = \"allow\"\n

      "},{"location":"config/tools/#post-install-scripts","title":"Post-install scripts","text":"

      In some situations it can be useful to perform additional actions after a tool has been installed. This is achieved by configuring both requirements and post-install scripts for a tool

      [tool.pyprojectx]\n[tool.pyprojectx.main]\nrequirements = [\"pdm\", \"ruff\", \"pre-commit\", \"px-utils\"]\npost-install = \"pre-commit install\"\n

      When creating your project's virtual environment with px pdm install for the first time in the example above, pre-commit is also initialised. This makes sure that pre-commit hooks are always run when committing code.

      Tip: Use toml subsections for better readability

      The example above uses a toml subsection instead of an inline table:

      main = { requirements = [...], post-install=\"...\"}`\n

      "},{"location":"config/tools/#using-an-alternative-package-index","title":"Using an alternative package index","text":"

      You can use pip's --index-url or --extra-index-url to install packages from alternative (private) package indexes:

      [tool.pyprojectx]\nprivate-tool = [\n    \"--extra-index-url https://artifactory.acme.com/artifactory/api/pypi/python-virtual/simple\",\n    \"some-private-package\"\n]\n
      "},{"location":"config/tools/#locking-requirements","title":"Locking requirements","text":"

      To achieve reproducible builds, you can lock the versions of all tools that you use in your project by:

      • creating a pw.lock file
      • pinning tool versions in pyproject.toml
      "},{"location":"config/tools/#creating-a-pwlock-file","title":"Creating a pw.lock file","text":"

      When you run ./pw --lock, a pw.lock file is created in the root directory of your project. This file should be committed to version control.

      This is the recommended way to lock tool versions to guarantee reproducible builds (see why)

      The lock file is automatically updated when the tool context requirements in pyproject.toml change.

      To upgrade all tools to the latest version (respecting the requirements in pyproject.toml), combine the lock option with the force-install option: ./pw --lock -f.

      Supporting multiple Python versions

      When generating the lock file, the version of the current Python interpreter is used as minimum version that should be supported by the resolved requirements. You can override this by configuring the lock-python-version, e.g., 3.8 or 3.8.17:

      [tool.pyprojectx]\nlock-python-version = \"3.8\"\n

      Tip: don't specify tool versions in pyproject.toml when using a pw.lock file

      When there is no version specified for a tool, the latest version will be installed and locked. Updating all tools to the latest version is then as simple as running ./pw --lock again. In case of conflicts or issues with a new version, you can always revert to the previous version of the lock file.

      "},{"location":"config/tools/#pinning-tool-versions-in-pyprojecttoml","title":"Pinning tool versions in pyproject.toml","text":"

      You can also pin tool versions in pyproject.toml:

      [tool.pyprojectx]\nmain = [\"pdm==2.11.2\", \"ruff==0.1.11\", \"pre-commit==3.6.0\", \"px-utils==1.0.1\"]\n
      Be aware that even with a fixed version, tools can break at future installs!

      "}]} \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index febfcb24da9be589b8a600351d477a5a2e9613ee..2f43da2fbb1b54ea96d16be400c47a7ec91dc9e9 100644 GIT binary patch delta 13 Ucmb=gXP58h;9z)TJdwQu02=cH?*IS* delta 13 Ucmb=gXP58h;9y|ZnaExN02WFD{{R30 diff --git a/usage/index.html b/usage/index.html index f0c9fb4..3d4b3fa 100644 --- a/usage/index.html +++ b/usage/index.html @@ -16,7 +16,7 @@ - +