Skip to content

Commit 31c06c3

Browse files
authored
build: use uv for setup and ci (#101)
* wip * remove no sync * ci: update Python setup action and pre-commit hook versions; fix typo in ColorStops class * fix rtd * ignore w004 * upd
1 parent f36acdf commit 31c06c3

File tree

8 files changed

+93
-99
lines changed

8 files changed

+93
-99
lines changed

.github/workflows/ci.yml

Lines changed: 54 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ jobs:
2121
runs-on: ubuntu-latest
2222
steps:
2323
- uses: actions/checkout@v4
24-
- uses: actions/setup-python@v5
25-
with:
26-
python-version: "3.x"
27-
- run: pip install check-manifest && check-manifest
24+
- run: pipx run check-manifest
2825

2926
test:
3027
name: ${{ matrix.platform }} (${{ matrix.python-version }})
3128
runs-on: ${{ matrix.platform }}
29+
env:
30+
UV_PRERELEASE: ${{ github.event_name == 'schedule' && 'allow' || 'if-necessary-or-explicit' }}
3231
strategy:
3332
fail-fast: false
3433
matrix:
@@ -38,88 +37,81 @@ jobs:
3837
steps:
3938
- uses: actions/checkout@v4
4039

41-
- name: Set up Python ${{ matrix.python-version }}
42-
uses: actions/setup-python@v5
40+
- uses: astral-sh/setup-uv@v6
4341
with:
4442
python-version: ${{ matrix.python-version }}
45-
cache-dependency-path: "pyproject.toml"
46-
cache: "pip"
47-
48-
- uses: tlambert03/setup-qt-libs@v1
49-
50-
- name: Install dependencies
43+
enable-cache: true
44+
cache-dependency-glob: "**/pyproject.toml"
5145

52-
run: |
53-
python -m pip install -U pip
54-
python -m pip install -e .[test_min]
46+
- name: Run min test
47+
run: uv run --no-dev --group test_min pytest -v
5548

56-
- name: Run test
57-
run: pytest -v
49+
- uses: pyvista/setup-headless-display-action@v3
50+
with:
51+
qt: true
5852

59-
- name: Install third-party dependencies
60-
if: runner.os != 'Windows'
61-
run: |
62-
python -m pip install -e .[test_thirdparty] ${{ github.event_name == 'schedule' && '--pre' || '' }}
63-
python -m pip install PyQt6==6.8.1
53+
- name: Run full test
54+
run: uv run --no-dev --group test_thirdparty coverage run -p -m pytest -v
6455

65-
- name: Run test
66-
if: runner.os != 'Windows'
67-
uses: aganders3/[email protected]
56+
- name: Upload coverage
57+
uses: actions/upload-artifact@v4
6858
with:
69-
run: pytest -v --cov=cmap --cov-report=xml --cov-report=term-missing
59+
name: covreport-${{ matrix.platform }}-py${{ matrix.python-version }}
60+
path: ./.coverage*
61+
include-hidden-files: true
7062

71-
- name: Coverage
72-
if: runner.os != 'Windows'
73-
uses: codecov/codecov-action@v5
74-
with:
75-
token: ${{ secrets.CODECOV_TOKEN }}
63+
upload_coverage:
64+
if: always()
65+
needs: [test]
66+
uses: pyapp-kit/workflows/.github/workflows/upload-coverage.yml@v2
67+
secrets:
68+
codecov_token: ${{ secrets.CODECOV_TOKEN }}
7669

7770
test-pyinstaller-build:
7871
name: Test pyinstaller
7972
runs-on: ubuntu-latest
8073
steps:
81-
- uses: actions/checkout@v4
82-
- name: Set up Python
83-
uses: actions/setup-python@v5
84-
with:
85-
python-version: 3.12
86-
- name: Install package and dev dependencies
87-
run: |
88-
python -m pip install --upgrade pip
89-
pip install .
90-
pip install pytest pyinstaller
91-
- name: Unit tests
92-
run: pytest -v --pyargs cmap.__pyinstaller
93-
94-
deploy:
95-
name: Deploy
74+
- uses: actions/checkout@v4
75+
- name: Set up Python
76+
uses: actions/setup-python@v5
77+
with:
78+
python-version: 3.12
79+
- name: Install package and dev dependencies
80+
run: |
81+
python -m pip install --upgrade pip
82+
pip install .
83+
pip install pytest pyinstaller
84+
- name: Unit tests
85+
run: pytest -v --pyargs cmap.__pyinstaller
86+
87+
build-and-inspect-package:
88+
name: Build & inspect package.
9689
needs: test
97-
if: success() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'schedule'
9890
runs-on: ubuntu-latest
91+
steps:
92+
- uses: actions/checkout@v4
93+
with:
94+
fetch-depth: 0
95+
- uses: hynek/build-and-inspect-python-package@v2
9996

97+
upload-to-pypi:
98+
name: Upload package to PyPI
99+
needs: build-and-inspect-package
100+
if: success() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'schedule'
101+
runs-on: ubuntu-latest
100102
permissions:
101103
id-token: write
102104
contents: write
103105

104106
steps:
105-
- uses: actions/checkout@v4
107+
- name: Download built artifact to dist/
108+
uses: actions/download-artifact@v4
106109
with:
107-
fetch-depth: 0
108-
109-
- name: Set up Python
110-
uses: actions/setup-python@v5
111-
with:
112-
python-version: "3.x"
113-
114-
- name: 👷 Build
115-
run: |
116-
python -m pip install build
117-
python -m build
118-
110+
name: Packages
111+
path: dist
119112
- name: 🚢 Publish to PyPI
120113
uses: pypa/gh-action-pypi-publish@release/v1
121-
122114
- uses: softprops/action-gh-release@v2
123115
with:
124116
generate_release_notes: true
125-
files: "./dist/*"
117+
files: './dist/*'

.github/workflows/docs.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v4
13-
- uses: actions/setup-python@v5
13+
- uses: astral-sh/setup-uv@v6
1414
with:
15-
python-version: '3.12'
16-
- run: |
17-
pip install -e .[docs]
18-
- run: mkdocs gh-deploy --strict --force
15+
python-version: 3.12
16+
- run: uv run --group docs mkdocs gh-deploy --strict --force

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,4 @@ src/cmap/_version.py
111111
docs/assets/_data/
112112

113113
.ruff_cache/
114+
uv.lock

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repos:
1515
args: [--autofix]
1616

1717
- repo: https://github.com/astral-sh/ruff-pre-commit
18-
rev: v0.11.4
18+
rev: v0.11.10
1919
hooks:
2020
- id: ruff
2121
args: [--fix, --unsafe-fixes]

.readthedocs.yaml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@
33
version: 2
44

55
build:
6-
os: ubuntu-20.04
6+
os: ubuntu-24.04
77
tools:
8-
python: "3.10"
8+
python: "3.12"
9+
jobs:
10+
post_install:
11+
- pip install uv
12+
- UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --all-extras --group docs --link-mode=copy
913

1014
mkdocs:
1115
configuration: mkdocs.yml
1216
fail_on_warning: true
13-
14-
python:
15-
install:
16-
- method: pip
17-
path: .
18-
extra_requirements:
19-
- docs

pyproject.toml

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,31 +25,17 @@ classifiers = [
2525
dynamic = ["version"]
2626
dependencies = ["numpy"]
2727

28-
# extras
29-
# https://peps.python.org/pep-0621/#dependencies-optional-dependencies
30-
[project.optional-dependencies]
31-
docs = [
32-
'colorcet',
33-
'colorspacious',
34-
'imageio',
35-
'mkdocs-gen-files',
36-
'mkdocs-literate-nav',
37-
'mkdocs-api-autonav',
38-
'mkdocs-material',
39-
'mkdocs-minify-plugin',
40-
'mkdocs',
41-
'mkdocstrings-python',
42-
'natsort',
43-
]
28+
[dependency-groups]
4429
test_min = ["pytest>=6.0"]
45-
test = ["cmap[test_min]", "pytest-cov"]
30+
test = [{ include-group = "test_min" }, "pytest-cov"]
4631
test_thirdparty = [
47-
"cmap[test]",
32+
{ include-group = "test" },
4833
"bokeh",
4934
"colorspacious",
5035
"colour",
5136
"matplotlib",
5237
"napari>=0.5.0",
38+
"PyQt6==6.8.1",
5339
"numba",
5440
"numba<0.61; python_version<'3.12'",
5541
"plotly",
@@ -64,16 +50,32 @@ test_thirdparty = [
6450
"vispy>=0.14",
6551
]
6652
dev = [
67-
"cmap[test_thirdparty]",
53+
{ include-group = "test_thirdparty" },
6854
"ipython",
6955
"mypy",
7056
"pdbpp",
71-
"pre-commit",
57+
"pre-commit-uv",
7258
"pytest",
7359
"rich",
7460
"ruff",
7561
"pyqt6",
7662
]
63+
docs = [
64+
'colorcet',
65+
'colorspacious',
66+
'imageio',
67+
'mkdocs-gen-files',
68+
'mkdocs-literate-nav',
69+
'mkdocs-api-autonav',
70+
'mkdocs-material',
71+
'mkdocs-minify-plugin',
72+
'mkdocs',
73+
'mkdocstrings-python',
74+
'natsort',
75+
]
76+
77+
[tool.uv.sources]
78+
cmap = { workspace = true }
7779

7880
[project.entry-points."pyinstaller40"]
7981
hook-dirs = "cmap.__pyinstaller:get_hook_dirs"
@@ -193,3 +195,6 @@ ignore = [
193195
"mkdocs.yml",
194196
".readthedocs.yaml",
195197
]
198+
199+
[tool.check-wheel-contents]
200+
ignore = ["W004"]

src/cmap/_colormap.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ def __getitem__(
998998
def __reversed__(self) -> Iterator[ColorStop]:
999999
# this for the reversed() builtin ... when iterating single
10001000
# ColorStops. But see the reversed() method below for when
1001-
# you want to create a new ColorStops object that is "permantently"
1001+
# you want to create a new ColorStops object that is "permanently"
10021002
# reversed.
10031003
for pos, *rgba in self._stops[::-1]:
10041004
# reverse the colors, but not the positions
@@ -1399,7 +1399,7 @@ def _mpl_segmentdata_to_stops(
13991399
alpha = np.ones_like(all_positions)
14001400

14011401
rgba = np.stack([*rgb, alpha], axis=1)
1402-
return [(a, tuple(b)) for a, b in zip(all_positions, rgba.tolist())] # type: ignore
1402+
return [(a, tuple(b)) for a, b in zip(all_positions, rgba.tolist())]
14031403

14041404

14051405
def _make_identifier(name: str) -> str:

tests/test_third_party.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def test_gee() -> None:
165165
assert alt[-1] == "0000FF"
166166

167167

168+
@pytest.mark.xfail(reason="viscm is unmaintained")
168169
def test_viscm(tmp_path: Path) -> None:
169170
pytest.importorskip("viscm")
170171
# NOT using importorskip here because there IS an error import viscm

0 commit comments

Comments
 (0)