Skip to content

Commit

Permalink
ci: switch to pyproject.toml and update other CI files
Browse files Browse the repository at this point in the history
Also use uv for publishing
  • Loading branch information
karlicoss committed Feb 1, 2025
1 parent 4910c86 commit d4246f4
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 142 deletions.
60 changes: 60 additions & 0 deletions .ci/release-uv
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
'''
Deploys Python package onto [[https://pypi.org][PyPi]] or [[https://test.pypi.org][test PyPi]].
- running manually
You'll need =UV_PUBLISH_TOKEN= env variable
- running on Github Actions
Instead of env variable, relies on configuring github as Trusted publisher (https://docs.pypi.org/trusted-publishers/) -- both for test and regular pypi
It's running as =pypi= job in [[file:.github/workflows/main.yml][Github Actions config]].
Packages are deployed on:
- every master commit, onto test pypi
- every new tag, onto production pypi
'''

UV_PUBLISH_TOKEN = 'UV_PUBLISH_TOKEN'

import argparse
import os
import shutil
from pathlib import Path
from subprocess import check_call

is_ci = os.environ.get('CI') is not None

def main() -> None:
p = argparse.ArgumentParser()
p.add_argument('--use-test-pypi', action='store_true')
args = p.parse_args()

publish_url = ['--publish-url', 'https://test.pypi.org/legacy/'] if args.use_test_pypi else []

root = Path(__file__).absolute().parent.parent
os.chdir(root) # just in case

if is_ci:
# see https://github.com/actions/checkout/issues/217
check_call('git fetch --prune --unshallow'.split())

# TODO ok, for now uv won't remove dist dir if it already exists
# https://github.com/astral-sh/uv/issues/10293
dist = root / 'dist'
if dist.exists():
shutil.rmtree(dist)

# todo what is --force-pep517?
check_call(['uv', 'build'])

if not is_ci:
# CI relies on trusted publishers so doesn't need env variable
assert UV_PUBLISH_TOKEN in os.environ, f'no {UV_PUBLISH_TOKEN} passed'

check_call(['uv', 'publish', *publish_url])


if __name__ == '__main__':
main()
15 changes: 2 additions & 13 deletions .ci/run
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,5 @@ if [ -n "${CI-}" ]; then
esac
fi


PY_BIN="python3"
# some systems might have python pointing to python3
if ! command -v python3 &> /dev/null; then
PY_BIN="python"
fi


# TODO hmm for some reason installing uv with pip and then running
# "$PY_BIN" -m uv tool fails with missing setuptools error??
# just uvx directly works, but it's not present in PATH...
"$PY_BIN" -m pip install --user pipx
"$PY_BIN" -m pipx run uv tool run --with=tox-uv tox $tox_cmd "$@"
# NOTE: expects uv installed
uv tool run --with tox-uv tox $tox_cmd "$@"
22 changes: 14 additions & 8 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
platform: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
exclude: [
# windows runners are pretty scarce, so let's only run lowest and highest python version
Expand All @@ -49,6 +49,10 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- uses: astral-sh/setup-uv@v5
with:
enable-cache: false # we don't have lock files, so can't use them as cache key

- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -77,7 +81,9 @@ jobs:
pypi:
runs-on: ubuntu-latest
needs: [build] # add all other jobs here

permissions:
# necessary for Trusted Publishing
id-token: write
steps:
# ugh https://github.com/actions/toolkit/blob/main/docs/commands.md#path-manipulation
- run: echo "$HOME/.local/bin" >> $GITHUB_PATH
Expand All @@ -86,21 +92,21 @@ jobs:
with:
python-version: '3.10'

- uses: astral-sh/setup-uv@v5
with:
enable-cache: false # we don't have lock files, so can't use them as cache key

- uses: actions/checkout@v4
with:
submodules: recursive

- name: 'release to test pypi'
# always deploy merged master to test pypi
if: github.event_name != 'pull_request' && github.event.ref == 'refs/heads/master'
env:
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD_TEST }}
run: pip3 install --user --upgrade build twine && .ci/release --test
run: .ci/release-uv --use-test-pypi

- name: 'release to pypi'
# always deploy tags to release pypi
# NOTE: release tags are guarded by on: push: tags on the top
if: github.event_name != 'pull_request' && startsWith(github.event.ref, 'refs/tags')
env:
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
run: pip3 install --user --upgrade build twine && .ci/release
run: .ci/release-uv
6 changes: 3 additions & 3 deletions doc/SETUP.org
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ This is convenient if you're planning to add new modules or change the existing

It's *extremely* convenient for developing and debugging.

** option 3: use without installing
This is less convenient, but gives you more control.
** option 3: use without installing (deprecated)
NOTE: this is deprecated -- it's almost always better to simply use an editable install.

1. Clone the repository: =git clone [email protected]:karlicoss/HPI.git /path/to/hpi=
2. Go into the project directory: =cd /path/to/hpi=
3. Install the dependencies: ~python3 setup.py --dependencies-only~
3. Install the necessary dependencies (see =pyproject.toml=)
4. Use =with_my= script to get access to ~my.~ modules.

For example:
Expand Down
89 changes: 89 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# see https://github.com/karlicoss/pymplate for up-to-date reference
[project]
dynamic = ["version"] # version is managed by setuptools_scm
# NOTE: 'my' is taken for PyPi already, and makes discovering the project impossible
# , so we're using HPI
name = "HPI"
dependencies = [
"pytz" , # even though it's not needed by the core, it's so common anyway...
"typing-extensions" , # one of the most common pypi packages, ok to depend for core
"appdirs" , # very common, and makes it portable
"more-itertools" , # it's just too useful and very common anyway
"decorator" , # less pain in writing correct decorators. very mature and stable, so worth keeping in core
"click>=8.1" , # for the CLI, printing colors, decorator-based - may allow extensions to CLI
"kompress>=0.2.20240918" , # for transparent access to compressed files via pathlib.Path

]
requires-python = ">=3.9"

## these need to be set if you're planning to upload to pypi
description = "A Python interface to my life"
license = {file = "LICENSE"}
authors = [
{name = "Dima Gerasimov (@karlicoss)", email = "[email protected]"},
]
maintainers = [
{name = "Dima Gerasimov (@karlicoss)", email = "[email protected]"},
]
# keywords = []
# # see: http://pypi.python.org/pypi?%3Aaction=list_classifiers
# classifiers = [
# ]


[project.urls]
Homepage = "https://github.com/karlicoss/HPI"
##


[project.optional-dependencies]
optional = [
# todo document these?
"orjson", # for my.core.serialize
"pyfzf_iter", # for my.core.denylist
"cachew>=0.15.20231019",
"mypy", # used for config checks
"colorlog", # for colored logs
"enlighten", # for CLI progress bars
]

[dependency-groups]
testing = [
"pytest",
"ruff",
"mypy",
"lxml", # for mypy coverage

# used in some tests.. although shouldn't rely on it
"pandas",

"orjson", # for my.core.serialize and denylist
"simplejson", # for my.core.serialize

##
# ideally we'd use --instal-types in mypy
# , but looks like it doesn't respect uv venv if it's running in it :(
"types-pytz" , # for my.core
"types-decorator" , # for my.core.compat
"pandas-stubs" , # for my.core.pandas
"types-dateparser", # for my.core.query_range
"types-simplejson", # for my.core.serialize
##
]

[project.scripts]
hpi = "my.core.__main__:main"


[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
version_scheme = "python-simplified-semver"
local_scheme = "dirty-tag"

# workaround for error during uv publishing
# see https://github.com/astral-sh/uv/issues/9513#issuecomment-2519527822
[tool.setuptools]
license-files = []
7 changes: 5 additions & 2 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
target-version = "py39" # NOTE: inferred from pyproject.toml if present
# NOTE: version is inferred from pyproject.toml if present
# however, if ruff.toml is separate, pyproject isn't even parsed..
# see https://github.com/astral-sh/ruff/issues/10299
target-version = "py39"

lint.extend-select = [
"F", # flakes rules -- default, but extend just in case
Expand Down Expand Up @@ -30,6 +33,7 @@ lint.extend-select = [
"PTH", # pathlib migration
"ARG", # unused argument checks
# "A", # builtin shadowing -- TODO handle later
"G", # logging stuff
# "EM", # TODO hmm could be helpful to prevent duplicate err msg in traceback.. but kinda annoying

# "ALL", # uncomment this to check for new rules!
Expand Down Expand Up @@ -113,7 +117,6 @@ lint.ignore = [
"PLW0603", # global variable update.. we usually know why we are doing this
"PLW2901", # for loop variable overwritten, usually this is intentional

"PT004", # deprecated rule, will be removed later
"PT011", # pytest raises should is too broad
"PT012", # pytest raises should contain a single statement

Expand Down
106 changes: 0 additions & 106 deletions setup.py

This file was deleted.

Loading

0 comments on commit d4246f4

Please sign in to comment.