# 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)
- [Specifying multiple Python and PyPy versions](advanced-usage.md#specifying-multiple-python/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-pypy-and-graalpy)
- [Python](advanced-usage.md#python)
- [PyPy](advanced-usage.md#pypy)
- [GraalPy](advanced-usage.md#graalpy)
- [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)
- [Allow pre-releases](advanced-usage.md#allow-pre-releases)
## 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@v4
- 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@v4
- 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@v4
- uses: actions/setup-python@v4
with:
python-version: '3.12.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, beta and rc (release candidate) releases included. (for specified major & minor versions):
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.12-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:
- **[ranges](https://github.com/npm/node-semver#ranges)** to download and set up the latest available version of Python satisfying a range:
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '>=3.9 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
### Avoiding rate limit issues
`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 by default 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 look like this:
##[error]API rate limit exceeded for YOUR_IP. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)
To get a higher rate limit, you can [generate a personal access token (PAT) on github.com](https://github.com/settings/tokens/new) and pass it as the `token` input for the action. It is important to understand that this needs to be a token from github.com and _not_ from your GHES instance. If you or your colleagues do not yet have a github.com account, you might need to create one.
Here are the steps you need to follow to avoid the rate limit:
1. Create a PAT on any github.com account by using [this link](https://github.com/settings/tokens/new) after logging into github.com (not your Enterprise instance). This PAT does _not_ need any rights, so make sure all the boxes are unchecked.
2. Store this PAT in the repository / organization where you run your workflow, e.g. as `GH_GITHUB_COM_TOKEN`. You can do this by navigating to your repository -> **Settings** -> **Secrets** -> **Actions** -> **New repository secret**.
3. To use this functionality, you need to use any version newer than `v4.3`. Also, change _python-version_ as needed.
```yml
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.8
token: ${{ secrets.GH_GITHUB_COM_TOKEN }}
```
Requests should now be authenticated. To verify that you are getting the higher rate limit, you can call GitHub's [rate limit API](https://docs.github.com/en/rest/rate-limit) from within your workflow ([example](https://github.com/actions/setup-python/pull/443#issuecomment-1206776401)).
### No access to github.com
If the runner is not able to access github.com, any Python versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information.
## Allow pre-releases
The `allow-prereleases` flag defaults to `false`.
If `allow-prereleases` is set to `true`, the action will allow falling back to pre-release versions of Python when a matching GA version of Python is not available.
This allows for example to simplify reuse of `python-version` as an input of nox for pre-releases of Python by not requiring manipulation of the `3.y-dev` specifier.
For CPython, `allow-prereleases` will only have effect for `x.y` version range (e.g. `3.12`).
Let's say that python 3.12 is not generally available, the following workflow will fallback to the most recent pre-release of python 3.12:
```yaml
jobs:
test:
name: ${{ matrix.os }} / ${{ matrix.python_version }}
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
os: [Ubuntu, Windows, macOS]
python_version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "${{ matrix.python_version }}"
allow-prereleases: true
- run: pipx run nox --error-on-missing-interpreters -s tests-${{ matrix.python_version }}
```