Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/e2e-cache-freethreaded.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,56 @@ jobs:
pip-version: '25.0.1'
- name: Install dependencies
run: pip install numpy pandas requests

python-pip-dependencies-caching-with-pip-install:
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
[
ubuntu-latest,
ubuntu-22.04,
ubuntu-24.04-arm,
ubuntu-22.04-arm,
windows-latest,
macos-latest,
macos-13
]
python-version: [3.13.0t, 3.13.1t, 3.13.2t]
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
pip-install: numpy pandas requests

python-pip-dependencies-caching-path-with-pip-install:
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }}, caching path)
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
[
ubuntu-latest,
ubuntu-22.04,
ubuntu-24.04-arm,
ubuntu-22.04-arm,
windows-latest,
macos-latest,
macos-13
]
python-version: [3.13.0t, 3.13.1t, 3.13.2t]
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: __tests__/data/requirements.txt
pip-install: numpy pandas requests
53 changes: 53 additions & 0 deletions .github/workflows/e2e-cache.yml
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,56 @@ jobs:
pip-version: '25.0.1'
- name: Install dependencies
run: pip install numpy pandas requests

python-pip-dependencies-caching-with-pip-install:
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
[
ubuntu-latest,
ubuntu-24.04-arm,
ubuntu-22.04,
ubuntu-22.04-arm,
windows-latest,
macos-latest,
macos-13
]
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
pip-install: numpy pandas requests

python-pip-dependencies-caching-path-with-pip-install:
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }}, caching path)
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
[
ubuntu-latest,
ubuntu-24.04-arm,
ubuntu-22.04,
ubuntu-22.04-arm,
windows-latest,
macos-latest,
macos-13
]
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: __tests__/data/requirements.txt
pip-install: numpy pandas requests
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poet
- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
- [Allow pre-releases](docs/advanced-usage.md#allow-pre-releases)
- [Using the pip-version input](docs/advanced-usage.md#using-the-pip-version-input)
- [Using the pip-install input](docs/advanced-usage.md#using-the-pip-install-input)

## Recommended permissions

Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ inputs:
default: false
pip-version:
description: "Used to specify the version of pip to install with the Python. Supported format: major[.minor][.patch]."
pip-install:
description: "Used to specify the packages to install with pip after setting up Python. Can be a requirements file or package names."
outputs:
python-version:
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"
python-path:
description: "The absolute path to the Python or PyPy executable."

runs:
using: 'node20'
main: 'dist/setup/index.js'
Expand Down
19 changes: 19 additions & 0 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -97945,12 +97945,30 @@ const os = __importStar(__nccwpck_require__(857));
const fs_1 = __importDefault(__nccwpck_require__(9896));
const cache_factory_1 = __nccwpck_require__(665);
const utils_1 = __nccwpck_require__(1798);
const exec_1 = __nccwpck_require__(5236);
function isPyPyVersion(versionSpec) {
return versionSpec.startsWith('pypy');
}
function isGraalPyVersion(versionSpec) {
return versionSpec.startsWith('graalpy');
}
function installPipPackages() {
return __awaiter(this, void 0, void 0, function* () {
const pipInstall = core.getInput('pip-install');
if (!pipInstall) {
return;
}
core.info(`Installing pip packages: ${pipInstall}`);
try {
const installArgs = pipInstall.trim().split(/\s+/);
yield (0, exec_1.exec)('python', ['-m', 'pip', 'install', ...installArgs]);
core.info('Successfully installed pip packages');
}
catch (error) {
core.setFailed(`Failed to install pip packages from "${pipInstall}". Please verify that the package names and versions in the requirements file are correct, that the specified packages and versions can be resolved from PyPI or the configured package index, and that your network connection is stable and allows access to the package index.`);
}
});
}
function cacheDependencies(cache, pythonVersion) {
return __awaiter(this, void 0, void 0, function* () {
const cacheDependencyPath = core.getInput('cache-dependency-path') || undefined;
Expand Down Expand Up @@ -98079,6 +98097,7 @@ function run() {
if (cache && (0, utils_1.isCacheFeatureAvailable)()) {
yield cacheDependencies(cache, pythonVersion);
}
yield installPipPackages();
}
else {
core.warning('The `python-version` input is not set. The version of Python currently in `PATH` will be used.');
Expand Down
22 changes: 21 additions & 1 deletion docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
- [Allow pre-releases](advanced-usage.md#allow-pre-releases)
- [Using the pip-version input](advanced-usage.md#using-the-pip-version-input)
- [Using the pip-install input](advanced-usage.md#using-the-pip-install-input)

## Using the `python-version` input

Expand Down Expand Up @@ -671,4 +672,23 @@ The version of Pip should be specified in the format `major`, `major.minor`, or
```
> The `pip-version` input is supported only with standard Python versions. It is not available when using PyPy or GraalPy.

> Using a specific or outdated version of pip may result in compatibility or security issues and can cause job failures. For best practices and guidance, refer to the official [pip documentation](https://pip.pypa.io/en/stable/).
> Using a specific or outdated version of pip may result in compatibility or security issues and can cause job failures. For best practices and guidance, refer to the official [pip documentation](https://pip.pypa.io/en/stable/).

## Using the pip-install input

The `pip-install` input allows you to install dependencies as part of the Python setup step.


```yaml
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
pip-install: -r requirements.txt
```
> Note: This feature is intended for standard pip-based dependency installations.
For complex workflows, or alternative package managers (e.g., poetry, pipenv), we recommend using separate steps to maintain clarity and flexibility.


21 changes: 21 additions & 0 deletions src/setup-python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getVersionInputFromFile,
getVersionsInputFromPlainFile
} from './utils';
import {exec} from '@actions/exec';

function isPyPyVersion(versionSpec: string) {
return versionSpec.startsWith('pypy');
Expand All @@ -22,6 +23,25 @@ function isGraalPyVersion(versionSpec: string) {
return versionSpec.startsWith('graalpy');
}

async function installPipPackages() {
const pipInstall = core.getInput('pip-install');

if (!pipInstall) {
return;
}
core.info(`Installing pip packages: ${pipInstall}`);

try {
const installArgs = pipInstall.trim().split(/\s+/);
await exec('python', ['-m', 'pip', 'install', ...installArgs]);
core.info('Successfully installed pip packages');
} catch (error) {
core.setFailed(
`Failed to install pip packages from "${pipInstall}". Please verify that the package names and versions in the requirements file are correct, that the specified packages and versions can be resolved from PyPI or the configured package index, and that your network connection is stable and allows access to the package index.`
);
}
}

export async function cacheDependencies(cache: string, pythonVersion: string) {
const cacheDependencyPath =
core.getInput('cache-dependency-path') || undefined;
Expand Down Expand Up @@ -194,6 +214,7 @@ async function run() {
if (cache && isCacheFeatureAvailable()) {
await cacheDependencies(cache, pythonVersion);
}
await installPipPackages();
} else {
core.warning(
'The `python-version` input is not set. The version of Python currently in `PATH` will be used.'
Expand Down
Loading