From 331a8fffb2592c8f1dac6544790c91a2d642d67e Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Tue, 1 Oct 2024 14:52:56 +0100 Subject: [PATCH] Update workflow, requirements, ruff (#41) * Update test/publish workflow * Update pre-commit, replace with ruff. * Rename * Update requirements.txt uv pip compile pyproject.toml -o requirements.txt --upgrade * Update dev requirements Manually. * Use requirements.txt in CI * No numpy 2.0, for now * Python 3.9 requirements.txt --- .github/workflows/ci.yml | 30 --------- .github/workflows/publish-to-pypi.yml | 88 +++++++++++++++++++-------- .pre-commit-config.yaml | 38 ++++-------- pyproject.toml | 15 ++--- requirements.txt | 33 ++++++++-- requirements_dev.txt | 9 +-- src/nxmx/__init__.py | 11 ++-- tests/conftest.py | 12 ++-- tests/test_nxmx.py | 24 ++++---- 9 files changed, 132 insertions(+), 128 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index d872330..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Python package - -on: [push] - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.9', '3.10', '3.11'] - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: pip # caching pip dependencies - - run: pip install -r requirements_dev.txt - - name: Install nxmx - run: pip install . - - name: Run pytest - run: pytest -vs - post_build: - name: "CI Successful" - needs: [build] - runs-on: ubuntu-latest - steps: - - name: Nothing - run: "true" diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index e88cdb4..9ae7660 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -1,34 +1,72 @@ -name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI +name: Build and Test on: push jobs: - build-n-publish: - name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI + build: runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Install Build + run: | + python -mpip install --upgrade pip + pip install build + - name: Build distribution + run: | + python -mbuild + pip install dist/*.whl + - uses: actions/upload-artifact@v3 + with: + path: ./dist/* + test: + needs: build + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.9', '3.10', '3.11', '3.12'] + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v3 + with: + name: artifact + path: dist + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest dist/*.whl -r requirements.txt -r requirements_dev.txt pytest-md pytest-emoji + - name: Run pytest + uses: pavelzw/pytest-action@510c5e90c360a185039bea56ce8b3e7e51a16507 # v2.2.0 + with: + click-to-expand: false + emoji: true + job-summary: true + verbose: false + custom-arguments: -v -ra + custom-pytest: PYTHONDEVMODE=1 pytest + report-title: Test Report + + pypi-publish: + name: Upload release to PyPI + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + runs-on: ubuntu-latest + environment: + name: Release + url: https://pypi.org/p/nxmx + permissions: + id-token: write steps: - - uses: actions/checkout@master - - name: Set up Python 3.10 - uses: actions/setup-python@v3 + - uses: actions/download-artifact@v3 with: - python-version: '3.10' - - name: Install pypa/build - run: >- - python -m - pip install - build - --user - - name: Build a binary wheel and a source tarball - run: >- - python -m - build - --sdist - --wheel - --outdir dist/ - . - - name: Publish distribution 📦 to PyPI - if: startsWith(github.ref, 'refs/tags') + name: artifact + path: dist + - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b85e871..e814ce2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,35 +1,19 @@ -# Run 'libtbx.precommit install' to enable repository pre-commits. -repos: - -# Bring Python code up to date with pyupgrade -- repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 - hooks: - - id: pyupgrade +ci: + autoupdate_schedule: quarterly + skip: [poetry-lock] -# Automatically sort imports with isort -- repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - -# Automatic source code formatting with Black -- repo: https://github.com/psf/black - rev: 22.12.0 - hooks: - - id: black - args: [--safe, --quiet] +repos: -# Enforce style with Flake8 -- repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.2 hooks: - - id: flake8 - args: [--max-line-length=88, '--select=E401,E711,E712,E713,E714,E721,E722,E901,F401,F402,F403,F405,F631,F632,F633,F811,F812,F821,F822,F841,F901,W191,W291,W292,W293,W602,W603,W604,W605,W606'] + - id: ruff + args: [--fix, --show-fixes, --exit-non-zero-on-fix] + - id: ruff-format # Format YAML & TOML files prettily - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks - rev: v2.6.0 + rev: v2.14.0 hooks: - id: pretty-format-yaml args: [--autofix, --indent, '2'] @@ -38,7 +22,7 @@ repos: # Syntax check with pre-commit out-of-the-box hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.6.0 hooks: - id: check-ast - id: check-json diff --git a/pyproject.toml b/pyproject.toml index 034370e..f21b322 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,15 +3,8 @@ build-backend = "setuptools.build_meta" requires = ["setuptools>=61", "setuptools-scm"] [project] -classifiers = [ - "Programming Language :: Python :: 3" -] -dependencies = [ - "h5py", - "pint", - "python-dateutil", - "scipy" -] +classifiers = ["Programming Language :: Python :: 3"] +dependencies = ["h5py", "pint", "python-dateutil", "scipy", "numpy <2"] description = "Read HDF5 data conforming to the NXmx application definition of the NeXus format" dynamic = ["version"] keywords = ["NeXus", "NXmx"] @@ -20,6 +13,10 @@ name = "nxmx" readme = "README.md" requires-python = ">=3.9" +[tool.ruff.lint] +ignore = ["E501"] +select = ["E", "F", "UP", "W", "I", "C"] + [tool.setuptools.package-data] nxmx = ["py.typed"] diff --git a/requirements.txt b/requirements.txt index 4f6734b..ee530ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,28 @@ -h5py==3.9.0 -numpy==1.25.2 -pint==0.22 -python-dateutil==2.8.2 -scipy==1.11.1 +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements.txt --python 3.9 +appdirs==1.4.4 + # via pint +flexcache==0.3 + # via pint +flexparser==0.3.1 + # via pint +h5py==3.12.1 + # via nxmx (pyproject.toml) +numpy==1.26.4 + # via + # nxmx (pyproject.toml) + # h5py + # scipy +pint==0.24.3 + # via nxmx (pyproject.toml) +python-dateutil==2.9.0.post0 + # via nxmx (pyproject.toml) +scipy==1.13.1 + # via nxmx (pyproject.toml) +six==1.16.0 + # via python-dateutil +typing-extensions==4.12.2 + # via + # flexcache + # flexparser + # pint diff --git a/requirements_dev.txt b/requirements_dev.txt index a5929b8..1fe7b5e 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,7 +1,2 @@ -h5py==3.9.0 -numpy==1.25.2 -pint==0.22 -pytest==7.4.0 -pytest-cov==4.1.0 -python-dateutil==2.8.2 -scipy==1.11.1 +pytest==8.3.3 +pytest-cov==5.0.0 diff --git a/src/nxmx/__init__.py b/src/nxmx/__init__.py index 0228903..3fbf560 100644 --- a/src/nxmx/__init__.py +++ b/src/nxmx/__init__.py @@ -5,8 +5,9 @@ import logging import operator from collections import abc, namedtuple +from collections.abc import Iterable, Iterator, Sequence from functools import cached_property, reduce -from typing import Iterable, Iterator, Sequence, Union, overload +from typing import Union, overload import dateutil.parser import h5py @@ -266,7 +267,6 @@ def data_scale_factor(self) -> str | None: if "data_scale_factor" in self._handle: return self._handle["data_scale_factor"][()] - @cached_property def data_offset(self) -> str | None: """ @@ -278,7 +278,6 @@ def data_offset(self) -> str | None: return self._handle["data_offset"][()] - class NXtransformations(H5Mapping): """Collection of axis-based translations and rotations to describe a geometry. @@ -1162,12 +1161,10 @@ def __iter__(self) -> Iterator[NXtransformationsAxis]: return iter(self.transformations) @overload - def __getitem__(self, idx: int) -> NXtransformationsAxis: - ... + def __getitem__(self, idx: int) -> NXtransformationsAxis: ... @overload - def __getitem__(self, idx: slice) -> Sequence[NXtransformationsAxis]: - ... + def __getitem__(self, idx: slice) -> Sequence[NXtransformationsAxis]: ... def __getitem__(self, idx): return self.transformations[idx] diff --git a/tests/conftest.py b/tests/conftest.py index f3421bd..e14cdee 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -79,9 +79,9 @@ def nxmx_example(): "fast_pixel_direction", data=7.5e-5 ) fast_pixel_direction.attrs["transformation_type"] = "translation" - fast_pixel_direction.attrs[ - "depends_on" - ] = "/entry/instrument/detector/module/module_offset" + fast_pixel_direction.attrs["depends_on"] = ( + "/entry/instrument/detector/module/module_offset" + ) fast_pixel_direction.attrs["vector"] = np.array([-1.0, 0.0, 0.0]) fast_pixel_direction.attrs["offset"] = np.array([0.0, 0.0, 0.0]) fast_pixel_direction.attrs["offset_units"] = b"m" @@ -91,9 +91,9 @@ def nxmx_example(): "slow_pixel_direction", data=7.5e-5 ) slow_pixel_direction.attrs["transformation_type"] = "translation" - slow_pixel_direction.attrs[ - "depends_on" - ] = "/entry/instrument/detector/module/module_offset" + slow_pixel_direction.attrs["depends_on"] = ( + "/entry/instrument/detector/module/module_offset" + ) slow_pixel_direction.attrs["vector"] = np.array([0.0, -1.0, 0.0]) slow_pixel_direction.attrs["offset"] = np.array([0.0, 0.0, 0.0]) slow_pixel_direction.attrs["offset_units"] = b"m" diff --git a/tests/test_nxmx.py b/tests/test_nxmx.py index ac1cd47..288d79f 100644 --- a/tests/test_nxmx.py +++ b/tests/test_nxmx.py @@ -263,9 +263,9 @@ def detector_depends_on_example(request): "fast_pixel_direction", data=7.5e-5 ) fast_pixel_direction.attrs["transformation_type"] = "translation" - fast_pixel_direction.attrs[ - "depends_on" - ] = "/entry/instrument/detector/module/module_offset" + fast_pixel_direction.attrs["depends_on"] = ( + "/entry/instrument/detector/module/module_offset" + ) fast_pixel_direction.attrs["vector"] = np.array([-1.0, 0.0, 0.0]) fast_pixel_direction.attrs["offset"] = np.array([0.0, 0.0, 0.0]) fast_pixel_direction.attrs["offset_units"] = "m" @@ -274,13 +274,13 @@ def detector_depends_on_example(request): module_offset = module.create_dataset("module_offset", data=0) module_offset.attrs["transformation_type"] = "translation" if request.param: - module_offset.attrs[ - "depends_on" - ] = "/entry/instrument/detector/transformations/det_z_tune" + module_offset.attrs["depends_on"] = ( + "/entry/instrument/detector/transformations/det_z_tune" + ) else: - module_offset.attrs[ - "depends_on" - ] = "/entry/instrument/detector/transformations/det_z" + module_offset.attrs["depends_on"] = ( + "/entry/instrument/detector/transformations/det_z" + ) module_offset.attrs["vector"] = np.array([1.0, 0.0, 0.0]) module_offset.attrs["offset"] = np.array([0.155985, 0.166904, -0]) module_offset.attrs["offset_units"] = "m" @@ -291,9 +291,9 @@ def detector_depends_on_example(request): det_z_tune = transformations.create_dataset( "det_z_tune", data=np.array([-0.5]) ) - det_z_tune.attrs[ - "depends_on" - ] = b"/entry/instrument/detector/transformations/det_z" + det_z_tune.attrs["depends_on"] = ( + b"/entry/instrument/detector/transformations/det_z" + ) det_z_tune.attrs["transformation_type"] = b"translation" det_z_tune.attrs["units"] = b"mm" det_z_tune.attrs["vector"] = np.array([0.0, 0.0, 1.0])