From 403b1a5f8a8e5389df4f18bc9b0fc6d104aa0fa9 Mon Sep 17 00:00:00 2001 From: Joel Dixon Date: Mon, 11 May 2026 10:57:47 -0500 Subject: [PATCH 1/4] Allow t0 and measurement.StartTime to differ. Do not throw a ValueError. Add a test to cover when neither t0 nor StartTime is specified it uses 'now' --- src/ni/datastore/data/_grpc_conversion.py | 9 ++--- tests/unit/data/test_publish_measurement.py | 39 ++++++++++++++++++--- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/ni/datastore/data/_grpc_conversion.py b/src/ni/datastore/data/_grpc_conversion.py index 2fcab116..7c6e7f9e 100644 --- a/src/ni/datastore/data/_grpc_conversion.py +++ b/src/ni/datastore/data/_grpc_conversion.py @@ -235,14 +235,9 @@ def get_publish_measurement_timestamp( elif value_case == "digital_waveform": waveform_t0 = publish_request.digital_waveform.t0 - # If an initialized waveform t0 value is present + # If an initialized waveform t0 value is present and no client timestamp was provided, + # use the waveform t0 as the measurement start time. if waveform_t0 is not None and waveform_t0 != PrecisionTimestamp(): if no_client_timestamp_provided: - # If the client did not provide a timestamp, use the waveform t0 value publish_time = waveform_t0 - elif publish_time != waveform_t0: - raise ValueError( - "The provided timestamp does not match the waveform t0. Please provide a matching timestamp or " - "omit the timestamp to use the waveform t0." - ) return publish_time diff --git a/tests/unit/data/test_publish_measurement.py b/tests/unit/data/test_publish_measurement.py index ac3742e7..18a8b24b 100644 --- a/tests/unit/data/test_publish_measurement.py +++ b/tests/unit/data/test_publish_measurement.py @@ -224,8 +224,9 @@ def test___publish_analog_waveform_data_without_t0___uses_timestamp_parameter( assert request.timestamp == hightime_datetime_to_protobuf(timestamp) -def test___publish_analog_waveform_data_with_mismatched_timestamp_parameter___raises_error( +def test___publish_analog_waveform_data_with_mismatched_timestamp_parameter___uses_provided_timestamp( data_store_client: DataStoreClient, + mocked_data_store_service_client: NonCallableMock, ) -> None: timestamp = datetime.now(tz=std_datetime.timezone.utc) waveform_values = [1.0, 2.0, 3.0] @@ -235,11 +236,39 @@ def test___publish_analog_waveform_data_with_mismatched_timestamp_parameter___ra timing=Timing.create_with_regular_interval(timedelta(seconds=1), timestamp), ) mismatched_timestamp = timestamp + timedelta(seconds=1) + mocked_data_store_service_client.publish_measurement.return_value = ( + PublishMeasurementResponse(measurement_id="response_id") + ) - with pytest.raises(ValueError): - data_store_client.publish_measurement( - "name", analog_waveform, "step_id", mismatched_timestamp - ) + measurement_id = data_store_client.publish_measurement( + "name", analog_waveform, "step_id", mismatched_timestamp + ) + + args, __ = mocked_data_store_service_client.publish_measurement.call_args + request = cast(PublishMeasurementRequest, args[0]) + assert measurement_id == "response_id" + assert request.timestamp == hightime_datetime_to_protobuf(mismatched_timestamp) + + +def test___publish_analog_waveform_data_without_t0_or_timestamp___uses_now( + data_store_client: DataStoreClient, + mocked_data_store_service_client: NonCallableMock, +) -> None: + now = datetime.now(tz=std_datetime.timezone.utc) + analog_waveform = AnalogWaveform.from_array_1d([1.0, 2.0, 3.0], dtype=float) + mocked_data_store_service_client.publish_measurement.return_value = ( + PublishMeasurementResponse(measurement_id="response_id") + ) + + with unittest.mock.patch( + "ni.datastore.data._grpc_conversion.ht.datetime" + ) as mock_ht_datetime: + mock_ht_datetime.now.return_value = now + data_store_client.publish_measurement("name", analog_waveform, "step_id") + + args, __ = mocked_data_store_service_client.publish_measurement.call_args + request = cast(PublishMeasurementRequest, args[0]) + assert request.timestamp == hightime_datetime_to_protobuf(now) def test___none___publish_measurement___raises_type_error( From 586720282809c09a1545e876f2e40a75b1865b6e Mon Sep 17 00:00:00 2001 From: Joel Dixon Date: Mon, 11 May 2026 11:01:04 -0500 Subject: [PATCH 2/4] Filter out warnings from generated code. --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 38247865..96f87303 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,3 +113,5 @@ exclude = ["**/*_pb2_grpc.py", "**/*_pb2_grpc.pyi", "**/*_pb2.py", "**/*_pb2.pyi [tool.pytest.ini_options] addopts = "--doctest-modules --doctest-plus --strict-markers" testpaths = ["tests"] +norecursedirs = [".venv"] +filterwarnings = ["ignore::pytest.PytestCollectionWarning"] From 5bc1fdbeacb281236f830a80a5b694d2c932fb86 Mon Sep 17 00:00:00 2001 From: Joel Dixon Date: Mon, 11 May 2026 11:21:41 -0500 Subject: [PATCH 3/4] Fix lint error --- tests/unit/data/test_publish_measurement.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/unit/data/test_publish_measurement.py b/tests/unit/data/test_publish_measurement.py index 18a8b24b..81cb2126 100644 --- a/tests/unit/data/test_publish_measurement.py +++ b/tests/unit/data/test_publish_measurement.py @@ -236,8 +236,8 @@ def test___publish_analog_waveform_data_with_mismatched_timestamp_parameter___us timing=Timing.create_with_regular_interval(timedelta(seconds=1), timestamp), ) mismatched_timestamp = timestamp + timedelta(seconds=1) - mocked_data_store_service_client.publish_measurement.return_value = ( - PublishMeasurementResponse(measurement_id="response_id") + mocked_data_store_service_client.publish_measurement.return_value = PublishMeasurementResponse( + measurement_id="response_id" ) measurement_id = data_store_client.publish_measurement( @@ -256,13 +256,11 @@ def test___publish_analog_waveform_data_without_t0_or_timestamp___uses_now( ) -> None: now = datetime.now(tz=std_datetime.timezone.utc) analog_waveform = AnalogWaveform.from_array_1d([1.0, 2.0, 3.0], dtype=float) - mocked_data_store_service_client.publish_measurement.return_value = ( - PublishMeasurementResponse(measurement_id="response_id") + mocked_data_store_service_client.publish_measurement.return_value = PublishMeasurementResponse( + measurement_id="response_id" ) - with unittest.mock.patch( - "ni.datastore.data._grpc_conversion.ht.datetime" - ) as mock_ht_datetime: + with unittest.mock.patch("ni.datastore.data._grpc_conversion.ht.datetime") as mock_ht_datetime: mock_ht_datetime.now.return_value = now data_store_client.publish_measurement("name", analog_waveform, "step_id") From efbf280a010415357680cf5fcba006d6c8bf4432 Mon Sep 17 00:00:00 2001 From: Joel Dixon Date: Mon, 11 May 2026 11:27:57 -0500 Subject: [PATCH 4/4] Narrow the ignored warning scope. --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 96f87303..4e55632a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -114,4 +114,6 @@ exclude = ["**/*_pb2_grpc.py", "**/*_pb2_grpc.pyi", "**/*_pb2.py", "**/*_pb2.pyi addopts = "--doctest-modules --doctest-plus --strict-markers" testpaths = ["tests"] norecursedirs = [".venv"] -filterwarnings = ["ignore::pytest.PytestCollectionWarning"] +filterwarnings = [ + "ignore:cannot collect test class.*because it has a __init__ constructor:pytest.PytestCollectionWarning", +]