diff --git a/.gitignore b/.gitignore index d3acf13..b4a8eaf 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ coverage.xml *.cover .hypothesis/ .pytest_cache/ +prof/ # Translations *.mo diff --git a/gemd/__version__.py b/gemd/__version__.py index 8a124bf..b19ee4b 100644 --- a/gemd/__version__.py +++ b/gemd/__version__.py @@ -1 +1 @@ -__version__ = "2.2.0" +__version__ = "2.2.1" diff --git a/gemd/demo/cake.py b/gemd/demo/cake.py index 8586dac..794744f 100644 --- a/gemd/demo/cake.py +++ b/gemd/demo/cake.py @@ -1,5 +1,5 @@ """Bake a cake.""" -from importlib_resources import files +from importlib.resources import files from io import BytesIO import random diff --git a/gemd/demo/strehlow_and_cook.py b/gemd/demo/strehlow_and_cook.py index 11e1035..fe8f662 100644 --- a/gemd/demo/strehlow_and_cook.py +++ b/gemd/demo/strehlow_and_cook.py @@ -45,7 +45,7 @@ def import_table(filename=SMALL_TABLE): """Return the deserialized JSON table.""" - from importlib_resources import files + from importlib.resources import files import json return json.loads(files("gemd.demo").joinpath(filename).read_text(encoding='utf-8')) diff --git a/gemd/units/impl.py b/gemd/units/impl.py index dfdccf7..0815d9c 100644 --- a/gemd/units/impl.py +++ b/gemd/units/impl.py @@ -1,23 +1,25 @@ """Implementation of units.""" from deprecation import deprecated import functools -from importlib_resources import files +from importlib.resources import files import os from pathlib import Path import re from tempfile import TemporaryDirectory from typing import Union, List, Tuple, Generator, Any +try: + from typing import TypeAlias # Python 3.10+ +except ImportError: # pragma nocover + from typing_extensions import TypeAlias # Python 3.9 from pint import UnitRegistry, register_unit_format -try: # Pint 0.23 migrated the location of this method, and augmented it - from pint.pint_eval import tokenizer -except ImportError: # pragma: no cover - from pint.compat import tokenizer +from pint.pint_eval import tokenizer from tokenize import NAME, NUMBER, OP, ERRORTOKEN, TokenInfo # alias the error that is thrown when units are incompatible # this helps to isolate the dependence on pint -from pint.errors import DimensionalityError as IncompatibleUnitsError # noqa Import -from pint.errors import UndefinedUnitError, DefinitionSyntaxError # noqa Import +from pint.errors import DimensionalityError as IncompatibleUnitsError +from pint.errors import UndefinedUnitError, DefinitionSyntaxError +from pint.registry import GenericUnitRegistry # Store directories so they don't get auto-cleaned until exit _TEMP_DIRECTORY = TemporaryDirectory() @@ -216,43 +218,29 @@ def _unmangle_scaling(input_string: str) -> str: return input_string -try: # pragma: no cover - # Pint 0.23 modified the preferred way to derive a custom class - # https://pint.readthedocs.io/en/0.23/advanced/custom-registry-class.html - from pint.registry import GenericUnitRegistry - from typing_extensions import TypeAlias +# Standard approach to creating a custom registry class: +# https://pint.readthedocs.io/en/0.23/advanced/custom-registry-class.html - class _ScaleFactorUnit(UnitRegistry.Unit): - """Child class of Units for generating units w/ clean scaling factors.""" +class _ScaleFactorUnit(UnitRegistry.Unit): + """Child class of Units for generating units w/ clean scaling factors.""" - def __format__(self, format_spec): - result = super().__format__(format_spec) - return _unmangle_scaling(result) + def __format__(self, format_spec): + result = super().__format__(format_spec) + return _unmangle_scaling(result) - class _ScaleFactorQuantity(UnitRegistry.Quantity): - """Child class of Quantity for generating units w/ clean scaling factors.""" - pass - - class _ScaleFactorRegistry(GenericUnitRegistry[_ScaleFactorQuantity, _ScaleFactorUnit]): - """UnitRegistry class that uses _GemdUnits.""" +class _ScaleFactorQuantity(UnitRegistry.Quantity): + """Child class of Quantity for generating units w/ clean scaling factors.""" - Quantity: TypeAlias = _ScaleFactorQuantity - Unit: TypeAlias = _ScaleFactorUnit + pass -except ImportError: # pragma: no cover - # https://pint.readthedocs.io/en/0.21/advanced/custom-registry-class.html - class _ScaleFactorUnit(UnitRegistry.Unit): - """Child class of Units for generating units w/ clean scaling factors.""" - def __format__(self, format_spec): - result = super().__format__(format_spec) - return _unmangle_scaling(result) +class _ScaleFactorRegistry(GenericUnitRegistry[_ScaleFactorQuantity, _ScaleFactorUnit]): + """UnitRegistry class that uses _GemdUnits.""" - class _ScaleFactorRegistry(UnitRegistry): - """UnitRegistry class that uses _GemdUnits.""" + Quantity: TypeAlias = _ScaleFactorQuantity + Unit: TypeAlias = _ScaleFactorUnit - _unit_class = _ScaleFactorUnit _REGISTRY: _ScaleFactorRegistry = None # global requires it be defined in this scope diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bea72a3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,73 @@ +[project] +name = "gemd" +dynamic = ["version"] +dependencies = [ + "pint>=0.24.4,<0.25", + "deprecation>=2.1.0,<3", + "typing_extensions>=4.8,<5; python_version<'3.10'", +] +requires-python = ">=3.9" +authors = [ + {name = "Citrine Informatics"} +] +description = "Python binding for Citrine's GEMD data model" +readme = "README.md" +license-files = ["LICENSE"] +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] + +[project.urls] +Homepage = "http://github.com/CitrineInformatics/gemd-python" + +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.dynamic] +version = {attr = "gemd.__version__.__version__"} + +[tool.setuptools.packages.find] +where = ["."] +include = ["gemd"] +exclude = ["docs", "tests"] + +[tool.setuptools.package-data] +"gemd.demo" = ["strehlow_and_cook.pif", "strehlow_and_cook_small.pif", "toothpick.jpg"] +"gemd.units" = ["citrine_en.txt", "constants_en.txt"] +"tests.units" = ["test_units.txt"] + + +[dependency-groups] +dev = [ + "flake8==7.0.0", + "flake8-docstrings==1.7.0", + "numpy==1.24.4; python_version<'3.10'", + "pandas==2.0.3; python_version<'3.10'", + "numpy>=2.0.2,<=2.1.0; python_version>='3.10'", + "pandas==2.3.0; python_version>='3.10'", + "pytest==8.4.2", + "pytest-cov==7.0.0", + "derp==0.1.1", + "tomli>=2.2.1", +] +docs = [ + "sphinx==5.0.0", + "sphinx-rtd-theme==1.0.0", + "sphinxcontrib-apidoc==0.3.0", +] + +[tool.pytest.ini_options] +testpaths = [ + "tests", +] + +[tool.coverage.run] +omit = [ + "gemd/demo/*", +] diff --git a/requirements.txt b/requirements.txt index bc1d0b6..0af944d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ pint==0.24.4 deprecation==2.1.0 -typing-extensions==4.8.0 -importlib-resources==5.3.0 +typing_extensions>=4.8,<5; python_version<'3.10' diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index a44c40b..b24d9ee 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -36,8 +36,9 @@ then python $REPO_DIR/scripts/validate_version_bump.py || fi flake8 $REPO_DIR/gemd || exit 1; -derp $REPO_DIR $REPO_DIR/gemd/__version__.py || exit 1; +derp $REPO_DIR/gemd $REPO_DIR/gemd/__version__.py || exit 1; pytest $QUIET $EXITFIRST --cov=$REPO_DIR/gemd \ --cov-report term-missing:skip-covered \ - --cov-config=$REPO_DIR/tox.ini --no-cov-on-fail --cov-fail-under=100 \ + --cov-config=$REPO_DIR/pyproject.toml \ + --no-cov-on-fail --cov-fail-under=100 \ $REPO_DIR || exit 1; diff --git a/setup.py b/setup.py deleted file mode 100644 index cb33c7d..0000000 --- a/setup.py +++ /dev/null @@ -1,67 +0,0 @@ -from setuptools import setup, find_packages -from pathlib import Path -import re - -packages = find_packages() - -this_directory = Path(__file__).parent.absolute() -version_file = this_directory / 'gemd' / '__version__.py' -version_re = r'''^\s*__version__\s*=\s*(['"])([\w\.]+)\1$''' -if mo := re.search(version_re, version_file.read_text(), re.M): - version = mo.group(2) -else: - raise RuntimeError(f"Unable to find version string in {version_file}") - -setup(name='gemd', - # Update this in gemd/__version__.py - version=version, - python_requires='>=3.9', - url='http://github.com/CitrineInformatics/gemd-python', - description="Python binding for Citrine's GEMD data model", - author='Citrine Informatics', - packages=packages, - package_data={ - 'gemd.demo': [ - 'strehlow_and_cook.pif', - 'strehlow_and_cook_small.pif', - 'toothpick.jpg' - ], - 'gemd.units': [ - 'citrine_en.txt', - 'constants_en.txt', - ], - 'tests.units': ['test_units.txt'] - }, - install_requires=[ - "pint>=0.24.4,<0.25", - "deprecation>=2.1.0,<3", - "typing_extensions>=4.8,<5", - "importlib-resources>=5.3,<7" - ], - extras_require={ - "scripts": [ - "packaging", - "sphinx==5.0.0", - "sphinx-rtd-theme==1.0.0", - "sphinxcontrib-apidoc==0.3.0", - ], - "tests": [ - "pytest>=8.0.0,<9" - ], - "tests.demo": [ - "pandas>=2.0.3,<3" - ], - "tests.entity.bounds": [ - "numpy>=1.24.4,<2; python_version<='3.10'", - "pandas>=2.0.3,<3" - ] - }, - classifiers=[ - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - ], - ) diff --git a/test_requirements.txt b/test_requirements.txt index 0460dfc..c8f0654 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -4,6 +4,6 @@ numpy==1.24.4; python_version<'3.10' pandas==2.0.3; python_version<'3.10' numpy>=2.0.2,<=2.1.0; python_version>='3.10' pandas==2.3.0; python_version>='3.10' -pytest==8.0.0 -pytest-cov==4.1.0 +pytest==8.4.2 +pytest-cov==7.0.0 derp==0.1.1 diff --git a/tests/units/test_parser.py b/tests/units/test_parser.py index 3706399..ffcdeac 100644 --- a/tests/units/test_parser.py +++ b/tests/units/test_parser.py @@ -1,6 +1,6 @@ from contextlib import contextmanager from deprecation import DeprecatedWarning -from importlib_resources import files +from importlib.resources import files import re from pint import UnitRegistry import pytest diff --git a/tox.ini b/tox.ini index 1cd27cc..881efa9 100644 --- a/tox.ini +++ b/tox.ini @@ -11,8 +11,5 @@ max-doc-length = 119 # D401: Imperative mood requirement basically gets in the way ignore = D100,D104,D105,D107,D301,D401 -[pytest] -testpaths = tests - [run] -omit = gemd/demo/* +omit = gemd/demo/* \ No newline at end of file