From 0f0a6004d118d79fbc0602e999272bde31ef8015 Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 14:24:10 +0100
Subject: [PATCH 1/7] Update pixi.lock
---
pixi.lock | 35 +++++++++++++++--------------------
1 file changed, 15 insertions(+), 20 deletions(-)
diff --git a/pixi.lock b/pixi.lock
index d946163..f51bc65 100644
--- a/pixi.lock
+++ b/pixi.lock
@@ -5,8 +5,6 @@ environments:
- url: https://conda.anaconda.org/conda-forge/
indexes:
- https://pypi.org/simple
- options:
- pypi-prerelease-mode: if-necessary-or-explicit
packages:
linux-64:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
@@ -80,7 +78,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -335,7 +333,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -590,7 +588,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -838,7 +836,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -1031,8 +1029,6 @@ environments:
- url: https://conda.anaconda.org/conda-forge/
indexes:
- https://pypi.org/simple
- options:
- pypi-prerelease-mode: if-necessary-or-explicit
packages:
linux-64:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
@@ -1106,7 +1102,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/f7/7c/347280982982383621d29b8c544cf497ae07ac41e44b1ca4903024131f55/coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -1362,7 +1358,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/b4/9b/77baf488516e9ced25fc215a6f75d803493fc3f6a1a1227ac35697910c2a/coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -1618,7 +1614,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/d7/cd/7ab01154e6eb79ee2fab76bf4d89e94c6648116557307ee4ebbb85e5c1bf/coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -1867,7 +1863,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/27/56/c216625f453df6e0559ed666d246fcbaaa93f3aa99eaa5080cea1229aa3d/coverage-7.13.1-cp311-cp311-win_amd64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -2061,8 +2057,6 @@ environments:
- url: https://conda.anaconda.org/conda-forge/
indexes:
- https://pypi.org/simple
- options:
- pypi-prerelease-mode: if-necessary-or-explicit
packages:
linux-64:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
@@ -2136,7 +2130,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -2391,7 +2385,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -2646,7 +2640,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -2894,7 +2888,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl
- pypi: https://files.pythonhosted.org/packages/b8/01/74922a1c552137c05a41fee0c61153753dddc9117d19c7c5902c146c25ab/copier-9.11.3-py3-none-any.whl
- - pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ - pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
- pypi: https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl
@@ -4091,7 +4085,7 @@ packages:
requires_python: '>=3.5'
- pypi: ./
name: easydynamics
- version: 0.1.0+devdirty7
+ version: 0.1.0+devdirty6
sha256: de299c914d4a865b9e2fdefa5e3947f37b1f26f73ff9087f7918ee417f3dd288
requires_dist:
- darkdetect
@@ -4134,7 +4128,8 @@ packages:
- validate-pyproject[all] ; extra == 'dev'
- versioningit ; extra == 'dev'
requires_python: '>=3.11'
-- pypi: git+https://github.com/easyscience/corelib.git#bd106537fcf522336aa0176aa6ccf215be8a5b86
+ editable: true
+- pypi: git+https://github.com/easyscience/corelib.git?rev=develop#bd106537fcf522336aa0176aa6ccf215be8a5b86
name: easyscience
version: 2.1.0
requires_dist:
From 4e860abdc9a6abad7655a9d50184f4d851aeb058 Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 14:28:21 +0100
Subject: [PATCH 2/7] Reapply templates from v0.4.0
---
.copier-answers.yml | 2 +-
.github/workflows/docs.yml | 7 +-
.github/workflows/quality.yml | 8 +
.github/workflows/tutorial-tests.yml | 2 +-
.gitignore | 5 +
.pre-commit-config.yaml | 29 +--
README.md | 14 +-
docs/docs/assets/stylesheets/extra.css | 23 +-
docs/docs/installation-and-setup/index.md | 32 +--
docs/docs/introduction/index.md | 3 +-
pixi.toml | 107 ++++++---
tools/nonpy_prettier_modified.py | 87 ++++++++
tools/update_github_labels.py | 254 ++++++++++++++++++++++
13 files changed, 484 insertions(+), 89 deletions(-)
create mode 100644 tools/nonpy_prettier_modified.py
create mode 100644 tools/update_github_labels.py
diff --git a/.copier-answers.yml b/.copier-answers.yml
index b2bdcfa..e644aa9 100644
--- a/.copier-answers.yml
+++ b/.copier-answers.yml
@@ -1,6 +1,6 @@
# WARNING: Do not edit this file manually.
# Any changes will be overwritten by Copier.
-_commit: v0.0.5
+_commit: v0.4.0
_src_path: gh:easyscience/templates
app_docs_url: https://easyscience.github.io/dynamics-app
app_doi: 10.5281/zenodo.18163581
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 05fef7d..4056c1c 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -107,11 +107,8 @@ jobs:
- name: Pre-build site step
run: pixi run python -c "import easydynamics"
- # Convert Python scripts in the docs/docs/tutorials/ directory to Jupyter
- # notebooks.
- # This step also strips any existing output from the notebooks and
- # prepares them for documentation.
- - name: Convert tutorial scripts to notebooks
+ # Prepare the Jupyter notebooks for documentation (strip output, etc.).
+ - name: Prepare notebooks
run: pixi run notebook-prepare
# Execute all Jupyter notebooks to generate output cells (plots, tables, etc.).
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index 1397f48..201dace 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -79,6 +79,14 @@ jobs:
continue-on-error: true
shell: bash
run: pixi run nonpy-format-check
+ # Check formatting of Jupyter Notebooks in the tutorials folder
+ - name: Prepare notebooks and check formatting
+ id: check_notebooks_formatting
+ continue-on-error: true
+ shell: bash
+ run: |
+ pixi run notebook-prepare
+ pixi run notebook-format-check
# Add summary
- name: Add quality checks summary
diff --git a/.github/workflows/tutorial-tests.yml b/.github/workflows/tutorial-tests.yml
index a3454fe..5599884 100644
--- a/.github/workflows/tutorial-tests.yml
+++ b/.github/workflows/tutorial-tests.yml
@@ -46,7 +46,7 @@ jobs:
shell: bash
run: pixi run script-tests
- - name: Convert tutorial scripts to notebooks
+ - name: Prepare notebooks
shell: bash
run: pixi run notebook-prepare
diff --git a/.gitignore b/.gitignore
index 7e0f2da..f7ce4ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,11 @@ __pycache__/
.venv/
.coverage
+# PyInstaller
+dist/
+build/
+*.spec
+
# MkDocs
docs/site/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c3d471c..262cd4f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,32 +11,35 @@ repos:
pass_filenames: false
stages: [pre-commit]
- - id: pixi-py-lint-check-staged
- name: pixi run py-lint-check-staged
+ - id: pixi-py-lint-check
+ name: pixi run py-lint-check-pre STAGED_FILES
entry: pixi run py-lint-check-pre
language: system
- pass_filenames: false
+ pass_filenames: true
+ files: ^(src/|tests/|docs/docs/tutorials/).*\.py$
stages: [pre-commit]
- - id: pixi-py-format-check-staged
- name: pixi run py-format-check-staged
+ - id: pixi-py-format-check
+ name: pixi run py-format-check-pre STAGED_FILES
entry: pixi run py-format-check-pre
language: system
- pass_filenames: false
+ pass_filenames: true
+ files: ^(src/|tests/|docs/docs/tutorials/).*\.py$
stages: [pre-commit]
- - id: pixi-nonpy-format-check-modified
- name: pixi run nonpy-format-check-modified
- entry: pixi run nonpy-format-check-modified
+ - id: pixi-nonpy-format-check
+ name: pixi run nonpy-format-check-pre STAGED_FILES
+ entry: pixi run nonpy-format-check-pre
language: system
- pass_filenames: false
+ pass_filenames: true
stages: [pre-commit]
- id: pixi-docs-format-check
- name: pixi run docs-format-check
- entry: pixi run docs-format-check
+ name: pixi run docs-format-check-pre STAGED_FILES
+ entry: pixi run docs-format-check-pre
language: system
- pass_filenames: false
+ pass_filenames: true
+ files: ^(src/|docs/docs/tutorials/).*\.py$
stages: [pre-commit]
# ----------------
diff --git a/README.md b/README.md
index 2f55c56..d0bddc0 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,18 @@
-
+
-
+
-
+
-**EasyDynamics** is a scientific software for plotting and fitting qens
-and ins powder data.
+**EasyDynamics** is a scientific software for plotting and fitting QENS and INS powder data.
+
+
+
**EasyDynamics** is available both as a Python library and as a
cross-platform desktop application.
@@ -38,3 +40,5 @@ Here, we focus on the Python library. For the graphical user interface
- ๐งโ๐ป [Source Code](https://github.com/easyscience/dynamics-lib)
- โ๏ธ
[License](https://raw.githubusercontent.com/easyscience/dynamics-lib/refs/heads/master/LICENSE)
+
+
diff --git a/docs/docs/assets/stylesheets/extra.css b/docs/docs/assets/stylesheets/extra.css
index 1c19995..a625be8 100644
--- a/docs/docs/assets/stylesheets/extra.css
+++ b/docs/docs/assets/stylesheets/extra.css
@@ -222,9 +222,27 @@ Adjust the margins and paddings to fit the defaults in MkDocs Material and do no
width: 100% !important;
display: flex !important;
}
+
.jp-Notebook {
padding: 0 !important;
margin-top: -3em !important;
+
+ /* Ensure notebook content stretches across the page */
+ width: 100% !important;
+ max-width: 100% !important;
+
+ /* mkdocs-material + some notebook HTML end up as flex */
+ align-items: stretch !important;
+}
+
+.jp-Notebook .jp-Cell {
+ /* Key: flex children often need min-width: 0 to prevent weird shrink */
+ width: 100% !important;
+ max-width: 100% !important;
+ min-width: 0 !important;
+
+ /* Removes jupyter cell paddings */
+ padding-left: 0 !important;
}
/* Removes jupyter cell prefixes, like In[123]: */
@@ -234,11 +252,6 @@ Adjust the margins and paddings to fit the defaults in MkDocs Material and do no
display: none !important;
}
-/* Removes jupyter cell paddings */
-.jp-Cell {
- padding-left: 0 !important;
-}
-
/* Removes jupyter output cell padding to align with input cell text */
.jp-RenderedText {
padding-left: 0.85em !important;
diff --git a/docs/docs/installation-and-setup/index.md b/docs/docs/installation-and-setup/index.md
index 3513f6e..18dd951 100644
--- a/docs/docs/installation-and-setup/index.md
+++ b/docs/docs/installation-and-setup/index.md
@@ -8,7 +8,7 @@ icon: material/cog-box
**Python 3.11** through **3.12**.
To install and set up EasyDynamics, we recommend using
-[**Pixi**](https://prefix.dev), a modern package manager for Windows,
+[**Pixi**](https://pixi.prefix.dev), a modern package manager for Windows,
macOS, and Linux.
!!! note "Main benefits of using Pixi"
@@ -46,16 +46,9 @@ This section describes the simplest way to set up EasyDynamics using
```txt
pixi add python=3.12
```
-- Add the GNU Scientific Library (GSL) dependency:
+- Add EasyDynamics to the Pixi environment from PyPI:
```txt
- pixi add gsl
- ```
-- Add EasyDynamics with the `visualization` extras, which include
- optional dependencies used for simplified visualization of charts and
- tables. This can be especially useful for running the Jupyter Notebook
- examples:
- ```txt
- pixi add --pypi "easydynamics[visualization]"
+ pixi add --pypi easydynamics
```
- Add a Pixi task to run EasyDynamics commands easily:
```txt
@@ -160,20 +153,7 @@ simply delete and recreate the environment.
### Installing from PyPI { #from-pypi }
EasyDynamics is available on **PyPI (Python Package Index)** and can be
-installed using `pip`.
-
-We recommend installing the latest release of EasyDynamics with the
-`visualization` extras, which include optional dependencies used for
-simplified visualization of charts and tables. This can be especially
-useful for running the Jupyter Notebook examples. To do so, use the
-following command:
-
-```txt
-pip install 'easydynamics[visualization]'
-```
-
-If only the core functionality is needed, the library can be installed
-simply with:
+installed using `pip`. To do so, use the following command:
```txt
pip install easydynamics
@@ -216,10 +196,10 @@ example:
pip install git+https://github.com/easyscience/dynamics-lib@develop
```
-To include extra dependencies (e.g., visualization):
+To include extra dependencies (e.g., dev):
```txt
-pip install 'easydynamics[visualization] @ git+https://github.com/easyscience/dynamics-lib@develop'
+pip install 'easydynamics[dev] @ git+https://github.com/easyscience/dynamics-lib@develop'
```
## How to Run Tutorials
diff --git a/docs/docs/introduction/index.md b/docs/docs/introduction/index.md
index 5824051..606ed6c 100644
--- a/docs/docs/introduction/index.md
+++ b/docs/docs/introduction/index.md
@@ -6,8 +6,7 @@ icon: material/information-slab-circle
## Description
-**EasyDynamics** is a scientific software for plotting and fitting qens
-and ins powder data.
+**EasyDynamics** is a scientific software for plotting and fitting QENS and INS powder data.
**EasyDynamics** is available both as a Python library and as a
cross-platform desktop application.
diff --git a/pixi.toml b/pixi.toml
index baa0ea3..befe237 100644
--- a/pixi.toml
+++ b/pixi.toml
@@ -76,44 +76,57 @@ default = { features = ['default', 'py-max'] }
[tasks]
+##################
# ๐งช Testing Tasks
-unit-tests = 'python -m pytest tests/unit/ --color=yes --cov= --cov-report='
+##################
+
+unit-tests = 'python -m pytest tests/unit/ --color=yes -v'
integration-tests = 'python -m pytest tests/integration/ --color=yes -n auto -v'
notebook-tests = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout=600 --color=yes -n auto -v'
script-tests = 'python -m pytest tools/test_scripts.py --color=yes -n auto -v'
test = { depends-on = ['unit-tests'] }
+###########
# โ๏ธ Checks
+###########
+
pyproject-check = 'python -m validate_pyproject pyproject.toml'
-py-lint-check-pre = "python -m ruff check"
-py-lint-check = 'pixi run py-lint-check-pre .'
-py-format-check-pre = "python -m ruff format --check"
-py-format-check = "pixi run py-format-check-pre ."
-nonpy-format-check-pre = "npx prettier --list-different --config=prettierrc.toml"
-nonpy-format-check-modified = "pixi run nonpy-format-check-pre $(git diff --diff-filter=d --name-only HEAD | grep -E '\\.(json|ya?ml|toml|md|css|html)$' || echo .)"
-nonpy-format-check = "pixi run nonpy-format-check-pre ."
+docs-format-check = 'docformatter --check src/ docs/docs/tutorials/'
notebook-format-check = 'nbqa ruff docs/docs/tutorials/'
-docs-format-check = 'docformatter src/ docs/docs/tutorials/ --check'
+py-lint-check = 'ruff check src/ tests/ docs/docs/tutorials/'
+py-format-check = "ruff format --check src/ tests/ docs/docs/tutorials/"
+nonpy-format-check = "npx prettier --list-different --config=prettierrc.toml --ignore-unknown ."
+nonpy-format-check-modified = "python tools/nonpy_prettier_modified.py"
check = { depends-on = [
- 'docs-format-check',
'py-format-check',
+ 'docs-format-check',
'py-lint-check',
'nonpy-format-check-modified',
] }
+##########
# ๐ ๏ธ Fixes
-py-lint-fix = 'pixi run py-lint-check --fix'
-#py-format-fix = "python -m ruff format $(git diff --cached --name-only -- '*.py')"
-py-format-fix = "python -m ruff format"
-nonpy-format-fix = 'pixi run nonpy-format-check --write'
-nonpy-format-fix-modified = "pixi run nonpy-format-check-modified --write"
-notebook-format-fix = 'pixi run notebook-format-check --fix'
-docs-format-fix = 'docformatter src/ docs/docs/tutorials/ --in-place'
+##########
+
+docs-format-fix = 'docformatter --in-place src/ docs/docs/tutorials/'
+notebook-format-fix = 'nbqa ruff --fix docs/docs/tutorials/'
+py-lint-fix = 'ruff check --fix src/ tests/ docs/docs/tutorials/'
+py-format-fix = "ruff format src/ tests/ docs/docs/tutorials/"
+nonpy-format-fix = 'npx prettier --write --list-different --config=prettierrc.toml --ignore-unknown .'
+nonpy-format-fix-modified = "python tools/nonpy_prettier_modified.py --write"
success-message-fix = 'echo "โ
All code auto-formatting steps have been applied."'
fix = { depends-on = [
+ 'py-format-fix',
+ 'docs-format-fix',
+ 'py-lint-fix',
+ 'nonpy-format-fix-modified',
+ 'success-message-fix',
+] }
+
+fix-all = { depends-on = [
'py-format-fix',
'docs-format-fix',
'py-lint-fix',
@@ -121,7 +134,10 @@ fix = { depends-on = [
'success-message-fix',
] }
+####################
# ๐งฎ Code Complexity
+####################
+
complexity-check = 'radon cc -s src/'
complexity-check-json = 'radon cc -s -j src/'
maintainability-check = 'radon mi src/'
@@ -129,8 +145,11 @@ maintainability-check-json = 'radon mi -j src/'
raw-metrics = 'radon raw -s src/'
raw-metrics-json = 'radon raw -s -j src/'
+#############
# ๐ Coverage
-unit-tests-coverage = 'python -m pytest tests/unit/ --color=yes --cov=src/easydynamics --cov-report=term-missing'
+#############
+
+unit-tests-coverage = 'pixi run unit-tests --cov=src/easydynamics --cov-report=term-missing'
integration-tests-coverage = 'pixi run integration-tests --cov=src/easydynamics --cov-report=term-missing'
docstring-coverage = 'interrogate -c pyproject.toml src/easydynamics'
@@ -140,19 +159,25 @@ cov = { depends-on = [
'integration-tests-coverage',
] }
+########################
# ๐ Notebook Management
+########################
+
notebook-convert = 'jupytext docs/docs/tutorials/*.py --from py:percent --to ipynb'
notebook-strip = 'nbstripout docs/docs/tutorials/*.ipynb'
notebook-tweak = 'python tools/tweak_notebooks.py tutorials/'
notebook-exec = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout=600 --overwrite --color=yes -n auto -v'
notebook-prepare = { depends-on = [
- ###'notebook-convert',
+ #'notebook-convert',
'notebook-strip',
- ###'notebook-tweak',
+ #'notebook-tweak',
] }
+########################
# ๐ Documentation Tasks
+########################
+
docs-vars = "JUPYTER_PLATFORM_DIRS=1 PYTHONWARNINGS='ignore::RuntimeWarning'"
docs-pre = "pixi run docs-vars python -m mkdocs"
docs-serve = "pixi run docs-pre serve -f docs/mkdocs.yml"
@@ -163,22 +188,25 @@ docs-build-local = "pixi run docs-build --no-directory-urls"
docs-deploy-pre = 'mike deploy -F docs/mkdocs.yml --push --branch gh-pages --update-aliases --alias-type redirect'
docs-set-default-pre = 'mike set-default -F docs/mkdocs.yml --push --branch gh-pages'
-docs-update-assets = 'pixi run python tools/update_docs_assets.py'
+docs-update-assets = 'python tools/update_docs_assets.py'
+##############################
# ๐ฆ Template Management Tasks
-copier-copy = "pixi run copier copy gh:easyscience/templates . --data-file ../dynamics/.copier-answers.yml --data template_type=lib"
-copier-recopy = "pixi run copier recopy --data-file ../dynamics/.copier-answers.yml --data template_type=lib"
-copier-update = "pixi run copier update --data-file ../dynamics/.copier-answers.yml --data template_type=lib"
+##############################
-# ๐ Development & Build Tasks
-default-build = 'python -m build'
-dist-build = 'python -m build --wheel --outdir dist'
+copier-copy = "copier copy gh:easyscience/templates . --data-file ../dynamics/.copier-answers.yml --data template_type=lib"
+copier-recopy = "copier recopy --data-file ../dynamics/.copier-answers.yml --data template_type=lib"
+copier-update = "copier update --data-file ../dynamics/.copier-answers.yml --data template_type=lib"
-npm-config = 'npm config set registry https://registry.npmjs.org/'
-prettier-install = 'npm install --no-save --no-audit --no-fund prettier prettier-plugin-toml'
+#####################
+# ๐ช Pre-commit Hooks
+#####################
-clean-pycache = "find . -type d -name '__pycache__' -prune -exec rm -rf '{}' +"
-spdx-update = 'python tools/update_spdx.py'
+# Pre-commit hook commands (to be used in .pre-commit-config.yaml)
+py-lint-check-pre = 'ruff check'
+py-format-check-pre = "ruff format --check"
+nonpy-format-check-pre = "npx prettier --list-different --config=prettierrc.toml --ignore-unknown"
+docs-format-check-pre = 'docformatter --check'
# Run like a real commit: staged files only (almost)
pre-commit-check = 'pre-commit run --hook-stage pre-commit'
@@ -196,11 +224,28 @@ pre-commit-setup = { depends-on = [
'pre-commit-install',
] }
+####################################
+# ๐ Other Development & Build Tasks
+####################################
+
+github-labels = 'python tools/update_github_labels.py'
+
+default-build = 'python -m build'
+dist-build = 'python -m build --wheel --outdir dist'
+
+npm-config = 'npm config set registry https://registry.npmjs.org/'
+prettier-install = 'npm install --no-save --no-audit --no-fund prettier prettier-plugin-toml'
+
+clean-pycache = "find . -type d -name '__pycache__' -prune -exec rm -rf '{}' +"
+spdx-update = 'python tools/update_spdx.py'
+
post-install = { depends-on = [
'npm-config',
'prettier-install',
'pre-commit-setup',
] }
+##########################
# ๐ Main Package Shortcut
+##########################
easydynamics = 'python -m easydynamics'
diff --git a/tools/nonpy_prettier_modified.py b/tools/nonpy_prettier_modified.py
new file mode 100644
index 0000000..81805e3
--- /dev/null
+++ b/tools/nonpy_prettier_modified.py
@@ -0,0 +1,87 @@
+from __future__ import annotations
+
+import shutil
+import subprocess
+import sys
+
+
+def get_stdout_lines(cmd: list[str]) -> list[str]:
+ """Execute a command and return its standard output as a list of
+ non-empty lines.
+
+ The command is executed with `check=True`, so a non-zero exit code
+ will raise `subprocess.CalledProcessError`.
+
+ Args:
+ cmd: Command and arguments to execute, as a list of strings.
+
+ Returns:
+ A list of stripped, non-empty lines from the command's stdout.
+ """
+ result = subprocess.run(
+ cmd,
+ capture_output=True,
+ text=True,
+ encoding='utf-8',
+ check=True,
+ )
+ return [line.strip() for line in result.stdout.splitlines() if line.strip()]
+
+
+def main() -> int:
+ """Run Prettier on modified or newly added non-Python files in the
+ Git repository.
+
+ The file list is constructed from:
+ - tracked files that are added or modified (staged or unstaged)
+ - untracked files that are not ignored by Git
+
+ Prettier is always run with `--list-different`.
+ If `--write` is provided as a command-line argument, files are fixed
+ in place in addition to being listed.
+
+ Returns:
+ Exit code of the Prettier process, or 0 if there are no files to
+ process.
+ """
+ # Tracked added/modified (staged or not)
+ files = get_stdout_lines(['git', 'diff', '--name-only', '--diff-filter=AM', 'HEAD'])
+
+ # Untracked new files
+ files += get_stdout_lines(['git', 'ls-files', '--others', '--exclude-standard'])
+
+ if not files:
+ return 0 # nothing to do
+
+ # Locate npx executable (npx.cmd on Windows)
+ npx = shutil.which('npx') or shutil.which('npx.cmd')
+ if not npx:
+ print('ERROR: npx not found in PATH', file=sys.stderr)
+ return 2
+
+ # Windows requires running .cmd files via the shell
+ need_shell = npx.lower().endswith('.cmd')
+
+ cmd = [
+ npx,
+ 'prettier',
+ '--list-different',
+ ]
+
+ # Optionally enable fixing
+ if '--write' in sys.argv:
+ cmd.append('--write')
+
+ cmd += [
+ '--ignore-unknown',
+ '--config=prettierrc.toml',
+ '--',
+ *files,
+ ]
+
+ proc = subprocess.run(cmd, shell=need_shell)
+ return proc.returncode
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())
diff --git a/tools/update_github_labels.py b/tools/update_github_labels.py
new file mode 100644
index 0000000..a18043d
--- /dev/null
+++ b/tools/update_github_labels.py
@@ -0,0 +1,254 @@
+"""
+Set/update GitHub labels for current or specified easyscience
+repository.
+
+Requires:
+ - gh CLI installed
+ - gh auth login completed
+
+Usage:
+ python update_github_labels.py
+ python update_github_labels.py --dry-run
+ python update_github_labels.py --repo easyscience/my-repo
+ python update_github_labels.py --repo easyscience/my-repo --dry-run
+"""
+
+from __future__ import annotations
+
+import argparse
+import json
+import shlex
+import subprocess
+import sys
+from dataclasses import dataclass
+from typing import Iterable
+
+
+EASYSCIENCE_ORG = 'easyscience'
+
+
+# --- Label definitions -----------------------------------------------------------
+
+BASIC_GITHUB_LABELS = [
+ 'bug',
+ 'documentation',
+ 'duplicate',
+ 'enhancement',
+ 'good first issue',
+ 'help wanted',
+ 'invalid',
+ 'question',
+ 'wontfix',
+]
+
+NEW_BASIC_LABEL_NAMES = [
+ '[scope] bug',
+ '[scope] documentation',
+ '[maintainer] duplicate',
+ '[scope] enhancement',
+ '[maintainer] good first issue',
+ '[maintainer] help wanted',
+ '[maintainer] invalid',
+ '[maintainer] question',
+ '[maintainer] wontfix',
+]
+
+SCOPE_LABELS = [
+ ('bug', 'Bug report or fix (major.minor.PATCH)'),
+ ('documentation', 'Documentation only changes (major.minor.patch.POST)'),
+ ('enhancement', 'Adds/improves features (major.MINOR.patch)'),
+ ('maintenance', 'Code/tooling cleanup, no feature or bugfix (major.minor.PATCH)'),
+ ('significant', 'Breaking or major changes (MAJOR.minor.patch)'),
+ ('โ ๏ธ label needed', 'Automatically added to issues and PRs without a [scope] label'),
+]
+
+MAINTAINER_LABELS = [
+ ('duplicate', 'Already reported or submitted'),
+ ('good first issue', 'Good entry-level issue for newcomers'),
+ ('help wanted', 'Needs additional help to resolve or implement'),
+ ('invalid', 'Invalid, incorrect or outdated'),
+ ('question', 'Needs clarification, discussion, or more information'),
+ ('wontfix', 'Will not be fixed or continued'),
+]
+
+PRIORITY_LABELS = [
+ ('lowest', 'Very low urgency'),
+ ('low', 'Low importance'),
+ ('medium', 'Normal/default priority'),
+ ('high', 'Should be prioritized soon'),
+ ('highest', 'Urgent. Needs attention ASAP'),
+ ('โ ๏ธ label needed', 'Automatically added to issues without a [priority] label'),
+]
+
+BOT_LABEL = (
+ '[bot] pull request',
+ 'Automated release PR. Excluded from changelog/versioning',
+)
+
+COLORS = {
+ 'scope': 'd73a4a',
+ 'maintainer': '0e8a16',
+ 'priority': 'fbca04',
+ 'bot': '5319e7',
+}
+
+
+# --- Helpers --------------------------------------------------------------------
+
+
+@dataclass(frozen=True)
+class CmdResult:
+ returncode: int
+ stdout: str
+ stderr: str
+
+
+def run_cmd(args: list[str], *, dry_run: bool, check: bool = True) -> CmdResult:
+ """Run a command (or print it in dry-run mode)."""
+ cmd_str = ' '.join(shlex.quote(a) for a in args)
+
+ if dry_run:
+ print(f'{cmd_str}')
+ return CmdResult(0, '', '')
+
+ proc = subprocess.run(
+ args,
+ text=True,
+ capture_output=True,
+ )
+ res = CmdResult(proc.returncode, proc.stdout.strip(), proc.stderr.strip())
+
+ if check and proc.returncode != 0:
+ raise RuntimeError(f'Command failed ({proc.returncode}): {cmd_str}\n{res.stderr}')
+
+ return res
+
+
+def get_current_repo_name_with_owner() -> str:
+ res = subprocess.run(
+ ['gh', 'repo', 'view', '--json', 'nameWithOwner'],
+ text=True,
+ capture_output=True,
+ check=True,
+ )
+ data = json.loads(res.stdout)
+ nwo = data.get('nameWithOwner')
+ if not nwo or '/' not in nwo:
+ raise RuntimeError('Could not determine current repository name')
+ return nwo
+
+
+def try_rename_label(repo: str, old: str, new: str, *, dry_run: bool) -> None:
+ try:
+ run_cmd(
+ ['gh', 'label', 'edit', old, '--name', new, '--repo', repo],
+ dry_run=dry_run,
+ )
+ print(f'Rename: {old!r} โ {new!r}')
+ except Exception:
+ print(f'Skip rename (label not found): {old!r}')
+
+
+def upsert_label(
+ repo: str,
+ name: str,
+ color: str,
+ description: str,
+ *,
+ dry_run: bool,
+) -> None:
+ run_cmd(
+ [
+ 'gh',
+ 'label',
+ 'create',
+ name,
+ '--color',
+ color,
+ '--description',
+ description,
+ '--force',
+ '--repo',
+ repo,
+ ],
+ dry_run=dry_run,
+ )
+ print(f'Upsert label: {name!r}')
+
+
+def upsert_group(
+ repo: str,
+ prefix: str,
+ color: str,
+ items: Iterable[tuple[str, str]],
+ *,
+ dry_run: bool,
+) -> None:
+ for short, desc in items:
+ upsert_label(
+ repo,
+ f'[{prefix}] {short}',
+ color,
+ desc,
+ dry_run=dry_run,
+ )
+
+
+# --- Main -----------------------------------------------------------------------
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(description='Sync GitHub labels for easyscience repos')
+ parser.add_argument(
+ '--repo',
+ help='Target repository in the form easyscience/',
+ )
+ parser.add_argument(
+ '--dry-run',
+ action='store_true',
+ help='Print actions without applying changes',
+ )
+ args = parser.parse_args()
+
+ if args.repo:
+ repo = args.repo
+ else:
+ repo = get_current_repo_name_with_owner()
+
+ org, _ = repo.split('/', 1)
+
+ if org.lower() != EASYSCIENCE_ORG:
+ print(
+ f"Refusing to run: repository {repo!r} is not under '{EASYSCIENCE_ORG}'.",
+ file=sys.stderr,
+ )
+ return 2
+
+ print(f'Target repository: {repo}')
+ if args.dry_run:
+ print('Running in DRY-RUN mode (no changes will be made)\n')
+
+ # 1) Rename basic labels
+ for old, new in zip(BASIC_GITHUB_LABELS, NEW_BASIC_LABEL_NAMES, strict=True):
+ try_rename_label(repo, old, new, dry_run=args.dry_run)
+
+ # 2) Scope / Maintainer / Priority groups
+ upsert_group(repo, 'scope', COLORS['scope'], SCOPE_LABELS, dry_run=args.dry_run)
+ upsert_group(repo, 'maintainer', COLORS['maintainer'], MAINTAINER_LABELS, dry_run=args.dry_run)
+ upsert_group(repo, 'priority', COLORS['priority'], PRIORITY_LABELS, dry_run=args.dry_run)
+
+ # 3) Bot label
+ upsert_label(
+ repo,
+ BOT_LABEL[0],
+ COLORS['bot'],
+ BOT_LABEL[1],
+ dry_run=args.dry_run,
+ )
+
+ print('\nDone.')
+ return 0
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())
From 9a624d6c6e70a2f406ca13b179d0b3c68047509e Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 14:30:13 +0100
Subject: [PATCH 3/7] pixi run fix-all
---
README.md | 6 ++----
docs/docs/installation-and-setup/index.md | 4 ++--
docs/docs/introduction/index.md | 3 ++-
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index d0bddc0..373d382 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,11 @@
-**EasyDynamics** is a scientific software for plotting and fitting QENS and INS powder data.
+**EasyDynamics** is a scientific software for plotting and fitting QENS
+and INS powder data.
-
**EasyDynamics** is available both as a Python library and as a
cross-platform desktop application.
@@ -40,5 +40,3 @@ Here, we focus on the Python library. For the graphical user interface
- ๐งโ๐ป [Source Code](https://github.com/easyscience/dynamics-lib)
- โ๏ธ
[License](https://raw.githubusercontent.com/easyscience/dynamics-lib/refs/heads/master/LICENSE)
-
-
diff --git a/docs/docs/installation-and-setup/index.md b/docs/docs/installation-and-setup/index.md
index 18dd951..420ef07 100644
--- a/docs/docs/installation-and-setup/index.md
+++ b/docs/docs/installation-and-setup/index.md
@@ -8,8 +8,8 @@ icon: material/cog-box
**Python 3.11** through **3.12**.
To install and set up EasyDynamics, we recommend using
-[**Pixi**](https://pixi.prefix.dev), a modern package manager for Windows,
-macOS, and Linux.
+[**Pixi**](https://pixi.prefix.dev), a modern package manager for
+Windows, macOS, and Linux.
!!! note "Main benefits of using Pixi"
diff --git a/docs/docs/introduction/index.md b/docs/docs/introduction/index.md
index 606ed6c..740d4b0 100644
--- a/docs/docs/introduction/index.md
+++ b/docs/docs/introduction/index.md
@@ -6,7 +6,8 @@ icon: material/information-slab-circle
## Description
-**EasyDynamics** is a scientific software for plotting and fitting QENS and INS powder data.
+**EasyDynamics** is a scientific software for plotting and fitting QENS
+and INS powder data.
**EasyDynamics** is available both as a Python library and as a
cross-platform desktop application.
From f057aafb5c4e936cbd8289a9d546f3c1737d36fe Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 16:22:16 +0100
Subject: [PATCH 4/7] Switch to manual pre-commit and simplify tasks
---
.copier-answers.yml | 2 +-
.pre-commit-config.yaml | 56 +++++++++-----------
pixi.toml | 31 ++----------
tools/nonpy_prettier_modified.py | 87 --------------------------------
4 files changed, 29 insertions(+), 147 deletions(-)
delete mode 100644 tools/nonpy_prettier_modified.py
diff --git a/.copier-answers.yml b/.copier-answers.yml
index e644aa9..4ce55e6 100644
--- a/.copier-answers.yml
+++ b/.copier-answers.yml
@@ -1,6 +1,6 @@
# WARNING: Do not edit this file manually.
# Any changes will be overwritten by Copier.
-_commit: v0.4.0
+_commit: v0.4.0-1-g365bd05
_src_path: gh:easyscience/templates
app_docs_url: https://easyscience.github.io/dynamics-app
app_doi: 10.5281/zenodo.18163581
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 262cd4f..007d238 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,60 +1,54 @@
repos:
- repo: local
hooks:
- # -----------------
- # Pre-commit checks
- # -----------------
+ # -------------
+ # Manual checks
+ # -------------
- id: pixi-pyproject-check
name: pixi run pyproject-check
entry: pixi run pyproject-check
language: system
pass_filenames: false
- stages: [pre-commit]
+ stages: [manual]
- id: pixi-py-lint-check
- name: pixi run py-lint-check-pre STAGED_FILES
- entry: pixi run py-lint-check-pre
+ name: pixi run py-lint-check
+ entry: pixi run py-lint-check
language: system
- pass_filenames: true
- files: ^(src/|tests/|docs/docs/tutorials/).*\.py$
- stages: [pre-commit]
+ pass_filenames: false
+ stages: [manual]
- id: pixi-py-format-check
- name: pixi run py-format-check-pre STAGED_FILES
- entry: pixi run py-format-check-pre
+ name: pixi run py-format-check
+ entry: pixi run py-format-check
language: system
- pass_filenames: true
- files: ^(src/|tests/|docs/docs/tutorials/).*\.py$
- stages: [pre-commit]
+ pass_filenames: false
+ stages: [manual]
- id: pixi-nonpy-format-check
- name: pixi run nonpy-format-check-pre STAGED_FILES
- entry: pixi run nonpy-format-check-pre
+ name: pixi run nonpy-format-check
+ entry: pixi run nonpy-format-check
language: system
- pass_filenames: true
- stages: [pre-commit]
+ pass_filenames: false
+ stages: [manual]
- id: pixi-docs-format-check
- name: pixi run docs-format-check-pre STAGED_FILES
- entry: pixi run docs-format-check-pre
+ name: pixi run docs-format-check
+ entry: pixi run docs-format-check
language: system
- pass_filenames: true
- files: ^(src/|docs/docs/tutorials/).*\.py$
- stages: [pre-commit]
+ pass_filenames: false
+ stages: [manual]
- # ----------------
- # Pre-push checks
- # ----------------
- - id: pixi-nonpy-format-check
- name: pixi run nonpy-format-check
- entry: pixi run nonpy-format-check
+ - id: pixi-notebook-format-check
+ name: pixi run notebook-format-check
+ entry: pixi run notebook-format-check
language: system
pass_filenames: false
- stages: [pre-push]
+ stages: [manual]
- id: pixi-unit-tests
name: pixi run unit-tests
entry: pixi run unit-tests
language: system
pass_filenames: false
- stages: [pre-push]
+ stages: [manual]
diff --git a/pixi.toml b/pixi.toml
index befe237..d280c25 100644
--- a/pixi.toml
+++ b/pixi.toml
@@ -99,12 +99,7 @@ py-format-check = "ruff format --check src/ tests/ docs/docs/tutorials/"
nonpy-format-check = "npx prettier --list-different --config=prettierrc.toml --ignore-unknown ."
nonpy-format-check-modified = "python tools/nonpy_prettier_modified.py"
-check = { depends-on = [
- 'py-format-check',
- 'docs-format-check',
- 'py-lint-check',
- 'nonpy-format-check-modified',
-] }
+check = 'pre-commit run --hook-stage manual --all-files'
##########
# ๐ ๏ธ Fixes
@@ -119,18 +114,11 @@ nonpy-format-fix-modified = "python tools/nonpy_prettier_modified.py --write"
success-message-fix = 'echo "โ
All code auto-formatting steps have been applied."'
fix = { depends-on = [
- 'py-format-fix',
- 'docs-format-fix',
- 'py-lint-fix',
- 'nonpy-format-fix-modified',
- 'success-message-fix',
-] }
-
-fix-all = { depends-on = [
'py-format-fix',
'docs-format-fix',
'py-lint-fix',
'nonpy-format-fix',
+ 'notebook-format-fix',
'success-message-fix',
] }
@@ -202,19 +190,6 @@ copier-update = "copier update --data-file ../dynamics/.copier-answers.yml --dat
# ๐ช Pre-commit Hooks
#####################
-# Pre-commit hook commands (to be used in .pre-commit-config.yaml)
-py-lint-check-pre = 'ruff check'
-py-format-check-pre = "ruff format --check"
-nonpy-format-check-pre = "npx prettier --list-different --config=prettierrc.toml --ignore-unknown"
-docs-format-check-pre = 'docformatter --check'
-
-# Run like a real commit: staged files only (almost)
-pre-commit-check = 'pre-commit run --hook-stage pre-commit'
-# CI check: lint/format everything
-pre-commit-check-all = 'pre-commit run --all-files --hook-stage pre-commit'
-# Pre-push check: lint/format everything
-pre-push-check = 'pre-commit run --all-files --hook-stage pre-push'
-
pre-commit-clean = 'pre-commit clean'
pre-commit-install = 'pre-commit install --hook-type pre-commit --hook-type pre-push --overwrite'
pre-commit-uninstall = 'pre-commit uninstall --hook-type pre-commit --hook-type pre-push'
@@ -242,7 +217,7 @@ spdx-update = 'python tools/update_spdx.py'
post-install = { depends-on = [
'npm-config',
'prettier-install',
- 'pre-commit-setup',
+ #'pre-commit-setup',
] }
##########################
diff --git a/tools/nonpy_prettier_modified.py b/tools/nonpy_prettier_modified.py
deleted file mode 100644
index 81805e3..0000000
--- a/tools/nonpy_prettier_modified.py
+++ /dev/null
@@ -1,87 +0,0 @@
-from __future__ import annotations
-
-import shutil
-import subprocess
-import sys
-
-
-def get_stdout_lines(cmd: list[str]) -> list[str]:
- """Execute a command and return its standard output as a list of
- non-empty lines.
-
- The command is executed with `check=True`, so a non-zero exit code
- will raise `subprocess.CalledProcessError`.
-
- Args:
- cmd: Command and arguments to execute, as a list of strings.
-
- Returns:
- A list of stripped, non-empty lines from the command's stdout.
- """
- result = subprocess.run(
- cmd,
- capture_output=True,
- text=True,
- encoding='utf-8',
- check=True,
- )
- return [line.strip() for line in result.stdout.splitlines() if line.strip()]
-
-
-def main() -> int:
- """Run Prettier on modified or newly added non-Python files in the
- Git repository.
-
- The file list is constructed from:
- - tracked files that are added or modified (staged or unstaged)
- - untracked files that are not ignored by Git
-
- Prettier is always run with `--list-different`.
- If `--write` is provided as a command-line argument, files are fixed
- in place in addition to being listed.
-
- Returns:
- Exit code of the Prettier process, or 0 if there are no files to
- process.
- """
- # Tracked added/modified (staged or not)
- files = get_stdout_lines(['git', 'diff', '--name-only', '--diff-filter=AM', 'HEAD'])
-
- # Untracked new files
- files += get_stdout_lines(['git', 'ls-files', '--others', '--exclude-standard'])
-
- if not files:
- return 0 # nothing to do
-
- # Locate npx executable (npx.cmd on Windows)
- npx = shutil.which('npx') or shutil.which('npx.cmd')
- if not npx:
- print('ERROR: npx not found in PATH', file=sys.stderr)
- return 2
-
- # Windows requires running .cmd files via the shell
- need_shell = npx.lower().endswith('.cmd')
-
- cmd = [
- npx,
- 'prettier',
- '--list-different',
- ]
-
- # Optionally enable fixing
- if '--write' in sys.argv:
- cmd.append('--write')
-
- cmd += [
- '--ignore-unknown',
- '--config=prettierrc.toml',
- '--',
- *files,
- ]
-
- proc = subprocess.run(cmd, shell=need_shell)
- return proc.returncode
-
-
-if __name__ == '__main__':
- raise SystemExit(main())
From 93d1e0eda880502207e6e9a82fe89a47d2da08bb Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 22:21:58 +0100
Subject: [PATCH 5/7] Enable PyPI Trusted Publishing via OIDC
---
.copier-answers.yml | 2 +-
.github/actions/publish-to-pypi/action.yml | 11 ++++++-----
.github/workflows/pypi-publish.yml | 16 ++++++++++++++--
3 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/.copier-answers.yml b/.copier-answers.yml
index 4ce55e6..eeff466 100644
--- a/.copier-answers.yml
+++ b/.copier-answers.yml
@@ -1,6 +1,6 @@
# WARNING: Do not edit this file manually.
# Any changes will be overwritten by Copier.
-_commit: v0.4.0-1-g365bd05
+_commit: v0.4.2
_src_path: gh:easyscience/templates
app_docs_url: https://easyscience.github.io/dynamics-app
app_doi: 10.5281/zenodo.18163581
diff --git a/.github/actions/publish-to-pypi/action.yml b/.github/actions/publish-to-pypi/action.yml
index 522e3a0..719928d 100644
--- a/.github/actions/publish-to-pypi/action.yml
+++ b/.github/actions/publish-to-pypi/action.yml
@@ -1,13 +1,14 @@
name: 'Publish to PyPI'
-description: 'Publish a built distribution to PyPI using pypa/gh-action-pypi-publish'
+description: 'Publish dist/ to PyPI via Trusted Publishing (OIDC)'
inputs:
- password:
- description: 'PyPI API token (or password) for authentication'
- required: true
+ packages_dir:
+ description: 'Directory containing the built packages to upload'
+ required: false
+ default: 'dist'
runs:
using: 'composite'
steps:
- uses: pypa/gh-action-pypi-publish@release/v1
with:
- password: ${{ inputs.password }}
+ packages-dir: ${{ inputs.packages_dir }}
diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml
index 15a2c6e..6e48e61 100644
--- a/.github/workflows/pypi-publish.yml
+++ b/.github/workflows/pypi-publish.yml
@@ -14,6 +14,10 @@ jobs:
pypi-publish:
runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
+
steps:
- name: Check-out repository
uses: actions/checkout@v5
@@ -23,10 +27,18 @@ jobs:
- name: Set up pixi
uses: ./.github/actions/setup-pixi
+ # Build the Python package (to dist/ folder)
- name: Create Python package
run: pixi run default-build
+ # Publish the package to PyPI (from dist/ folder)
+ # Instead of publishing with personal access token, we use
+ # GitHub Actions OIDC to get a short-lived token from PyPI.
+ # New publisher must be previously configured in PyPI at
+ # https://pypi.org/manage/project/easydynamics/settings/publishing/
+ # Use the following data:
+ # Owner: easyscience
+ # Repository name: dynamics-lib
+ # Workflow name: pypi-publish.yml
- name: Publish to PyPI
uses: ./.github/actions/publish-to-pypi
- with:
- password: ${{ secrets.PYPI_PASSWORD }}
From ff11076793aff4403a67192780618f7d0dab0d30 Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 22:26:12 +0100
Subject: [PATCH 6/7] Reorder imports and widget magic in notebooks
---
docs/docs/tutorials/components.ipynb | 3 +--
docs/docs/tutorials/detailed_balance.ipynb | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/docs/docs/tutorials/components.ipynb b/docs/docs/tutorials/components.ipynb
index 7815bcd..83278fc 100644
--- a/docs/docs/tutorials/components.ipynb
+++ b/docs/docs/tutorials/components.ipynb
@@ -21,6 +21,7 @@
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
+ "import scipp as sc\n",
"\n",
"from easydynamics.sample_model import DampedHarmonicOscillator\n",
"from easydynamics.sample_model import DeltaFunction\n",
@@ -105,8 +106,6 @@
"metadata": {},
"outputs": [],
"source": [
- "import scipp as sc\n",
- "\n",
"x1 = sc.linspace(dim='x', start=-2.0, stop=2.0, num=100, unit='meV')\n",
"x2 = sc.linspace(dim='x', start=-2.0 * 1e3, stop=2.0 * 1e3, num=101, unit='microeV')\n",
"\n",
diff --git a/docs/docs/tutorials/detailed_balance.ipynb b/docs/docs/tutorials/detailed_balance.ipynb
index d09a254..135894d 100644
--- a/docs/docs/tutorials/detailed_balance.ipynb
+++ b/docs/docs/tutorials/detailed_balance.ipynb
@@ -23,11 +23,11 @@
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
- "\n",
- "%matplotlib widget\n",
"import numpy as np\n",
"\n",
- "from easydynamics.utils import _detailed_balance_factor as detailed_balance_factor"
+ "from easydynamics.utils import _detailed_balance_factor as detailed_balance_factor\n",
+ "\n",
+ "%matplotlib widget"
]
},
{
From 43b19bfcae80c6cae014a82521e7c4d6f3d8b717 Mon Sep 17 00:00:00 2001
From: Andrew Sazonov
Date: Thu, 5 Feb 2026 22:26:41 +0100
Subject: [PATCH 7/7] Normalize notebook cell IDs
---
docs/docs/tutorials/diffusion_model.ipynb | 2 +-
docs/docs/tutorials/experiment.ipynb | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/docs/docs/tutorials/diffusion_model.ipynb b/docs/docs/tutorials/diffusion_model.ipynb
index 9277486..44d2bb3 100644
--- a/docs/docs/tutorials/diffusion_model.ipynb
+++ b/docs/docs/tutorials/diffusion_model.ipynb
@@ -69,7 +69,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "a50c67ec",
+ "id": "3",
"metadata": {},
"outputs": [],
"source": [
diff --git a/docs/docs/tutorials/experiment.ipynb b/docs/docs/tutorials/experiment.ipynb
index 6319c61..f6e185d 100644
--- a/docs/docs/tutorials/experiment.ipynb
+++ b/docs/docs/tutorials/experiment.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "906b959a",
+ "id": "0",
"metadata": {},
"source": [
"# Experiment\n",
@@ -12,7 +12,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "c7d23add",
+ "id": "1",
"metadata": {},
"outputs": [],
"source": [
@@ -24,7 +24,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "2b7c5ca8",
+ "id": "2",
"metadata": {},
"outputs": [],
"source": [
@@ -38,7 +38,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "238ba6ee",
+ "id": "3",
"metadata": {},
"outputs": [],
"source": [
@@ -50,7 +50,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "bc32ab1f",
+ "id": "4",
"metadata": {},
"outputs": [],
"source": [