Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion .github/workflows/run_unit_tests_oldest_deps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ jobs:
- 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-oldest-deps-${{ matrix.os }}-py${{ matrix.python-version }}.xml
# Skip test___pickled_value___unpickle___is_compatible because this test's pickle data was saved with NumPy 2.x and cannot be loaded in NumPy 1.x.
run: poetry run pytest ./tests/unit -v --cov=nitypes --junitxml=test_results/nitypes-oldest-deps-${{ matrix.os }}-py${{ matrix.python-version }}.xml -k "not test___pickled_value___unpickle___is_compatible"
- name: Upload test results
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
Expand Down
6 changes: 5 additions & 1 deletion src/nitypes/waveform/_digital/_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ def __init__(
self,
owner: DigitalWaveform[TDigitalState],
signal_index: SupportsIndex,
column_index: SupportsIndex,
column_index: SupportsIndex | None = None,
) -> None:
"""Initialize a new digital waveform signal."""
if column_index is None:
# when unpickling an old version, column_index may not be provided
column_index = signal_index

self._owner = owner
self._signal_index = arg_to_uint("signal index", signal_index)
self._column_index = arg_to_uint("column index", column_index)
Expand Down
3 changes: 3 additions & 0 deletions src/nitypes/waveform/_digital/_waveform.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,9 @@ def __init__(
):
extended_properties = ExtendedPropertyDictionary(extended_properties)
self._extended_properties = extended_properties
if not hasattr(self._extended_properties, "_on_key_changed"):
# when unpickling an old version, _on_key_changed may not exist
self._extended_properties._on_key_changed = []
self._extended_properties._on_key_changed.append(
weakref.WeakMethod(self._on_extended_property_changed)
)
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/waveform/test_digital_waveform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1965,6 +1965,36 @@ def test___waveform___pickle___references_public_modules() -> None:
assert b"nitypes.waveform._timing" not in value_bytes


@pytest.mark.parametrize(
"pickled_value, expected",
[
# nitypes 1.0.0
pytest.param(
b"\x80\x04\x95\x08\x02\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x07getattr\x94\x93\x94\x8c\x10nitypes.waveform\x94\x8c\x0fDigitalWaveform\x94\x93\x94\x8c\t_unpickle\x94\x86\x94R\x94K\x03K\x01\x8c\x05numpy\x94\x8c\x05dtype\x94\x93\x94\x8c\x02b1\x94\x89\x88\x87\x94R\x94(K\x03\x8c\x01|\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x87\x94}\x94(\x8c\x04data\x94\x8c\x16numpy._core.multiarray\x94\x8c\x0c_reconstruct\x94\x93\x94h\t\x8c\x07ndarray\x94\x93\x94K\x00\x85\x94C\x01b\x94\x87\x94R\x94(K\x01K\x03K\x01\x86\x94h\x0e\x89C\x03\x01\x01\x01\x94t\x94b\x8c\x13extended_properties\x94h\x03\x8c\x1aExtendedPropertyDictionary\x94\x93\x94)\x81\x94N}\x94\x8c\x0b_properties\x94}\x94(\x8c\x0eNI_ChannelName\x94\x8c\x08Dev1/ai0\x94\x8c\x12NI_UnitDescription\x94\x8c\x05Volts\x94us\x86\x94b\x8c\x18copy_extended_properties\x94\x89\x8c\x06timing\x94h\x02h\x03\x8c\x06Timing\x94\x93\x94h\x06\x86\x94R\x94(h\x03\x8c\x12SampleIntervalMode\x94\x93\x94K\x01\x85\x94R\x94NN\x8c\x08datetime\x94\x8c\ttimedelta\x94\x93\x94K\x00K\x00M\xe8\x03\x87\x94R\x94Nt\x94}\x94\x86\x94R\x94u\x86\x94R\x94.",
DigitalWaveform(
data=np.array([1, 2, 3], _np_bool),
extended_properties={"NI_ChannelName": "Dev1/ai0", "NI_UnitDescription": "Volts"},
timing=Timing.create_with_regular_interval(dt.timedelta(milliseconds=1)),
),
),
# nitypes 1.0.1
(
b"\x80\x04\x95\xf4\x01\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x07getattr\x94\x93\x94\x8c\x10nitypes.waveform\x94\x8c\x0fDigitalWaveform\x94\x93\x94\x8c\t_unpickle\x94\x86\x94R\x94K\x03K\x01\x8c\x05numpy\x94\x8c\x05dtype\x94\x93\x94\x8c\x02b1\x94\x89\x88\x87\x94R\x94(K\x03\x8c\x01|\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x87\x94}\x94(\x8c\x04data\x94\x8c\x16numpy._core.multiarray\x94\x8c\x0c_reconstruct\x94\x93\x94h\t\x8c\x07ndarray\x94\x93\x94K\x00\x85\x94C\x01b\x94\x87\x94R\x94(K\x01K\x03K\x01\x86\x94h\x0e\x89C\x03\x01\x01\x01\x94t\x94b\x8c\x13extended_properties\x94h\x03\x8c\x1aExtendedPropertyDictionary\x94\x93\x94}\x94(\x8c\x0eNI_ChannelName\x94\x8c\x08Dev1/ai0\x94\x8c\x12NI_UnitDescription\x94\x8c\x05Volts\x94u\x85\x94R\x94\x8c\x18copy_extended_properties\x94\x89\x8c\x06timing\x94h\x02h\x03\x8c\x06Timing\x94\x93\x94h\x06\x86\x94R\x94(h\x03\x8c\x12SampleIntervalMode\x94\x93\x94K\x01\x85\x94R\x94NN\x8c\x08datetime\x94\x8c\ttimedelta\x94\x93\x94K\x00K\x00M\xe8\x03\x87\x94R\x94Nt\x94}\x94\x86\x94R\x94u\x86\x94R\x94.",
DigitalWaveform(
data=np.array([1, 2, 3], _np_bool),
extended_properties={"NI_ChannelName": "Dev1/ai0", "NI_UnitDescription": "Volts"},
timing=Timing.create_with_regular_interval(dt.timedelta(milliseconds=1)),
),
),
],
)
def test___pickled_value___unpickle___is_compatible(
pickled_value: bytes, expected: DigitalWaveform[Any]
) -> None:
new_value = pickle.loads(pickled_value)
assert new_value == expected


def test___waveform_with_extended_properties___pickle_unpickle___valid_on_key_changed() -> None:
value = DigitalWaveform(
data=np.array([1, 2, 3], _np_bool),
Expand Down
26 changes: 26 additions & 0 deletions tests/unit/waveform/test_digital_waveform_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,29 @@ def test___waveform___pickle___references_public_modules() -> None:

assert b"nitypes.waveform" in value_bytes
assert b"nitypes.waveform._digital" not in value_bytes


@pytest.mark.parametrize(
"pickled_value, expected",
[
# nitypes 1.0.0
pytest.param(
b"\x80\x04\x95\xfa\x01\x00\x00\x00\x00\x00\x00\x8c\x10nitypes.waveform\x94\x8c\x15DigitalWaveformSignal\x94\x93\x94\x8c\x08builtins\x94\x8c\x07getattr\x94\x93\x94h\x00\x8c\x0fDigitalWaveform\x94\x93\x94\x8c\t_unpickle\x94\x86\x94R\x94K\x03K\x02\x8c\x05numpy\x94\x8c\x05dtype\x94\x93\x94\x8c\x02u1\x94\x89\x88\x87\x94R\x94(K\x03\x8c\x01|\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x87\x94}\x94(\x8c\x04data\x94\x8c\x16numpy._core.multiarray\x94\x8c\x0c_reconstruct\x94\x93\x94h\x0b\x8c\x07ndarray\x94\x93\x94K\x00\x85\x94C\x01b\x94\x87\x94R\x94(K\x01K\x03K\x02\x86\x94h\x10\x89C\x06\x00\x00\x00\x00\x00\x00\x94t\x94b\x8c\x13extended_properties\x94h\x00\x8c\x1aExtendedPropertyDictionary\x94\x93\x94)\x81\x94N}\x94\x8c\x0b_properties\x94}\x94\x8c\x0cNI_LineNames\x94\x8c\x18port0/line1, port0/line0\x94ss\x86\x94b\x8c\x18copy_extended_properties\x94\x89\x8c\x06timing\x94h\x05h\x00\x8c\x06Timing\x94\x93\x94h\x08\x86\x94R\x94(h\x00\x8c\x12SampleIntervalMode\x94\x93\x94K\x00\x85\x94R\x94NNNNt\x94}\x94\x86\x94R\x94u\x86\x94R\x94K\x01\x86\x94R\x94.",
DigitalWaveform(
3, 2, extended_properties={"NI_LineNames": "port0/line1, port0/line0"}
).signals[1],
),
# nitypes 1.0.1
(
b"\x80\x04\x95\xe8\x01\x00\x00\x00\x00\x00\x00\x8c\x10nitypes.waveform\x94\x8c\x15DigitalWaveformSignal\x94\x93\x94\x8c\x08builtins\x94\x8c\x07getattr\x94\x93\x94h\x00\x8c\x0fDigitalWaveform\x94\x93\x94\x8c\t_unpickle\x94\x86\x94R\x94K\x03K\x02\x8c\x05numpy\x94\x8c\x05dtype\x94\x93\x94\x8c\x02u1\x94\x89\x88\x87\x94R\x94(K\x03\x8c\x01|\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x87\x94}\x94(\x8c\x04data\x94\x8c\x16numpy._core.multiarray\x94\x8c\x0c_reconstruct\x94\x93\x94h\x0b\x8c\x07ndarray\x94\x93\x94K\x00\x85\x94C\x01b\x94\x87\x94R\x94(K\x01K\x03K\x02\x86\x94h\x10\x89C\x06\x00\x00\x00\x00\x00\x00\x94t\x94b\x8c\x13extended_properties\x94h\x00\x8c\x1aExtendedPropertyDictionary\x94\x93\x94}\x94\x8c\x0cNI_LineNames\x94\x8c\x18port0/line1, port0/line0\x94s\x85\x94R\x94\x8c\x18copy_extended_properties\x94\x89\x8c\x06timing\x94h\x05h\x00\x8c\x06Timing\x94\x93\x94h\x08\x86\x94R\x94(h\x00\x8c\x12SampleIntervalMode\x94\x93\x94K\x00\x85\x94R\x94NNNNt\x94}\x94\x86\x94R\x94u\x86\x94R\x94K\x01K\x00\x87\x94R\x94.",
DigitalWaveform(
3, 2, extended_properties={"NI_LineNames": "port0/line1, port0/line0"}
).signals[1],
),
],
)
def test___pickled_value___unpickle___is_compatible(
pickled_value: bytes, expected: DigitalWaveformSignal[Any]
) -> None:
new_value = pickle.loads(pickled_value)
assert new_value == expected