diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5d98c258..b2d1b91c 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -6,12 +6,12 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: "3.10" - name: Install run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a72bee05..23fb29dc 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,12 +6,12 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: "3.10" - name: Install run: | diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 0c0e6ef6..ebc24701 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -6,12 +6,12 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: "3.10" - name: Install tools run: | diff --git a/.github/workflows/unit-test-pinned.yml b/.github/workflows/unit-test-pinned.yml index 246bff72..3d0e1c63 100644 --- a/.github/workflows/unit-test-pinned.yml +++ b/.github/workflows/unit-test-pinned.yml @@ -6,12 +6,12 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - - name: Set up Python 3.9 - uses: actions/setup-python@v5 + - name: Set up Python 3.10 + uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: "3.10" - name: Install pinned dependencies run: | diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 6a3f5a39..c78ffad4 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -6,14 +6,14 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} diff --git a/RELEASE.md b/RELEASE.md index d78ff39b..66c65a56 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1,8 @@ +# Release 0.3.8 +- Migrated to Pint >= 0.24 (the `ScaleConverter` and `UnitDefinition` classes moved to `pint.facets.plain` and changed argument signatures). This reverses the `Pint < 0.20` pin introduced in 0.3.5 and restores compatibility with numpy 2.x, which older Pint versions could not import. +- Added support for Python 3.14. +- Dropped support for Python 3.9 as Pint >= 0.24 requires Python >= 3.10. + # Release 0.3.7 - Added support for Python 3.12 and 3.13. - Dropped support for Python 3.6, 3.7 and 3.8 as they are at end of life. diff --git a/cellmlmanip/units.py b/cellmlmanip/units.py index a706c8a4..2fa25844 100644 --- a/cellmlmanip/units.py +++ b/cellmlmanip/units.py @@ -12,9 +12,9 @@ import pint import sympy -from pint.converters import ScaleConverter -from pint.definitions import UnitDefinition from pint.errors import DimensionalityError +from pint.facets.plain import ScaleConverter, UnitDefinition +from pint.util import UnitsContainer from . import model @@ -168,7 +168,9 @@ def add_unit(self, name, expression): # To test if this is a dimensionless unit, parse the string as a Quantity and check if it's dimensionless quantity = self._registry.parse_expression(expression) if quantity.units == self._registry.dimensionless: - definition = UnitDefinition(qname, '', (), ScaleConverter(quantity.to(self._registry.dimensionless))) + definition = UnitDefinition( + qname, None, (), ScaleConverter(quantity.to(self._registry.dimensionless).magnitude), + UnitsContainer()) else: definition = qname + '=' + expression diff --git a/cellmlmanip/version.txt b/cellmlmanip/version.txt index 0f826853..66784322 100644 --- a/cellmlmanip/version.txt +++ b/cellmlmanip/version.txt @@ -1 +1 @@ -0.3.7 +0.3.8 diff --git a/requirements/README.md b/requirements/README.md index c4e271e2..7a47eb81 100644 --- a/requirements/README.md +++ b/requirements/README.md @@ -3,6 +3,6 @@ This directory contains some 'pinned' dependencies used in testing. Users are **not** required to use these pinned versions of cellmlmanip's dependencies. -They are generated using Python 3.6, and are not expected to work with all other versions. +They are generated using Python 3.10, and are not expected to work with all other versions. To update, install `pip-tools`, and run `make`. diff --git a/requirements/base.in b/requirements/base.in index 72c3f449..bfe658df 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,5 +1,5 @@ lxml>=4.7 -pint>=0.9, <0.20 +pint>=0.24, <0.26 rdflib>=4 networkx>=2.1 sympy>=1.4, <1.13 diff --git a/requirements/base.txt b/requirements/base.txt index d109d5ab..3ec581cf 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,28 +1,33 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --output-file=base.txt base.in # -decorator==4.4.2 - # via networkx -isodate==0.6.0 +flexcache==0.3 + # via pint +flexparser==0.4 + # via pint +isodate==0.7.2 # via rdflib -lxml==5.3.0 +lxml==6.1.1 # via -r base.in -mpmath==1.1.0 +mpmath==1.3.0 # via sympy -networkx==2.5 +networkx==3.4.2 # via -r base.in -pint==0.19.2 +pint==0.24.4 # via -r base.in -pyparsing==2.4.7 +platformdirs==4.10.0 + # via pint +pyparsing==3.3.2 # via rdflib -rdflib==5.0.0 +rdflib==7.6.0 # via -r base.in -six==1.15.0 - # via - # isodate - # rdflib -sympy==1.7.1 +sympy==1.12.1 # via -r base.in +typing-extensions==4.16.0 + # via + # flexcache + # flexparser + # pint diff --git a/requirements/check-python-version.py b/requirements/check-python-version.py index 5f47d9e1..c16cb8c4 100755 --- a/requirements/check-python-version.py +++ b/requirements/check-python-version.py @@ -1,8 +1,8 @@ #!/usr/bin/env python import sys -if not (sys.version_info[0] == 3 and sys.version_info[1] == 6): +if not (sys.version_info[0] == 3 and sys.version_info[1] == 10): print( '\033[31mERROR\033[0m: ' - 'Pinned dependencies should only be set from Python 3.6', + 'Pinned dependencies should only be set from Python 3.10', file=sys.stderr) sys.exit(1) diff --git a/requirements/dev.txt b/requirements/dev.txt index 7b8991e6..4eb5f097 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,71 +1,93 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --output-file=dev.txt dev.in # -attrs==20.3.0 - # via pytest -click==7.1.2 +build==1.5.1 + # via pip-tools +click==8.4.2 # via pip-tools -coverage==5.4 +coverage[toml]==7.15.1 # via pytest-cov -decorator==4.4.2 - # via networkx -flake8==3.8.4 +exceptiongroup==1.3.1 + # via pytest +flake8==7.3.0 # via # -r dev.in # -r test.in -iniconfig==1.1.1 +flexcache==0.3 + # via pint +flexparser==0.4 + # via pint +iniconfig==2.3.0 # via pytest -isodate==0.6.0 +isodate==0.7.2 # via rdflib -isort==5.7.0 +isort==8.0.1 # via # -r dev.in # -r test.in -lxml==5.3.0 +lxml==6.1.1 # via -r base.in -mccabe==0.6.1 +mccabe==0.7.0 # via flake8 -mpmath==1.1.0 +mpmath==1.3.0 # via sympy -networkx==2.5 +networkx==3.4.2 # via -r base.in -packaging==20.8 - # via pytest -pint==0.19.2 +packaging==26.2 + # via + # build + # pytest + # wheel +pint==0.24.4 # via -r base.in -pip-tools==5.5.0 +pip-tools==7.5.3 # via -r dev.in -pluggy==0.13.1 - # via pytest -py==1.10.0 - # via pytest -pycodestyle==2.6.0 +platformdirs==4.10.0 + # via pint +pluggy==1.6.0 + # via + # pytest + # pytest-cov +pycodestyle==2.14.0 # via flake8 -pyflakes==2.2.0 +pyflakes==3.4.0 # via flake8 -pyparsing==2.4.7 +pygments==2.20.0 + # via pytest +pyparsing==3.3.2 + # via rdflib +pyproject-hooks==1.2.0 # via - # packaging - # rdflib -pytest==6.2.2 + # build + # pip-tools +pytest==9.1.1 # via # -r test.in # pytest-cov -pytest-cov==2.11.1 +pytest-cov==7.1.0 # via -r test.in -rdflib==5.0.0 +rdflib==7.6.0 # via -r base.in -six==1.15.0 - # via - # isodate - # rdflib -sympy==1.7.1 +sympy==1.12.1 # via -r base.in -toml==0.10.2 - # via pytest +tomli==2.4.1 + # via + # build + # coverage + # pip-tools + # pytest +typing-extensions==4.16.0 + # via + # exceptiongroup + # flexcache + # flexparser + # pint +wheel==0.47.0 + # via pip-tools # The following packages are considered to be unsafe in a requirements file: # pip +# setuptools diff --git a/requirements/test.txt b/requirements/test.txt index 2713dea2..63a91dd9 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,60 +1,68 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --output-file=test.txt test.in # -attrs==20.3.0 - # via pytest -coverage==5.4 +coverage[toml]==7.15.1 # via pytest-cov -decorator==4.4.2 - # via networkx -flake8==3.8.4 +exceptiongroup==1.3.1 + # via pytest +flake8==7.3.0 # via -r test.in -iniconfig==1.1.1 +flexcache==0.3 + # via pint +flexparser==0.4 + # via pint +iniconfig==2.3.0 # via pytest -isodate==0.6.0 +isodate==0.7.2 # via rdflib -isort==5.7.0 +isort==8.0.1 # via -r test.in -lxml==5.3.0 +lxml==6.1.1 # via -r base.in -mccabe==0.6.1 +mccabe==0.7.0 # via flake8 -mpmath==1.1.0 +mpmath==1.3.0 # via sympy -networkx==2.5 +networkx==3.4.2 # via -r base.in -packaging==20.8 +packaging==26.2 # via pytest -pint==0.19.2 +pint==0.24.4 # via -r base.in -pluggy==0.13.1 - # via pytest -py==1.10.0 - # via pytest -pycodestyle==2.6.0 +platformdirs==4.10.0 + # via pint +pluggy==1.6.0 + # via + # pytest + # pytest-cov +pycodestyle==2.14.0 # via flake8 -pyflakes==2.2.0 +pyflakes==3.4.0 # via flake8 -pyparsing==2.4.7 - # via - # packaging - # rdflib -pytest==6.2.2 +pygments==2.20.0 + # via pytest +pyparsing==3.3.2 + # via rdflib +pytest==9.1.1 # via # -r test.in # pytest-cov -pytest-cov==2.11.1 +pytest-cov==7.1.0 # via -r test.in -rdflib==5.0.0 +rdflib==7.6.0 # via -r base.in -six==1.15.0 - # via - # isodate - # rdflib -sympy==1.7.1 +sympy==1.12.1 # via -r base.in -toml==0.10.2 - # via pytest +tomli==2.4.1 + # via + # coverage + # pytest +typing-extensions==4.16.0 + # via + # exceptiongroup + # flexcache + # flexparser + # pint diff --git a/setup.py b/setup.py index 90951539..b97b0c91 100644 --- a/setup.py +++ b/setup.py @@ -22,17 +22,22 @@ url='https://github.com/ModellingWebLab/cellmlmanip', classifiers=[ 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', ], packages=find_packages(exclude=('tests', 'docs')), include_package_data=True, - python_requires='>=3.9', + python_requires='>=3.10', install_requires=[ 'lxml>=4.7', 'networkx>=2.1', - 'Pint>=0.9, <0.20', + 'Pint>=0.24, <0.26', 'rdflib>=4', 'sympy>=1.4, <1.13', ], diff --git a/tests/test_parser.py b/tests/test_parser.py index 7828a799..cd6c542f 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -193,7 +193,7 @@ def test_bad_connection_units(self): p.parse() match = ("Cannot convert from 'second' ([time]) to " - "'volt' ([length] ** 2 * [mass] / [current] / [time] ** 3)") + "'volt' ([mass] * [length] ** 2 / [time] ** 3 / [current])") assert match in str(dim_error.value)