Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for uv as package manager #124

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
42 changes: 42 additions & 0 deletions .circleci/test-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ jobs:
working_directory: ~/project/sample_poetry
command: |-
poetry run pytest
uv-test:
executor: python/default
steps:
- checkout
- python/install-packages:
app-dir: ~/project/sample_uv
cache-version: << pipeline.parameters.cache-version >>
pkg-manager: uv
- run:
working_directory: ~/project/sample_uv
command: |-
uvx run pytest
workflows:
test-deploy:
jobs:
Expand All @@ -155,6 +167,8 @@ workflows:
filters: *filters
- poetry-test:
filters: *filters
- uv-test:
filters: *filters
- dist-test:
name: "dist-test-wheel"
filters: *filters
Expand All @@ -180,6 +194,19 @@ workflows:
name: Verify cache was successful
working_directory: ~/project/sample_poetry
command: 'cat install_output.txt | grep "No dependencies to install or update"'
- python/test:
filters: *filters
name: job-test-uv
pkg-manager: uv
cache-version: uv-<< pipeline.parameters.cache-version >>
args: "| tee install_output.txt"
include-branch-in-cache-key: false
app-dir: ~/project/sample_uv
post-steps:
- run:
name: Verify cache was successful
working_directory: ~/project/sample_uv
command: 'cat install_output.txt | grep "No dependencies to install or update"'
- python/test:
filters: *filters
name: job-test-pipenv
Expand Down Expand Up @@ -213,6 +240,18 @@ workflows:
name: Verify cache was successful
working_directory: ~/project/sample_poetry
command: 'cat install_output.txt | grep "No dependencies to install or update"'
- python/test:
filters: *filters
name: job-auto-test-uv
cache-version: uv-auto-<< pipeline.parameters.cache-version >>
args: "| tee install_output.txt"
include-branch-in-cache-key: false
app-dir: ~/project/sample_uv
post-steps:
- run:
name: Verify cache was successful
working_directory: ~/project/sample_uv
command: 'cat install_output.txt | grep "No dependencies to install or update"'
- python/test:
filters: *filters
name: job-auto-test-pipenv
Expand Down Expand Up @@ -286,13 +325,16 @@ workflows:
- pip-install-test-args
- pipenv-test
- poetry-test
- uv-test
- pip-install-rel-dir
- job-test-poetry
- job-test-uv
- job-test-pipenv
- job-test-pip
- job-test-pip-dist
- job-test-pip-dist-pyproject
- job-auto-test-poetry
- job-auto-test-uv
- job-auto-test-pipenv
- job-auto-test-pip
- dist-test-wheel
Expand Down
17 changes: 17 additions & 0 deletions sample_uv/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Example toml for integration testing - this is not used by the orb in anyway
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
authors = ["Test"]
name = "test"
description = "none"
version = "0.0.1"
requires-python = ">=3.9"
dependencies = []

[dependency-groups]
dev = [
"pytest"
]
Empty file added sample_uv/tests/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions sample_uv/tests/test_job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

import unittest

class TestCase(unittest.TestCase):

def test_true(self):
assert True
88 changes: 88 additions & 0 deletions sample_uv/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion src/commands/install-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: >
parameters:
pkg-manager:
type: enum
enum: [auto, poetry, pipenv, pip, pip-dist]
enum: [auto, poetry, pipenv, pip, pip-dist, uv]
default: auto
description: Which package management tool to use, pipenv, pip or poetry with dependency file. Use `pip-dist` to install with project setup.py or PEP621 (pyproject.toml).
path-args:
Expand Down Expand Up @@ -143,6 +143,16 @@ steps:
working_directory: << parameters.app-dir >>
command: |
poetry install --no-ansi << parameters.args >>
- when:
condition:
equal: [uv, << parameters.pkg-manager >>]
steps:
- run:
name: "Install dependencies with uv using project pyproject.toml and uv.lock"
no_output_timeout: << parameters.no_output_timeout >>
working_directory: << parameters.app-dir >>
command: |
uv sync << parameters.args >>
- when:
condition:
# if pip == pkgmanager and args != "" or pip-dependency-file != ""
Expand Down
23 changes: 23 additions & 0 deletions src/examples/work-with-uv.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
description: |
An example of working with the uv cache on CircleCI to speed up builds.
usage:
version: 2.1
orbs:
python: circleci/[email protected]
workflows:
main:
jobs:
- build
jobs:
build:
executor: python/default
steps:
- checkout
- python/install-packages:
pkg-manager: uv
- run:
name: "Test it"
# pytest would have to be defined in pyproject.toml
# inline packages are not allowed with uv sync
command: |
uv run pytest --version
8 changes: 5 additions & 3 deletions src/jobs/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ parameters:
The name of executor to use.
pkg-manager:
type: enum
enum: [auto, pip, pipenv, poetry, pip-dist]
enum: [auto, pip, pipenv, poetry, pip-dist, uv]
default: "auto"
description: Select the package manager to use. Default is pip
pip-dependency-file:
type: string
default: requirements.txt
description: Name of the requirements file that needs to be installed with pip. Prepended with `app-dir`. If using pipenv or poetry, this is ignored.
description: Name of the requirements file that needs to be installed with pip. Prepended with `app-dir`. If using pipenv, poetry or uv, this is ignored.
app-dir:
type: string
default: "~/project"
Expand All @@ -33,7 +33,7 @@ parameters:
args:
type: string
default: ""
description: Arguments to pass to install command for pipenv and poetry. Override '-r requirements.txt' for pip.
description: Arguments to pass to install command for pipenv, poetry or uv. Override '-r requirements.txt' for pip.
setup:
type: steps
description: Provide any optional steps you would like to run prior to install the python project.
Expand Down Expand Up @@ -144,6 +144,7 @@ steps:
or:
- equal: [poetry, << parameters.pkg-manager >>]
- equal: [pipenv, << parameters.pkg-manager >>]
- equal: [uv, << parameters.pkg-manager >>]
steps:
- run:
name: Run tests with <<parameters.pkg-manager>> run
Expand Down Expand Up @@ -176,6 +177,7 @@ steps:
or:
- equal: [poetry, << parameters.pkg-manager >>]
- equal: [pipenv, << parameters.pkg-manager >>]
- equal: [uv, << parameters.pkg-manager >>]
steps:
- run:
name: Run tests with <<parameters.pkg-manager>> run
Expand Down
9 changes: 7 additions & 2 deletions src/scripts/auto-install-command.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ source "$AUTO_DETECT_ENV_SCRIPT"
case ${DETECT_PKG_MNGR:-${PARAM_PKG_MNGR}} in
pip)
PYTHON_INSTALL_ARGS="-r ${PARAM_DEPENDENCY_FILE:-requirements.txt}"
eval "${PYTHON_ENV_TOOL:-pip} install ${PYTHON_INSTALL_ARGS} ${PARAM_ADDITIONAL_ARGS}"
;;
pip-dist)
PYTHON_INSTALL_ARGS="-e ${PARAM_PATH_ARGS}"
eval "${PYTHON_ENV_TOOL:-pip} install ${PYTHON_INSTALL_ARGS} ${PARAM_ADDITIONAL_ARGS}"
;;
poetry)
PYTHON_INSTALL_ARGS="--no-ansi"
eval "poetry install ${PYTHON_INSTALL_ARGS} ${PARAM_ADDITIONAL_ARGS}"
;;
uv)
PYTHON_INSTALL_ARGS=""
eval "uv sync ${PYTHON_INSTALL_ARGS} ${PARAM_ADDITIONAL_ARGS}"
;;
esac

eval "${PYTHON_ENV_TOOL:-pip} install ${PYTHON_INSTALL_ARGS} ${PARAM_ADDITIONAL_ARGS}"
3 changes: 3 additions & 0 deletions src/scripts/cache-link-lockfile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ if [ ! -f "${LOCKFILE_PATH}" ]; then
poetry)
LOCK_FILE="poetry.lock"
;;
uv)
LOCK_FILE="uv.lock"
;;
esac

if [ -z "${LOCK_FILE}" ]; then
Expand Down
5 changes: 5 additions & 0 deletions src/scripts/cache-save.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ case ${DETECT_PKG_MNGR:-${PARAM_PKG_MNGR}} in
VENV_PATHS='[ "/home/circleci/.cache/pypoetry/virtualenvs" ]'
CACHE_PATHS='[ "/home/circleci/.cache/pip" ]'
;;
uv)
LOCK_FILE="uv.lock"
VENV_PATHS="[ \"${CIRCLE_WORKING_DIRECTORY}/.venv\" ]"
CACHE_PATHS='[ "/home/circleci/.cache/uv" ]'
;;
esac

if [ -n "${PARAM_VENV_PATH}" ]; then
Expand Down
3 changes: 3 additions & 0 deletions src/scripts/detect-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ if [ "${PARAM_PKG_MNGR}" = "auto" ]; then
elif [ -f "Pipfile" ]; then
export DETECT_PKG_MNGR="pipenv"
export PYTHON_ENV_TOOL="pipenv"
elif [ -f "uv.lock" ]; then
export DETECT_PKG_MNGR="uv"
export PYTHON_ENV_TOOL="uv"
elif [ -f "pyproject.toml" ]; then
export DETECT_PKG_MNGR="poetry"
export PYTHON_ENV_TOOL="poetry"
Expand Down
13 changes: 11 additions & 2 deletions src/scripts/ensure-test-tool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ case ${DETECT_PKG_MNGR:-${PARAM_PKG_MNGR}} in
REQUIREMENTS_PATH="pyproject.toml"
PYTHON_ENV_TOOL="poetry"
;;
uv)
REQUIREMENTS_PATH="uv.lock"
PYTHON_ENV_TOOL="uv"
;;
esac

if [ -f ${REQUIREMENTS_PATH} ]; then
Expand All @@ -39,8 +43,13 @@ if [ "${PARAM_TEST_TOOL}" != "unittest" ]; then
# If the test package is not detected, install using PYTHON_INSTALL_TOOL
if [ -z "$DETECT_TEST_TOOL" ]; then
echo "INFO: Test package ${PARAM_TEST_TOOL} was not found. Installing..."
eval "${PYTHON_ENV_TOOL:-pip} install ${PYTHON_INSTALL_ARGS} ${PARAM_TEST_TOOL}"
INSTALL_RESULT=$?
if [ "$PYTHON_ENV_TOOL" = "uv" ]; then
eval "uv add ${PYTHON_INSTALL_ARGS} ${PARAM_TEST_TOOL}"
INSTALL_RESULT=$?
else
eval "${PYTHON_ENV_TOOL:-pip} install ${PYTHON_INSTALL_ARGS} ${PARAM_TEST_TOOL}"
INSTALL_RESULT=$?
fi
else
echo "INFO: Detected test package: $DETECT_TEST_TOOL"
fi
Expand Down
3 changes: 3 additions & 0 deletions src/scripts/export-detect-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ echo 'if [ "${PARAM_PKG_MNGR}" = "auto" ]; then
elif [ -f "Pipfile" ]; then
export DETECT_PKG_MNGR="pipenv"
export PYTHON_ENV_TOOL="pipenv"
elif [ -f "uv.lock" ]; then
export DETECT_PKG_MNGR="uv"
export PYTHON_ENV_TOOL="uv"
elif [ -f "pyproject.toml" ]; then
export DETECT_PKG_MNGR="poetry"
export PYTHON_ENV_TOOL="poetry"
Expand Down