diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 75d29dff..fa94cd7f 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -34,8 +34,8 @@ jobs: run: poetry install -v - name: Display installed dependency versions run: poetry run pip list - - name: Run unit tests and code coverage - run: poetry run pytest ./tests/unit -v --cov=nitypes --junitxml=test_results/nitypes-${{ matrix.os }}-py${{ matrix.python-version }}.xml + - name: Run unit/acceptance/doc tests and code coverage + run: poetry run pytest -v --cov=nitypes --junitxml=test_results/nitypes-${{ matrix.os }}-py${{ matrix.python-version }}.xml - name: Run benchmarks run: poetry run pytest ./tests/benchmark -v --junitxml=test_results/nitypes-benchmarks-${{ matrix.os }}-py${{ matrix.python-version }}.xml - name: Upload test results diff --git a/poetry.lock b/poetry.lock index 61ede3aa..b1a6a330 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "alabaster" @@ -1716,15 +1716,15 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests [[package]] name = "pytest" -version = "9.0.1" +version = "9.0.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.10" groups = ["test"] markers = "python_version >= \"3.10\"" files = [ - {file = "pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad"}, - {file = "pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8"}, + {file = "pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b"}, + {file = "pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11"}, ] [package.dependencies] diff --git a/src/nitypes/_arguments.py b/src/nitypes/_arguments.py index 948b729a..aa5bd138 100644 --- a/src/nitypes/_arguments.py +++ b/src/nitypes/_arguments.py @@ -14,10 +14,6 @@ ) from nitypes._numpy import isdtype as _np_isdtype -# Some of these doctests use types introduced in NumPy 2.0 (np.long and np.ulong) or highlight -# formatting differences between NumPy 1.x and 2.x (e.g. dtype=int32, 1.23 vs. np.float64(1.23)). -__doctest_requires__ = {("arg_to_float", "is_dtype", "validate_dtype"): ["numpy>=2.0"]} - def arg_to_float( arg_description: str, value: SupportsFloat | None, default_value: float | None = None @@ -143,6 +139,17 @@ def is_dtype(dtype: npt.DTypeLike, supported_dtypes: tuple[npt.DTypeLike, ...]) Unlike :any:`numpy.isdtype`, this function supports structured data types. + # Some of these doctests use types introduced in NumPy 2.0 (np.long and np.ulong) or highlight + # formatting differences between NumPy 1.x and 2.x (e.g. dtype=int32, 1.23 vs. + # np.float64(1.23)). + # We use inline version checks instead of __doctest_requires__ due to a pytest-doctestplus 1.6.0 + # bug that doesn't properly parse version requirements like "numpy>=2.0". + # This check may exist in multiple places in the code. If you are making changes, you + # probably need them in every location. + # TODO: Remove these version checks when NumPy < 2.0 compatibility is no longer required. + >>> import numpy as np; import pytest + >>> version_tuple = tuple(map(int, np.__version__.split('.')[:2])) + >>> if version_tuple < (2, 0): pytest.skip("requires numpy>=2.0") >>> is_dtype(np.float64, (np.float64, np.intc, np.long,)) True >>> is_dtype("float64", (np.float64, np.intc, np.long,)) @@ -172,6 +179,17 @@ def is_dtype(dtype: npt.DTypeLike, supported_dtypes: tuple[npt.DTypeLike, ...]) def validate_dtype(dtype: npt.DTypeLike, supported_dtypes: tuple[npt.DTypeLike, ...]) -> None: """Validate a dtype-like object against a tuple of supported dtype-like objects. + # Some of these doctests use types introduced in NumPy 2.0 (np.long and np.ulong) or highlight + # formatting differences between NumPy 1.x and 2.x (e.g. dtype=int32, 1.23 vs. + # np.float64(1.23)). + # We use inline version checks instead of __doctest_requires__ due to a pytest-doctestplus 1.6.0 + # bug that doesn't properly parse version requirements like "numpy>=2.0". + # This check may exist in multiple places in the code. If you are making changes, you + # probably need them in every location. + # TODO: Remove these version checks when NumPy < 2.0 compatibility is no longer required. + >>> import numpy as np; import pytest + >>> version_tuple = tuple(map(int, np.__version__.split('.')[:2])) + >>> if version_tuple < (2, 0): pytest.skip("requires numpy>=2.0") >>> validate_dtype(np.float64, (np.float64, np.intc, np.long,)) >>> validate_dtype("float64", (np.float64, np.intc, np.long,)) >>> validate_dtype(np.float64, (np.byte, np.short, np.intc, np.int_, np.long, np.longlong)) diff --git a/src/nitypes/complex/__init__.py b/src/nitypes/complex/__init__.py index e904f485..f9234dcc 100644 --- a/src/nitypes/complex/__init__.py +++ b/src/nitypes/complex/__init__.py @@ -27,7 +27,15 @@ You can construct an array of complex integers from a sequence of tuples using :func:`numpy.array`: ->>> import numpy as np +# Some of these doctests use types introduced in NumPy 2.0 (np.long and np.ulong) or highlight +# formatting differences between NumPy 1.x and 2.x (e.g. dtype=int32, 1.23 vs. np.float64(1.23)). +# We use inline version checks instead of __doctest_requires__ due to a pytest-doctestplus 1.6.0 +# bug that doesn't properly parse version requirements like "numpy>=2.0". +# This check may exist in multiple places in the code. If you are making changes, you +# probably need them in every location. +# TODO: Remove these version checks when NumPy < 2.0 compatibility is no longer required. +>>> import numpy as np; import pytest +>>> if tuple(map(int, np.__version__.split('.')[:2])) < (2, 0): pytest.skip("requires numpy>=2.0") >>> np.array([(1, 2), (3, 4)], dtype=ComplexInt32DType) array([(1, 2), (3, 4)], dtype=[('real', '=2.0"]} diff --git a/src/nitypes/waveform/_digital/_port.py b/src/nitypes/waveform/_digital/_port.py index c02070b6..938a874a 100644 --- a/src/nitypes/waveform/_digital/_port.py +++ b/src/nitypes/waveform/_digital/_port.py @@ -147,7 +147,7 @@ def _mask_to_column_indices( [8] >>> _mask_to_column_indices(0xDEADBEEF, 32, "little") [0, 1, 2, 3, 5, 6, 7, 9, 10, 11, 12, 13, 15, 16, 18, 19, 21, 23, 25, 26, 27, 28, 30, 31] - >>> _mask_to_column_indices(-1, 8) + >>> _mask_to_column_indices(-1, 8, "little") Traceback (most recent call last): ... ValueError: The mask must be a non-negative integer. diff --git a/src/nitypes/waveform/_digital/_waveform.py b/src/nitypes/waveform/_digital/_waveform.py index 7d542148..fca60948 100644 --- a/src/nitypes/waveform/_digital/_waveform.py +++ b/src/nitypes/waveform/_digital/_waveform.py @@ -273,10 +273,10 @@ class DigitalWaveform(Generic[TDigitalState]): and the digital state from the actual and expected waveforms: >>> result.failures[0] # doctest: +NORMALIZE_WHITESPACE - DigitalWaveformFailure(sample_index=0, expected_sample_index=0, signal_index=0, column_index=1, + DigitalWaveformFailure(sample_index=0, expected_sample_index=0, signal_index=0, actual_state=, expected_state=) >>> result.failures[1] # doctest: +NORMALIZE_WHITESPACE - DigitalWaveformFailure(sample_index=1, expected_sample_index=1, signal_index=0, column_index=1, + DigitalWaveformFailure(sample_index=1, expected_sample_index=1, signal_index=0, actual_state=, expected_state=) Timing information