diff --git a/README.md b/README.md index 84cd67b6b..bc637ed87 100644 --- a/README.md +++ b/README.md @@ -1,295 +1,61 @@ -# setup-python V4 +# setup-python

GitHub Actions status

-This action sets up a Python environment for use in actions by: +This action provides the following functionality for GitHub Actions users: -- optionally installing and adding to PATH a version of Python that is already installed in the tools cache. -- downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the tools cache. -- failing if a specific version of Python is not preinstalled or available for download. -- optionally caching dependencies for pip, pipenv and poetry. -- registering problem matchers for error output. +- Installing a version of Python or PyPy and (by default) adding it to the PATH +- Optionally caching dependencies for pip, pipenv and poetry +- Registering problem matchers for error output -# What's new - -- Ability to download, install and set up Python packages from `actions/python-versions` that do not come preinstalled on runners. - - Allows for pinning to a specific patch version of Python without the worry of it ever being removed or changed. -- Automatic setup and download of Python packages if using a self-hosted runner. -- Support for pre-release versions of Python. -- Support for installing any version of PyPy on-flight -- Support for built-in caching of pip, pipenv and poetry dependencies -- Support for `.python-version` file - -# Usage +## Basic usage See [action.yml](action.yml) -Basic: -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax - architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified -- run: python my_script.py -``` - -Read Python version from file: -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version-file: '.python-version' # Read python version from a file -- run: python my_script.py -``` - -Matrix Testing: -```yaml -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.7', 'pypy3.8' ] - name: Python ${{ matrix.python-version }} sample - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - architecture: x64 - - run: python my_script.py -``` - -Exclude a specific Python version: -```yaml -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.8'] - exclude: - - os: macos-latest - python-version: '3.8' - - os: windows-latest - python-version: '3.6' - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Display Python version - run: python --version -``` - -Download and set up a version of Python that does not come preinstalled on an image: -```yaml -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - # in this example, there is a newer version already installed, 3.7.7, so the older version will be downloaded - python-version: ['3.7.4', '3.8', '3.9', '3.10'] - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - run: python my_script.py -``` - -Download and set up an accurate pre-release version of Python: -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.11.0-alpha.1' -- run: python my_script.py -``` - -Download and set up the latest available version of Python (includes both pre-release and stable versions): +**Python** ```yaml steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: '3.11.0-alpha - 3.11.0' # SemVer's version range syntax + python-version: '3.10' - run: python my_script.py ``` -Download and set up the latest patch version of Python (for specified major & minor versions): +**PyPy** ```yaml steps: - uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.11-dev' -- run: python my_script.py -``` - -Download and set up the latest stable version of Python (for specified major version): -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 +- uses: actions/setup-python@v4 with: - python-version: '3.x' + python-version: 'pypy3.9' - run: python my_script.py ``` +The `python-version` input is optional. If not supplied, the action will try to resolve the version from the default `.python-version` file. If the `.python-version` file doesn't exist Python or PyPy version from the PATH will be used. The default version of Python or PyPy in PATH varies between runners and can be changed unexpectedly so we recommend always using `setup-python`. -Download and set up PyPy: - -```yaml -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: - - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7 - - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3 - - 'pypy3.8' # the latest available version of PyPy that supports Python 3.8 - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - run: python my_script.py -``` -More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#available-versions-of-pypy) section. - -An output is available with the absolute path of the python interpreter executable if you need it: -```yaml -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - id: cp310 - with: - python-version: "3.10" - - run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version -``` - ->The environment variable `pythonLocation` also becomes available after Python or PyPy installation. It contains the absolute path to the folder where the desired version of Python or PyPy is installed. - -# Getting started with Python + Actions - -Check out our detailed guide on using [Python with GitHub Actions](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions). - -# Available versions of Python - -`setup-python` is able to configure Python from two sources: - -- Preinstalled versions of Python in the tools cache on GitHub-hosted runners. - - For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software). - - For every minor version of Python, expect only the latest patch to be preinstalled. - - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tools cache. - - If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache. - - Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*. -- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)). - - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file. - - If there is a specific version of Python that is not available, you can open an issue here - -**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images python versions are built from the source code. For Windows the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository. - - # Available versions of PyPy - - `setup-python` is able to configure PyPy from two sources: - -- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners - - For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software). - - For the latest PyPy release, all versions of Python are cached. - - Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`. - -- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/). - - All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file. - - PyPy < 7.3.3 are not available to install on-flight. - - If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/ - -# Hosted Tool Cache - -GitHub hosted runners have a tools cache that comes with a few versions of Python + PyPy already installed. This tools cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tools cache and adding it to PATH. - -|| Location | -|------|-------| -|**Tool Cache Directory** |`RUNNER_TOOL_CACHE`| -|**Python Tool Cache**|`RUNNER_TOOL_CACHE/Python/*`| -|**PyPy Tool Cache**|`RUNNER_TOOL_CACHE/PyPy/*`| - -GitHub virtual environments are setup in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, setup and documented. -- Tools cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1) -- Tools cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1) - -# Specifying a Python version - -If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the exact major, minor, and patch version (such as `3.7.5`) - - The only downside to this is that set up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions. - - MSI installers are used on Windows for this, so runs will take a little longer to set up vs Mac and Linux. - -You should specify only a major and minor version if you are okay with the most recent patch version being used. - - There will be a single patch version already installed on each runner for every minor version of Python that is supported. - - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced. - - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used. - -# Specifying a PyPy version -The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`. -The `` parameter is optional and can be skipped. The latest version will be used in this case. - -``` -pypy3.7 or pypy-3.7 # the latest available version of PyPy that supports Python 3.7 -pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8 -pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7 -pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3 -pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x -pypy3.7-v7.3.3rc1 or pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy -pypy3.7-nightly or pypy-3.7-nightly # Python 3.7 and nightly PyPy -``` - -Note: `pypy2` and `pypy3` have been removed in v3. Use the format above instead. +The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/). -# Check latest version +For information regarding locally cached versions of Python or PyPy on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments). -The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific `Python/PyPy` version is always used. +## Supported version syntax -If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, a `Python/PyPy` version will then be downloaded. Set `check-latest` to `true` if you want the most up-to-date `Python/PyPy` version to always be used. +The `python-version` input supports the [Semantic Versioning Specification](https://semver.org/) and some special version notations (e.g. `semver ranges`, `x.y-dev syntax`, etc.), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-the-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide. -> Setting `check-latest` to `true` has performance implications as downloading `Python/PyPy` versions is slower than using cached versions. +## Supported architectures -```yaml -steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 - with: - python-version: '3.7' - check-latest: true - - run: python my_script.py -``` - -# Caching packages dependencies +Using `architecture` input it is possible to specify the required Python or PyPy interpreter architecture: `x86` or `x64`. If the input is not specified the architecture defaults to `x64`. -The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip`, `pipenv` and `poetry`. The `cache` input is optional, and caching is turned off by default. +## Caching packages dependencies -The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases where multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used. +The action has built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip`, `pipenv` and `poetry`. The `cache` input is optional, and caching is turned off by default. - - For pip, the action will cache global cache directory - - For pipenv, the action will cache virtualenv directory - - For poetry, the action will cache virtualenv directory +The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash that want to be used. -**Please Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available that can lead to an increase in total build time. - -The requirements file format allows to specify dependency versions using logical operators (for example chardet>=3.0.4) or specify dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary. + - For `pip`, the action will cache the global cache directory + - For `pipenv`, the action will cache virtualenv directory + - For `poetry`, the action will cache virtualenv directory **Caching pip dependencies:** @@ -299,151 +65,31 @@ steps: - uses: actions/setup-python@v4 with: python-version: '3.9' - cache: 'pip' + cache: 'pip' # caching pip dependencies - run: pip install -r requirements.txt ``` +>**Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available which can lead to an increase in total build time. -**Caching pipenv dependencies:** -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'pipenv' -- name: Install pipenv - run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python -- run: pipenv install -``` - -**Caching poetry dependencies:** -```yaml -steps: -- uses: actions/checkout@v3 -- name: Install poetry - run: pipx install poetry -- uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'poetry' -- run: poetry install -- run: poetry run pytest -``` - -**If you only need poetry install, consider using pip:** -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'pip' - cache-dependency-path: 'poetry.lock' -- run: pip install . -- run: pytest -``` - -**Using wildcard patterns to cache dependencies** -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'pip' - cache-dependency-path: '**/requirements-dev.txt' -- run: pip install -r subdirectory/requirements-dev.txt -``` - -**Using a list of file paths to cache dependencies** -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'pipenv' - cache-dependency-path: | - server/app/Pipfile.lock - __test__/app/Pipfile.lock -- name: Install pipenv - run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python -- run: pipenv install -``` - -**Using a list of wildcard patterns to cache dependencies** -```yaml -steps: -- uses: actions/checkout@v3 -- uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' - cache-dependency-path: | - **/setup.cfg - **/requirements*.txt -- run: pip install -e . -r subdirectory/requirements-dev.txt -``` - - -# Environment variables - - The `update-environment` flag defaults to `true`. - With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box. - - If `update-environment` is set to `false`, the action will not add/update environment variables. - This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python. - Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows. - - ```yaml - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - id: cp310 - with: - python-version: '3.10' - update-environment: false - - run: ${{ steps.cp310.outputs.python-path }} my_script.py - ``` - -# Using `setup-python` with a self hosted runner - -Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner. - -If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs. - -### Windows - -- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time. -- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient. -- You need `7zip` installed and added to your `PATH` so that the downloaded versions of Python files can be extracted properly during first-time setup. -- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings. -- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app. - -### Linux - -- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source with the [--enable-shared](https://github.com/actions/python-versions/blob/main/builders/ubuntu-python-builder.psm1#L37) flag. -- By default runner downloads and install the tools to the `RUNNER_TOOL_CACHE` directory, however `AGENT_TOOLSDIRECTORY` can be set to override this location. - -### Mac - -- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source with the [--enable-shared](https://github.com/actions/python-versions/blob/main/builders/macos-python-builder.psm1#L44) flag, however lack the relocatable flag. -- Due to the fixed shared library path, only the hosted tool cache of `/Users/runner/hostedtoolcache` is supported, and the path must be writeable by the runner user. - -# Using Python without `setup-python` - -`setup-python` helps keep your dependencies explicit and ensures consistent behavior between different runners. If you use `python` in a shell on a GitHub hosted runner without `setup-python` it will default to whatever is in PATH. The default version of Python in PATH vary between runners and can change unexpectedly so we recommend you always use `setup-python`. +>The requirements file format allows for specifying dependency versions using logical operators (for example chardet>=3.0.4) or specifying dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary. -# Using `setup-python` on GHES +See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poetry` in the section: [Caching packages](docs/advanced-usage.md#caching-packages) of the [Advanced usage](docs/advanced-usage.md) guide. -`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during download that read `##[error]API rate limit exceeded for...`. +## Advanced usage -To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache). +- [Using the python-version input](docs/advanced-usage.md#using-the-python-version-input) +- [Using the python-version-file input](docs/advanced-usage.md#using-the-python-version-file-input) +- [Check latest version](docs/advanced-usage.md#check-latest-version) +- [Caching packages](docs/advanced-usage.md#caching-packages) +- [Outputs and environment variables](docs/advanced-usage.md#outputs-and-environment-variables) +- [Available versions of Python and PyPy](docs/advanced-usage.md#available-versions-of-python-and-pypy) +- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache) +- [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner) +- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes) -# License +## License The scripts and documentation in this project are released under the [MIT License](LICENSE). -# Contributions +## Contributions -Contributions are welcome! See our [Contributor's Guide](docs/contributors.md). +Contributions are welcome! See our [Contributor's Guide](docs/contributors.md). \ No newline at end of file diff --git a/action.yml b/action.yml index f4aeb35b9..c0fd1d122 100644 --- a/action.yml +++ b/action.yml @@ -1,35 +1,35 @@ --- -name: 'Setup Python' -description: 'Set up a specific version of Python and add the command-line tools to the PATH.' -author: 'GitHub' +name: "Setup Python" +description: "Set up a specific version of Python and add the command-line tools to the PATH." +author: "GitHub" inputs: python-version: - description: "Version range or exact version of Python to use, using SemVer's version range syntax. Reads from .python-version if unset." + description: "Version range or exact version of Python or PyPy to use, using SemVer's version range syntax. Reads from .python-version if unset." python-version-file: description: "File containing the Python version to use. Example: .python-version" cache: - description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry.' + description: "Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry." required: false architecture: - description: 'The target architecture (x86, x64) of the Python interpreter.' + description: "The target architecture (x86, x64) of the Python or PyPy interpreter." check-latest: - description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec.' + description: "Set this option if you want the action to check for the latest available version that satisfies the version spec." default: false token: - description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user. + description: "Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user." default: ${{ github.token }} cache-dependency-path: - description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.' + description: "Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies." update-environment: - description: 'Set this option if you want the action to update environment variables.' + description: "Set this option if you want the action to update environment variables." default: true outputs: python-version: - description: "The installed python version. Useful when given a version range as input." + description: "The installed Python or PyPy version. Useful when given a version range as input." cache-hit: - description: 'A boolean value to indicate a cache entry was found' + description: "A boolean value to indicate a cache entry was found" python-path: - description: "The absolute path to the Python executable." + description: "The absolute path to the Python or PyPy executable." runs: using: 'node16' main: 'dist/setup/index.js' diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md new file mode 100644 index 000000000..024e8b1ec --- /dev/null +++ b/docs/advanced-usage.md @@ -0,0 +1,476 @@ +# Advanced Usage +- [Using the python-version input](advanced-usage.md#using-the-python-version-input) + - [Specifying a Python version](advanced-usage.md#specifying-a-python-version) + - [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version) + - [Matrix Testing](advanced-usage.md#matrix-testing) +- [Using the python-version-file input](advanced-usage.md#using-the-python-version-file-input) +- [Check latest version](advanced-usage.md#check-latest-version) +- [Caching packages](advanced-usage.md#caching-packages) +- [Outputs and environment variables](advanced-usage.md#outputs-and-environment-variables) + - [Outputs](advanced-usage.md#outputs) + - [Environment variables](advanced-usage.md#environment-variables) + - [Using update-environment flag](advanced-usage.md#using-update-environment-flag) +- [Available versions of Python and PyPy](advanced-usage.md#available-versions-of-python-and-pypy) + - [Python](advanced-usage.md#python) + - [PyPy](advanced-usage.md#pypy) +- [Hosted tool cache](advanced-usage.md#hosted-tool-cache) +- [Using `setup-python` with a self-hosted runner](advanced-usage.md#using-setup-python-with-a-self-hosted-runner) + - [Windows](advanced-usage.md#windows) + - [Linux](advanced-usage.md#linux) + - [macOS](advanced-usage.md#macos) +- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes) + +## Using the `python-version` input + +### Specifying a Python version + +If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`): + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.7.5' +- run: python my_script.py +``` + +- The only downside to this is that setup may take a little longer. If the exact version is not already installed on the runner due to more recent versions, the exact version will have to be downloaded. +- MSI installers are used on Windows for this, so runs will take a little longer to set up vs macOS and Linux. + +You can specify **only a major and minor version** if you are okay with the most recent patch version being used: + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.7' +- run: python my_script.py +``` +- There will be a single patch version already installed on each runner for every minor version of Python that is supported. +- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced. +- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used. + +You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python: + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.11.0-alpha.1' +- run: python my_script.py +``` + +It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions): + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.11-dev' +- run: python my_script.py +``` + +You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance: + +- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions): + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.11.0-alpha - 3.11.0' +- run: python my_script.py +``` + +- **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version): + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.x' +- run: python my_script.py +``` +Please refer to the [Advanced range syntax section](https://github.com/npm/node-semver#advanced-range-syntax) of the [semver](https://github.com/npm/node-semver) to check other available range syntaxes. + +### Specifying a PyPy version +The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`. +The `-v` parameter is optional and can be skipped. The latest PyPy version will be used in this case. + +``` +pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8 +pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7 +pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3 +pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x +pypy3.7-v7.3.3rc1 or pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy +pypy3.7-nightly or pypy-3.7-nightly # Python 3.7 and nightly PyPy +``` + +Download and set up PyPy: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7 + - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - run: python my_script.py +``` +More details on PyPy syntax can be found in the [Available versions of PyPy](#pypy) section. + +### Matrix Testing + +Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python or PyPy: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.7', 'pypy3.8' ] + name: Python ${{ matrix.python-version }} sample + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + - run: python my_script.py +``` + +Exclude a specific Python version: + +```yaml +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.8'] + exclude: + - os: macos-latest + python-version: '3.8' + - os: windows-latest + python-version: '3.6' + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Display Python version + run: python --version +``` + +## Using the `python-version-file` input + +`setup-python` action can read Python or PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the file that was supplied to `python-version-file` input doesn't exist, the action will fail with error. + +>In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority. + +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version-file: '.python-version' # Read python version from a file .python-version +- run: python my_script.py +``` +## Check latest version + +The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific `Python or PyPy` version is always used. + +If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, a `Python or PyPy` version will then be downloaded. Set `check-latest` to `true` if you want the most up-to-date `Python or PyPy` version to always be used. + +```yaml +steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + with: + python-version: '3.7' + check-latest: true + - run: python my_script.py +``` +> Setting `check-latest` to `true` has performance implications as downloading `Python or PyPy` versions is slower than using cached versions. + + +## Caching packages + +**Caching pipenv dependencies:** +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pipenv' +- name: Install pipenv + run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python +- run: pipenv install +``` + +**Caching poetry dependencies:** +```yaml +steps: +- uses: actions/checkout@v3 +- name: Install poetry + run: pipx install poetry +- uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'poetry' +- run: poetry install +- run: poetry run pytest +``` + +**Using a list of file paths to cache dependencies** +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pipenv' + cache-dependency-path: | + server/app/Pipfile.lock + __test__/app/Pipfile.lock +- name: Install pipenv + run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python +- run: pipenv install +``` +**Using wildcard patterns to cache dependencies** +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pip' + cache-dependency-path: '**/requirements-dev.txt' +- run: pip install -r subdirectory/requirements-dev.txt +``` + +**Using a list of wildcard patterns to cache dependencies** +```yaml +steps: +- uses: actions/checkout@v3 +- uses: actions/setup-python@v4 + with: + python-version: '3.10' + cache: 'pip' + cache-dependency-path: | + **/setup.cfg + **/requirements*.txt +- run: pip install -e . -r subdirectory/requirements-dev.txt +``` + +# Outputs and environment variables + +## Outputs + +### `python-version` + +Using **python-version** output it's possible to get the installed by action Python or PyPy version. This output is useful when the input `python-version` is given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1). + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + id: cp310 + with: + python-version: "3.8.0 - 3.10.0" + - run: echo '${{ steps.cp310.outputs.python-version }}' +``` + +### `python-path` + +**python-path** output is available with the absolute path of the Python or PyPy interpreter executable if you need it: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + id: cp310 + with: + python-version: "3.10" + - run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version +``` +### `cache-hit` + +**cache-hit** output is available with a boolean value that indicates whether a cache hit occurred on the primary key: + +``` +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + id: cp310 + with: + python-version: "3.8.0" + cache: "poetry" + - run: echo '${{ steps.cp310.outputs.cache-hit }}' # true if cache-hit occured on the primary key +``` + +## Environment variables + +These environment variables become available after setup-python action execution: + +| **Env.variable** | **Description** | +| ----------- | ----------- | +| pythonLocation |Contains the absolute path to the folder where the requested version of Python or PyPy is installed| +| Python_ROOT_DIR | https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython | +| Python2_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2| +| Python3_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython3| + +## Using `update-environment` flag + +The `update-environment` flag defaults to `true`. +With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for Python or PyPy to just work out of the box. + +If `update-environment` is set to `false`, the action will not add/update environment variables. +This can prove useful if you want the only side-effect to be to ensure Python or PyPy is installed and rely on the `python-path` output to run executable. +Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows. + +```yaml + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + id: cp310 + with: + python-version: '3.10' + update-environment: false + - run: ${{ steps.cp310.outputs.python-path }} my_script.py +``` +## Available versions of Python and PyPy +### Python + +`setup-python` is able to configure **Python** from two sources: + +- Preinstalled versions of Python in the tool cache on GitHub-hosted runners. + - For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software). + - For every minor version of Python, expect only the latest patch to be preinstalled. + - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tool cache. + - If the exact patch version doesn't matter to you, specifying just the major and minor versions will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache. + - Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*. +- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)). + - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file. + - If there is a specific version of Python that is not available, you can open an issue here + +>**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images, python versions are built from the source code. For Windows, the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository. + +### PyPy + + `setup-python` is able to configure **PyPy** from two sources: + +- Preinstalled versions of PyPy in the tool cache on GitHub-hosted runners + - For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software). + - For the latest PyPy release, all versions of Python are cached. + - Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`. + +- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/). + - All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file. + - PyPy < 7.3.3 are not available to install on-flight. + - If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/ + +## Hosted tool cache + +GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of the tool cache with Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy from this tool cache and adding it to PATH. + +|| Location | +|------|-------| +|**Tool cache Directory** |`RUNNER_TOOL_CACHE`| +|**Python tool cache**|`RUNNER_TOOL_CACHE/Python/*`| +|**PyPy tool cache**|`RUNNER_TOOL_CACHE/PyPy/*`| + +GitHub virtual environments are set up in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, set up and documented. +- Tool cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1) +- Tool cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1) + + +## Using `setup-python` with a self-hosted runner + +Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` may not work. + +If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner. + + +### Windows + +- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time. +- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient. +- You need `7zip` installed and added to your `PATH` so that the downloaded versions of Python files can be extracted properly during the first-time setup. +- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings. +- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app. + +> By default runner downloads and installs tools into the folder set up by `RUNNER_TOOL_CACHE` environment variable. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location for Windows self-hosted runners. + +>If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see additional logs. + +### Linux + +By default runner downloads and installs tools into the folder set up by `RUNNER_TOOL_CACHE` environment variable. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location for Linux self-hosted runners: +- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/path/to/folder`. +- More permanent way of setting the environment variable is to create an `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/path/to/folder`. This ensures the variable is always set if your runner is configured as a service. + +If you're using a non-default tool cache directory be sure that the user starting the runner has write permission to the new tool cache directory. To check the current user and group that the runner belongs type `ls -l` inside the runner's root directory. + +The runner can be granted write access to any directory using a few techniques: +- The user starting the runner is the owner, and the owner has write permission. +- The user starting the runner is in the owning group, and the owning group has write permission. +- All users have write permission. +One quick way to grant access is to change the user and group of the non-default tool cache folder to be the same as the runners using `chown`: +`sudo chown runner-user:runner-group /path/to/folder`. + + +> If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service). + + +### macOS + + The Python packages for macOS that are downloaded from `actions/python-versions` are originally compiled from the source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before the use of `setup-python` on the macOS self-hosted runner: + + - Create a directory called `/Users/runner/hostedtoolcache` + - Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access + +You can check the current user and group that the runner belongs to by typing `ls -l` inside the runner's root directory. +The runner can be granted write access to the `/Users/runner/hostedtoolcache` directory using a few techniques: + - The user starting the runner is the owner, and the owner has write permission + - The user starting the runner is in the owning group, and the owning group has write permission + - All users have write permission. +One quick way to grant access is to change the user and group of `/Users/runner/hostedtoolcache` to be the same as the runners using `chown`: +`sudo chown runner-user:runner-group /Users/runner/hostedtoolcache` + +> If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service). + + + +## Using `setup-python` on GHES + +`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during downloading that looks like: `##[error]API rate limit exceeded for...`. + +To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache). \ No newline at end of file