Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/check_nitypes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,15 @@ jobs:
run: poetry run mypy --platform win32
- name: Bandit security checks
run: poetry run bandit -c pyproject.toml -r src/nitypes
- name: Add virtualenv to the path for pyright-action
run: echo "$(poetry env info --path)/bin" >> $GITHUB_PATH
- name: Pyright static analysis (Linux)
uses: jakebailey/pyright-action@v2
with:
python-platform: Linux
version: PATH
- name: Pyright static analysis (Windows)
uses: jakebailey/pyright-action@v2
with:
python-platform: Windows
version: PATH
52 changes: 51 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ typing-extensions = ">=4.13.2"
bandit = { version = ">=1.7", extras = ["toml"] }
ni-python-styleguide = ">=0.4.1"
mypy = ">=1.0"
pyright = { version = ">=1.1.400", extras = ["nodejs"] }

[tool.poetry.group.test.dependencies]
pytest = ">=7.2"
Expand Down Expand Up @@ -62,3 +63,6 @@ strict = true
skips = [
"B101", # assert_used
]

[tool.pyright]
include = ["src/", "tests/"]
32 changes: 18 additions & 14 deletions src/nitypes/waveform/_analog.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from collections.abc import Mapping, Sequence
from typing import Any, SupportsIndex, Union, overload
from typing import Any, SupportsIndex, Union, cast, overload

import numpy as np
import numpy.typing as npt
Expand Down Expand Up @@ -92,7 +92,7 @@ def from_array_1d(
def from_array_1d(
cls,
array: npt.NDArray[Any] | Sequence[Any],
dtype: type[_TRaw] | np.dtype[_TRaw] = ...,
dtype: type[_TRaw] | np.dtype[_TRaw],
*,
copy: bool = ...,
start_index: SupportsIndex | None = ...,
Expand All @@ -119,7 +119,7 @@ def from_array_1d(

@override
@classmethod
def from_array_1d(
def from_array_1d( # pyright: ignore[reportIncompatibleMethodOverride]
cls,
array: npt.NDArray[Any] | Sequence[Any],
dtype: npt.DTypeLike = None,
Expand Down Expand Up @@ -178,7 +178,7 @@ def from_array_2d(
def from_array_2d(
cls,
array: npt.NDArray[Any] | Sequence[Sequence[Any]],
dtype: type[_TRaw] | np.dtype[_TRaw] = ...,
dtype: type[_TRaw] | np.dtype[_TRaw],
*,
copy: bool = ...,
start_index: SupportsIndex | None = ...,
Expand All @@ -205,7 +205,7 @@ def from_array_2d(

@override
@classmethod
def from_array_2d(
def from_array_2d( # pyright: ignore[reportIncompatibleMethodOverride]
cls,
array: npt.NDArray[Any] | Sequence[Sequence[Any]],
dtype: npt.DTypeLike = None,
Expand Down Expand Up @@ -237,15 +237,19 @@ def from_array_2d(
information, and scale mode are applied to all waveforms. Consider assigning
these properties after construction.
"""
return super(AnalogWaveform, cls).from_array_2d(
array,
dtype,
copy=copy,
start_index=start_index,
sample_count=sample_count,
extended_properties=extended_properties,
timing=timing,
scale_mode=scale_mode,
# list[T] is invariant but we are using it in a covariant way here.
return cast(
list[AnalogWaveform[Any]],
super(AnalogWaveform, cls).from_array_2d(
array,
dtype,
copy=copy,
start_index=start_index,
sample_count=sample_count,
extended_properties=extended_properties,
timing=timing,
scale_mode=scale_mode,
),
)

__slots__ = ()
Expand Down
32 changes: 18 additions & 14 deletions src/nitypes/waveform/_complex.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from collections.abc import Mapping, Sequence
from typing import Any, SupportsIndex, Union, overload
from typing import Any, SupportsIndex, Union, cast, overload

import numpy as np
import numpy.typing as npt
Expand Down Expand Up @@ -80,7 +80,7 @@ def from_array_1d(
def from_array_1d(
cls,
array: npt.NDArray[Any] | Sequence[Any],
dtype: type[_TRaw] | np.dtype[_TRaw] = ...,
dtype: type[_TRaw] | np.dtype[_TRaw],
*,
copy: bool = ...,
start_index: SupportsIndex | None = ...,
Expand All @@ -107,7 +107,7 @@ def from_array_1d(

@override
@classmethod
def from_array_1d(
def from_array_1d( # pyright: ignore[reportIncompatibleMethodOverride]
cls,
array: npt.NDArray[Any] | Sequence[Any],
dtype: npt.DTypeLike = None,
Expand Down Expand Up @@ -166,7 +166,7 @@ def from_array_2d(
def from_array_2d(
cls,
array: npt.NDArray[Any] | Sequence[Sequence[Any]],
dtype: type[_TRaw] | np.dtype[_TRaw] = ...,
dtype: type[_TRaw] | np.dtype[_TRaw],
*,
copy: bool = ...,
start_index: SupportsIndex | None = ...,
Expand All @@ -193,7 +193,7 @@ def from_array_2d(

@override
@classmethod
def from_array_2d(
def from_array_2d( # pyright: ignore[reportIncompatibleMethodOverride]
cls,
array: npt.NDArray[Any] | Sequence[Sequence[Any]],
dtype: npt.DTypeLike = None,
Expand Down Expand Up @@ -225,15 +225,19 @@ def from_array_2d(
information, and scale mode are applied to all waveforms. Consider assigning
these properties after construction.
"""
return super(ComplexWaveform, cls).from_array_2d(
array,
dtype,
copy=copy,
start_index=start_index,
sample_count=sample_count,
extended_properties=extended_properties,
timing=timing,
scale_mode=scale_mode,
# list[T] is invariant but we are using it in a covariant way here.
return cast(
list[ComplexWaveform[Any]],
super(ComplexWaveform, cls).from_array_2d(
array,
dtype,
copy=copy,
start_index=start_index,
sample_count=sample_count,
extended_properties=extended_properties,
timing=timing,
scale_mode=scale_mode,
),
)

__slots__ = ()
Expand Down
6 changes: 3 additions & 3 deletions src/nitypes/waveform/_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ def get_scaled_data( # noqa: D107 - Missing docstring in __init__ (auto-generat
@overload
def get_scaled_data( # noqa: D107 - Missing docstring in __init__ (auto-generated noqa)
self,
dtype: type[_TOtherScaled] | np.dtype[_TOtherScaled] = ...,
dtype: type[_TOtherScaled] | np.dtype[_TOtherScaled],
*,
start_index: SupportsIndex | None = ...,
sample_count: SupportsIndex | None = ...,
Expand Down Expand Up @@ -546,12 +546,12 @@ def _get_timing(self, requested_type: type[_TTiming]) -> _TTiming:
self._converted_timing_cache[requested_type] = value
return value

def _set_timing(self, value: _TTiming) -> None:
def _set_timing(self, value: _AnyTiming) -> None:
if self._timing is not value:
self._timing = value
self._converted_timing_cache.clear()

def _validate_timing(self, value: _TTiming) -> None:
def _validate_timing(self, value: _AnyTiming) -> None:
if value._timestamps is not None and len(value._timestamps) != self._sample_count:
raise ValueError(
"The number of irregular timestamps is not equal to the number of samples in the waveform.\n\n"
Expand Down
27 changes: 15 additions & 12 deletions src/nitypes/waveform/_timing/_precision.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
from __future__ import annotations

from collections.abc import Sequence
from typing import ClassVar
from typing import ClassVar, final

import hightime as ht
from typing_extensions import override
from typing_extensions import Self, override

from nitypes.waveform._timing._base import BaseTiming
from nitypes.waveform._timing._sample_interval import SampleIntervalMode


@final
class PrecisionTiming(BaseTiming[ht.datetime, ht.timedelta]):
"""High-precision waveform timing using the hightime package.

Expand All @@ -24,27 +25,29 @@ class PrecisionTiming(BaseTiming[ht.datetime, ht.timedelta]):
"""A waveform timing object with no timestamp, time offset, or sample interval."""

@override
@staticmethod
@classmethod
def create_with_no_interval( # noqa: D102 - Missing docstring in public method - override
timestamp: ht.datetime | None = None, time_offset: ht.timedelta | None = None
) -> PrecisionTiming:
return PrecisionTiming(SampleIntervalMode.NONE, timestamp, time_offset)
cls, timestamp: ht.datetime | None = None, time_offset: ht.timedelta | None = None
) -> Self:
return cls(SampleIntervalMode.NONE, timestamp, time_offset)

@override
@staticmethod
@classmethod
def create_with_regular_interval( # noqa: D102 - Missing docstring in public method - override
cls,
sample_interval: ht.timedelta,
timestamp: ht.datetime | None = None,
time_offset: ht.timedelta | None = None,
) -> PrecisionTiming:
return PrecisionTiming(SampleIntervalMode.REGULAR, timestamp, time_offset, sample_interval)
) -> Self:
return cls(SampleIntervalMode.REGULAR, timestamp, time_offset, sample_interval)

@override
@staticmethod
@classmethod
def create_with_irregular_interval( # noqa: D102 - Missing docstring in public method - override
cls,
timestamps: Sequence[ht.datetime],
) -> PrecisionTiming:
return PrecisionTiming(SampleIntervalMode.IRREGULAR, timestamps=timestamps)
) -> Self:
return cls(SampleIntervalMode.IRREGULAR, timestamps=timestamps)

@override
@staticmethod
Expand Down
27 changes: 15 additions & 12 deletions src/nitypes/waveform/_timing/_standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import datetime as dt
from collections.abc import Sequence
from typing import ClassVar
from typing import ClassVar, final

from typing_extensions import override
from typing_extensions import Self, override

from nitypes.waveform._timing._base import BaseTiming
from nitypes.waveform._timing._sample_interval import SampleIntervalMode


@final
class Timing(BaseTiming[dt.datetime, dt.timedelta]):
"""Waveform timing using the standard datetime module.

Expand All @@ -25,27 +26,29 @@ class Timing(BaseTiming[dt.datetime, dt.timedelta]):
"""A waveform timing object with no timestamp, time offset, or sample interval."""

@override
@staticmethod
@classmethod
def create_with_no_interval( # noqa: D102 - Missing docstring in public method - override
timestamp: dt.datetime | None = None, time_offset: dt.timedelta | None = None
) -> Timing:
return Timing(SampleIntervalMode.NONE, timestamp, time_offset)
cls, timestamp: dt.datetime | None = None, time_offset: dt.timedelta | None = None
) -> Self:
return cls(SampleIntervalMode.NONE, timestamp, time_offset)

@override
@staticmethod
@classmethod
def create_with_regular_interval( # noqa: D102 - Missing docstring in public method - override
cls,
sample_interval: dt.timedelta,
timestamp: dt.datetime | None = None,
time_offset: dt.timedelta | None = None,
) -> Timing:
return Timing(SampleIntervalMode.REGULAR, timestamp, time_offset, sample_interval)
) -> Self:
return cls(SampleIntervalMode.REGULAR, timestamp, time_offset, sample_interval)

@override
@staticmethod
@classmethod
def create_with_irregular_interval( # noqa: D102 - Missing docstring in public method - override
cls,
timestamps: Sequence[dt.datetime],
) -> Timing:
return Timing(SampleIntervalMode.IRREGULAR, timestamps=timestamps)
) -> Self:
return cls(SampleIntervalMode.IRREGULAR, timestamps=timestamps)

@override
@staticmethod
Expand Down
Loading