Skip to content

Commit 85e6c08

Browse files
authored
Merge branch 'main' into bugfix/issue355-nan-in-categorical-coloring
2 parents 82d6d49 + 0d4239b commit 85e6c08

File tree

243 files changed

+3331
-896
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

243 files changed

+3331
-896
lines changed

.github/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ changelog:
44
- release-ignore
55
authors:
66
- pre-commit-ci
7+
- pre-commit-ci[bot]
78
categories:
89
- title: Added
910
labels:

.github/workflows/test.yaml

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,66 +3,69 @@ name: Test
33
on:
44
push:
55
branches: [main]
6-
tags:
7-
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
6+
tags: ["v*"] # Push events to matching v*, i.e. v1.0, v20.15.10
87
pull_request:
9-
branches: "*"
8+
branches: ["*"]
109

1110
jobs:
1211
test:
13-
runs-on: ${{ matrix.os }}
14-
defaults:
15-
run:
16-
shell: bash -e {0} # -e to fail on error
17-
12+
runs-on: ubuntu-latest
1813
strategy:
1914
fail-fast: false
2015
matrix:
21-
python: ["3.10", "3.12"]
22-
os: [ubuntu-latest]
16+
env: ["dev-py311", "dev-py313"]
2317

18+
# Configure pytest-xdist
2419
env:
25-
OS: ${{ matrix.os }}
26-
PYTHON: ${{ matrix.python }}
20+
OMP_NUM_THREADS: "1"
21+
OPENBLAS_NUM_THREADS: "1"
22+
MKL_NUM_THREADS: "1"
23+
NUMEXPR_MAX_THREADS: "1"
24+
MPLBACKEND: "agg"
25+
DISPLAY: ":42"
26+
PYTEST_ADDOPTS: "-n auto --dist=load --durations=10"
2727

2828
steps:
2929
- uses: actions/checkout@v4
30-
- name: Set up Python ${{ matrix.python }}
31-
uses: actions/setup-python@v5
32-
with:
33-
python-version: ${{ matrix.python }}
3430

35-
- name: Get pip cache dir
36-
id: pip-cache-dir
37-
run: |
38-
echo "::set-output name=dir::$(pip cache dir)"
39-
- name: Restore pip cache
40-
uses: actions/cache@v3
31+
# Cache rattler's shared package cache (speeds up downloads)
32+
- name: Restore rattler cache
33+
uses: actions/cache@v4
4134
with:
42-
path: ${{ steps.pip-cache-dir.outputs.dir }}
43-
key: pip-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('**/pyproject.toml') }}
35+
path: ~/.cache/rattler
36+
key: rattler-${{ runner.os }}-${{ matrix.env }}-${{ hashFiles('pyproject.toml') }}
4437
restore-keys: |
45-
pip-${{ runner.os }}-${{ env.pythonLocation }}-
46-
- name: Install test dependencies
47-
run: |
48-
python -m pip install --upgrade pip wheel
49-
pip install pytest-cov
50-
- name: Install dependencies
38+
rattler-${{ runner.os }}-${{ matrix.env }}-
39+
rattler-${{ runner.os }}-
40+
41+
# Install pixi and the requested environment
42+
- uses: prefix-dev/[email protected]
43+
with:
44+
environments: ${{ matrix.env }}
45+
# We're not comitting the pixi-lock file
46+
locked: false
47+
cache: false
48+
activate-environment: ${{ matrix.env }}
49+
50+
- name: Show versions
5151
run: |
52-
pip install --pre -e ".[dev,test,pre]"
53-
- name: Test
52+
python --version
53+
pixi --version
54+
55+
- name: Run tests
5456
env:
5557
MPLBACKEND: agg
56-
PLATFORM: ${{ matrix.os }}
57-
DISPLAY: :42
58+
DISPLAY: ":42"
5859
run: |
5960
pytest -v --cov --color=yes --cov-report=xml
61+
6062
- name: Archive figures generated during testing
6163
if: always()
6264
uses: actions/upload-artifact@v4
6365
with:
64-
name: visual_test_results_${{ matrix.os }}-python${{ matrix.python }}
66+
name: visual_test_results_${{ matrix.env }}
6567
path: /home/runner/work/spatialdata-plot/spatialdata-plot/tests/figures/*
68+
6669
- name: Upload coverage to Codecov
6770
uses: codecov/codecov-action@v4
6871
with:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ tests/figures/
4444
# other
4545
_version.py
4646
/temp/
47+
48+
# pixi
49+
pixi.lock

.mypy.ini

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[mypy]
22
python_version = 3.10
3-
plugins = numpy.typing.mypy_plugin
43

54
ignore_errors = False
65
warn_redundant_casts = True

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ ci:
99
skip: []
1010
repos:
1111
- repo: https://github.com/rbubley/mirrors-prettier
12-
rev: v3.5.3
12+
rev: v3.7.4
1313
hooks:
1414
- id: prettier
1515
- repo: https://github.com/astral-sh/ruff-pre-commit
16-
rev: v0.11.6
16+
rev: v0.14.8
1717
hooks:
1818
- id: ruff
1919
args: [--fix, --exit-non-zero-on-fix]
2020
- id: ruff-format
2121
- repo: https://github.com/pre-commit/mirrors-mypy
22-
rev: v1.15.0
22+
rev: v1.19.0
2323
hooks:
2424
- id: mypy
2525
additional_dependencies: [numpy, types-requests]

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
info = metadata("spatialdata-plot")
2222
project_name = info["Name"]
2323
author = info["Author"]
24-
copyright = f"{datetime.now():%Y}, {author}."
24+
copyright = f"{datetime.now():%Y}, {author}"
2525
version = info["Version"]
2626

2727
# repository_url = f"https://github.com/scverse/{project_name}"

pyproject.toml

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ authors = [
99
{name = "scverse"},
1010
]
1111
maintainers = [
12-
{name = "scverse", email = "[email protected]"},
12+
{name = "Tim Treis", email = "[email protected]"},
1313
]
1414
urls.Documentation = "https://spatialdata.scverse.org/projects/plot/en/latest/index.html"
1515
urls.Source = "https://github.com/scverse/spatialdata-plot.git"
1616
urls.Home-page = "https://github.com/scverse/spatialdata-plot.git"
17-
requires-python = ">=3.10"
17+
requires-python = ">=3.11"
1818
dynamic= [
19-
"version" # allow version to be set by git tags
19+
"version" # allow version to be set by git tags
2020
]
2121
license = {file = "LICENSE"}
2222
readme = "README.md"
@@ -30,7 +30,16 @@ dependencies = [
3030

3131
[project.optional-dependencies]
3232
dev = [
33-
"bump2version",
33+
"jupyterlab",
34+
"notebook",
35+
"ipykernel",
36+
"ipywidgets",
37+
"jupytext",
38+
"pytest",
39+
"pytest-cov",
40+
"pooch",
41+
"ruff",
42+
"pre-commit",
3443
]
3544
docs = [
3645
"sphinx>=4.5",
@@ -47,12 +56,9 @@ docs = [
4756
test = [
4857
"pytest",
4958
"pytest-cov",
59+
"pytest-xdist",
5060
"pooch", # for scipy.datasets module
5161
]
52-
# this will be used by readthedocs and will make pip also look for pre-releases, generally installing the latest available version
53-
pre = [
54-
"spatialdata>=0.1.0-pre0"
55-
]
5662

5763
[tool.coverage.run]
5864
source = ["spatialdata_plot"]
@@ -143,30 +149,45 @@ unfixable = ["B", "UP", "C4", "BLE", "T20", "RET"]
143149
"tests/*" = ["D", "PT", "B024"]
144150
"*/__init__.py" = ["F401", "D104", "D107", "E402"]
145151
"docs/*" = ["D","B","E","A"]
146-
# "src/spatialdata/transformations/transformations.py" = ["D101","D102", "D106", "B024", "T201", "RET504"]
147152
"tests/conftest.py"= ["E402", "RET504"]
148153
"src/spatialdata_plot/pl/utils.py"= ["PGH003"]
149154

150155
[tool.ruff.lint.pydocstyle]
151156
convention = "numpy"
152157

153-
[tool.bumpver]
154-
current_version = "0.0.2"
155-
version_pattern = "MAJOR.MINOR.PATCH"
156-
commit_message = "bump version {old_version} -> {new_version}"
157-
tag_message = "{new_version}"
158-
tag_scope = "default"
159-
pre_commit_hook = ""
160-
post_commit_hook = ""
161-
commit = true
162-
tag = true
163-
push = false
164-
165-
[tool.bumpver.file_patterns]
166-
"pyproject.toml" = [
167-
'current_version = "{version}"',
168-
]
169-
"README.md" = [
170-
"{version}",
171-
"{pep440_version}",
172-
]
158+
[tool.pixi.workspace]
159+
channels = ["conda-forge"]
160+
platforms = ["osx-arm64", "linux-64"]
161+
162+
[tool.pixi.dependencies]
163+
python = ">=3.11"
164+
165+
[tool.pixi.pypi-dependencies]
166+
spatialdata-plot = { path = ".", editable = true }
167+
168+
# for gh-actions
169+
[tool.pixi.feature.py311.dependencies]
170+
python = "3.11.*"
171+
172+
[tool.pixi.feature.py313.dependencies]
173+
python = "3.13.*"
174+
175+
[tool.pixi.environments]
176+
# 3.11 lane (for gh-actions)
177+
dev-py311 = { features = ["dev", "test", "py311"], solve-group = "py311" }
178+
docs-py311 = { features = ["docs", "py311"], solve-group = "py311" }
179+
180+
# 3.13 lane
181+
default = { features = ["py313"], solve-group = "py313" }
182+
dev-py313 = { features = ["dev", "test", "py313"], solve-group = "py313" }
183+
docs-py313 = { features = ["docs", "py313"], solve-group = "py313" }
184+
test-py313 = { features = ["test", "py313"], solve-group = "py313" }
185+
186+
[tool.pixi.tasks]
187+
lab = "jupyter lab"
188+
kernel-install = "python -m ipykernel install --user --name pixi-dev --display-name \"sdata-plot (dev)\""
189+
test = "pytest -v --color=yes --tb=short --durations=10"
190+
lint = "ruff check ."
191+
format = "ruff format ."
192+
pre-commit-install = "pre-commit install"
193+
pre-commit-run = "pre-commit run --all-files"

src/spatialdata_plot/_logging.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# from https://github.com/scverse/spatialdata/blob/main/src/spatialdata/_logging.py
22

33
import logging
4+
import re
5+
from collections.abc import Iterator
6+
from contextlib import contextmanager
7+
from typing import TYPE_CHECKING
8+
9+
if TYPE_CHECKING: # pragma: no cover
10+
from _pytest.logging import LogCaptureFixture
411

512

613
def _setup_logger() -> "logging.Logger":
@@ -21,3 +28,44 @@ def _setup_logger() -> "logging.Logger":
2128

2229

2330
logger = _setup_logger()
31+
32+
33+
@contextmanager
34+
def logger_warns(
35+
caplog: "LogCaptureFixture",
36+
logger: logging.Logger,
37+
match: str | None = None,
38+
level: int = logging.WARNING,
39+
) -> Iterator[None]:
40+
"""
41+
Context manager similar to pytest.warns, but for logging.Logger.
42+
43+
Usage:
44+
with logger_warns(caplog, logger, match="Found 1 NaN"):
45+
call_code_that_logs()
46+
"""
47+
# Store initial record count to only check new records
48+
initial_record_count = len(caplog.records)
49+
50+
# Add caplog's handler directly to the logger to capture logs even if propagate=False
51+
handler = caplog.handler
52+
logger.addHandler(handler)
53+
original_level = logger.level
54+
logger.setLevel(level)
55+
56+
# Use caplog.at_level to ensure proper capture setup
57+
with caplog.at_level(level, logger=logger.name):
58+
try:
59+
yield
60+
finally:
61+
logger.removeHandler(handler)
62+
logger.setLevel(original_level)
63+
64+
# Only check records that were added during this context
65+
records = [r for r in caplog.records[initial_record_count:] if r.levelno >= level]
66+
67+
if match is not None:
68+
pattern = re.compile(match)
69+
if not any(pattern.search(r.getMessage()) for r in records):
70+
msgs = [r.getMessage() for r in records]
71+
raise AssertionError(f"Did not find log matching {match!r} in records: {msgs!r}")

0 commit comments

Comments
 (0)