Skip to content
Merged
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
78 changes: 33 additions & 45 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,22 @@ jobs:

strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "pypy-3.10"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.10"]
fail-fast: false

steps:
- uses: "actions/checkout@v4"
with:
persist-credentials: false

- uses: "pdm-project/setup-pdm@v4"
with:
python-version: "${{ matrix.python-version }}"
allow-python-prereleases: true
cache: true
version: "2.21.0"
- uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3.0.0
- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0

- name: "Run Tox"
- name: "Run Tests"
env:
FAST: ${{ startsWith(matrix.python-version, 'pypy') && '1' || '' }}
run: |
python -Im pip install --upgrade tox tox-gh-actions

python -Im tox
just --set python ${{ startsWith(matrix.python-version, 'pypy') && matrix.python-version || format('python{0}', matrix.python-version) }} cov

- name: Upload coverage data
uses: actions/upload-artifact@v4
Expand All @@ -55,33 +51,28 @@ jobs:
with:
persist-credentials: false

- uses: "actions/setup-python@v5"
with:
cache: "pip"
python-version: "3.12"

- run: "python -Im pip install --upgrade coverage[toml]"

- name: Download coverage data
uses: actions/download-artifact@v4
with:
pattern: coverage-data-*
merge-multiple: true

- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0

- name: "Combine coverage"
run: |
python -Im coverage combine
python -Im coverage html
python -Im coverage json
uv run --group test coverage combine
uv run --group test coverage html
uv run --group test coverage json

# Report and write to summary.
python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
uv run --group test coverage report --format=markdown >> $GITHUB_STEP_SUMMARY

export TOTAL=$(python -c "import json;print(json.load(open('coverage.json'))['totals']['percent_covered_display'])")
export TOTAL=$(uv run python -c "import json;print(json.load(open('coverage.json'))['totals']['percent_covered_display'])")
echo "total=$TOTAL" >> $GITHUB_ENV

# Report again and fail if under the threshold.
python -Im coverage report --fail-under=100
uv run --group test coverage report --fail-under=100

- name: "Upload HTML report."
uses: "actions/upload-artifact@v4"
Expand All @@ -90,19 +81,20 @@ jobs:
path: "htmlcov"
if: always()

- name: "Make badge"
if: github.ref == 'refs/heads/main'
uses: "schneegans/[email protected]"
lint:
name: "Run linters"
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v4"
with:
# GIST_TOKEN is a GitHub personal access token with scope "gist".
auth: ${{ secrets.GIST_TOKEN }}
gistID: 22405310d6a663164d894a2beab4d44d
filename: covbadge.json
label: Coverage
message: ${{ env.total }}%
minColorRange: 50
maxColorRange: 90
valColorRange: ${{ env.total }}
persist-credentials: false

- uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3.0.0
- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0

- name: "Run linters"
run: |
just lint

package:
name: "Build & verify package"
Expand All @@ -112,18 +104,14 @@ jobs:
- uses: "actions/checkout@v4"
with:
persist-credentials: false
- uses: "pdm-project/setup-pdm@v4"
with:
python-version: "3.12"
version: "2.21.0"

- name: "Install check-wheel-content and twine"
run: "python -m pip install twine check-wheel-contents"
- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817

- name: "Build package"
run: "pdm build"
run: "uvx pdm build"
- name: "List result"
run: "ls -l dist"
- name: "Check wheel contents"
run: "check-wheel-contents --toplevel cattr,cattrs dist/*.whl"
run: "uvx check-wheel-contents --toplevel cattr,cattrs dist/*.whl"
- name: "Check long_description"
run: "python -m twine check dist/*"
run: "uvx twine check dist/*"
25 changes: 16 additions & 9 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ sphinx:
configuration: docs/conf.py

build:
os: ubuntu-20.04
os: ubuntu-lts-latest
tools:
# Keep version in sync with tox.ini (docs and gh-actions).
python: "3.11"
python: "3.13"
jobs:
# Need the tags to calculate the version
post_checkout:
- git fetch --tags
post_create_environment:
- "curl -sSL https://github.com/raw/pdm-project/pdm/main/install-pdm.py | python3 -"
create_environment:
- asdf plugin add uv
- asdf plugin add just
- asdf install uv latest
- asdf global uv latest
- asdf install just latest
- asdf global just latest
install:
- UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --group docs --all-extras --link-mode=copy
post_install:
- "VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH ~/.local/bin/pdm sync -dG :all,docs"
# Need the tags to calculate the version
- git fetch --tags
build:
html:
- UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH just docs $READTHEDOCS_OUTPUT
27 changes: 17 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,45 @@ Ready to contribute? Here's how to set up _cattrs_ for local development.
$ git clone [email protected]:your_name_here/cattrs.git
```

3. Install your local copy into a virtualenv. Assuming you have [PDM](https://pdm.fming.dev/latest/) installed, this is how you set up your fork for local development::
3. Install your local copy into a virtualenv. Assuming you have [uv](https://docs.astral.sh/uv/) installed, this is how you set up your fork for local development::

```shell
$ cd cattrs/
$ pdm install -d -G :all
$ uv sync --all-groups --all-extras
```

4. Create a branch for local development::

```shell
$ git checkout -b name-of-your-bugfix-or-feature
$ git switch -c name-of-your-bugfix-or-feature
```

Now you can make your changes locally.

5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox::
5. When you're done making changes, check that your changes pass lints and the tests, including testing other Python versions::

```shell
$ make lint
$ make test
$ tox
$ just lint
$ just test
$ just --set python python3.9 test # Test on other versions
```

6. Commit your changes and push your branch to GitHub::
6. Write any necessary documentation, including updating the changelog (HISTORY.md). The docs can be built like so:

```shell
$ just docs
$ just htmllive # Build the docs, serve then and autoreload on changes
```

7. Commit your changes and push your branch to GitHub::

```shell
$ git add .
$ git commit -m "Your detailed description of your changes."
$ git push origin name-of-your-bugfix-or-feature
```

7. Submit a pull request through the GitHub website.
8. Submit a pull request through the GitHub website.

## Pull Request Guidelines

Expand All @@ -106,5 +113,5 @@ Before you submit a pull request, check that it meets these guidelines:
To run a subset of tests:

```shell
$ pdm run pytest tests.test_unstructure
$ just test tests/test_unstructure.py
```
3 changes: 3 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Our backwards-compatibility policy can be found [here](https://github.com/python
- The default disambiguation hook factory is now only enabled for converters with `unstructure_strat=AS_DICT` (the default).
Since the strategy doesn't support tuples, it is skipped for `unstructure_strat=AS_TUPLE` converters.
([#673](https://github.com/python-attrs/cattrs/pull/673))
- Switch to [`uv`](https://docs.astral.sh/uv/) and [`just`](https://just.systems/man/en/) in lieu of PDM, tox and Make.
See [the Contributing section](https://catt.rs/en/v25.2.0/contributing.html#get-started) for new workflow instructions.
([#671](https://github.com/python-attrs/cattrs/pull/671))

## 25.1.1 (2025-06-04)

Expand Down
26 changes: 26 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
python := ""

lint:
uv run -p python3.13 --group lint ruff check src/ tests bench
uv run -p python3.13 --group lint black --check src tests docs/conf.py

test *args="-x --ff -n auto tests":
uv run {{ if python != '' { '-p ' + python } else { '' } }} --all-extras --group test pytest {{args}}

cov *args="-x --ff -n auto tests":
@uv run {{ if python != '' { '-p ' + python } else { '' } }} python -c 'import pathlib, site; pathlib.Path(f"{site.getsitepackages()[0]}/cov.pth").write_text("import coverage; coverage.process_startup()")'
COVERAGE_PROCESS_START={{justfile_directory()}}/pyproject.toml uv run {{ if python != '' { '-p ' + python } else { '' } }} --all-extras --group test coverage run -m pytest {{args}}

bench-cmp:
uv run pytest bench --benchmark-compare

bench:
uv run pytest bench --benchmark-save base

docs output_dir="_build": ## generate Sphinx HTML documentation, including API docs
make -C docs -e BUILDDIR={{output_dir}} clean
make -C docs -e BUILDDIR={{output_dir}} doctest
make -C docs -e BUILDDIR={{output_dir}} html

htmllive: docs ## compile the docs watching for changes
make -C docs htmllive
80 changes: 0 additions & 80 deletions Makefile

This file was deleted.

8 changes: 4 additions & 4 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = pdm run sphinx-build
SPHINXBUILD = uv run --all-extras --group docs sphinx-build
PAPER =
BUILDDIR = _build

Expand Down Expand Up @@ -173,15 +173,15 @@ pseudoxml:

.PHONY: apidoc
apidoc:
pdm run sphinx-apidoc -o . ../src/cattrs/ '../**/converters.py' -f -M
uv run sphinx-apidoc -o . ../src/cattrs/ '../**/converters.py' -f -M

## htmlview to open the index page built by the html target in your browser
.PHONY: htmlview
htmlview: html
pdm run python -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('$(BUILDDIR)/html/index.html'))"
uv run python -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('$(BUILDDIR)/html/index.html'))"

## htmllive to rebuild and reload HTML files in your browser
.PHONY: htmllive
htmllive: SPHINXBUILD = pdm run sphinx-autobuild
htmllive: SPHINXBUILD = uv run sphinx-autobuild
htmllive: SPHINXERRORHANDLING = --re-ignore="/\.idea/|/venv/|/pep-0000.rst|/topic/"
htmllive: html
Loading