nidaqmx 1.3.0.dev0__tar.gz → 1.4.0.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/PKG-INFO +8 -6
  2. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/README.rst +1 -1
  3. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_base_interpreter.py +15 -4
  4. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_dotenvpath.py +1 -16
  5. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_feature_toggles.py +3 -5
  6. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_grpc_interpreter.py +147 -13
  7. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_install_daqmx.py +1 -1
  8. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_installer_metadata.json +6 -6
  9. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_lib.py +1 -1
  10. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_library_interpreter.py +44 -36
  11. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_linux_installation_commands.py +1 -1
  12. nidaqmx-1.4.0.dev0/generated/nidaqmx/_stubs/nidaqmx_pb2.py +2362 -0
  13. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2.pyi +213 -1
  14. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2_grpc.py +132 -0
  15. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2_grpc.pyi +68 -0
  16. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_time.py +20 -4
  17. nidaqmx-1.4.0.dev0/generated/nidaqmx/_waveform_utils.py +18 -0
  18. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_analog_multi_channel_reader.py +1 -1
  19. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_analog_single_channel_reader.py +1 -1
  20. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_channel_reader_base.py +2 -4
  21. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_digital_multi_channel_reader.py +3 -5
  22. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_channel_writer_base.py +2 -4
  23. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_digital_multi_channel_writer.py +2 -1
  24. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/__init__.py +1 -0
  25. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_collections/device_collection.py +1 -1
  26. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_collections/persisted_channel_collection.py +1 -1
  27. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_collections/persisted_scale_collection.py +1 -1
  28. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_collections/persisted_task_collection.py +1 -1
  29. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_collections/physical_channel_collection.py +1 -1
  30. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_watchdog_modules/expiration_states_collection.py +1 -1
  31. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/physical_channel.py +2 -3
  32. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/system.py +5 -5
  33. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/_in_stream.py +5 -5
  34. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/_task.py +11 -7
  35. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_channel_collection.py +1 -1
  36. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/types.py +4 -0
  37. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/pyproject.toml +22 -25
  38. nidaqmx-1.3.0.dev0/generated/nidaqmx/_stubs/nidaqmx_pb2.py +0 -2343
  39. nidaqmx-1.3.0.dev0/generated/nidaqmx/_stubs/session_pb2.py +0 -52
  40. nidaqmx-1.3.0.dev0/generated/nidaqmx/_stubs/session_pb2.pyi +0 -240
  41. nidaqmx-1.3.0.dev0/generated/nidaqmx/_stubs/session_pb2_grpc.py +0 -204
  42. nidaqmx-1.3.0.dev0/generated/nidaqmx/_stubs/session_pb2_grpc.pyi +0 -130
  43. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/LICENSE +0 -0
  44. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/__init__.py +0 -0
  45. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/__main__.py +0 -0
  46. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_bitfield_utils.py +0 -0
  47. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_grpc_time.py +0 -0
  48. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_lib_time.py +0 -0
  49. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/__init__.py +0 -0
  50. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2.py +0 -0
  51. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2.pyi +0 -0
  52. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2_grpc.py +0 -0
  53. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2_grpc.pyi +0 -0
  54. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/constants.py +0 -0
  55. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/error_codes.py +0 -0
  56. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/errors.py +0 -0
  57. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/grpc_session_options.py +0 -0
  58. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/scale.py +0 -0
  59. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/__init__.py +0 -0
  60. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_analog_unscaled_reader.py +0 -0
  61. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_counter_reader.py +0 -0
  62. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_digital_single_channel_reader.py +0 -0
  63. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_readers/_power_readers.py +0 -0
  64. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/__init__.py +0 -0
  65. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_analog_multi_channel_writer.py +0 -0
  66. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_analog_single_channel_writer.py +0 -0
  67. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_analog_unscaled_writer.py +0 -0
  68. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_counter_writer.py +0 -0
  69. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/stream_writers/_digital_single_channel_writer.py +0 -0
  70. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_collections/__init__.py +0 -0
  71. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_watchdog_modules/__init__.py +0 -0
  72. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/_watchdog_modules/expiration_state.py +0 -0
  73. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/device.py +0 -0
  74. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/storage/__init__.py +0 -0
  75. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/storage/persisted_channel.py +0 -0
  76. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/storage/persisted_scale.py +0 -0
  77. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/storage/persisted_task.py +0 -0
  78. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/system/watchdog.py +0 -0
  79. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/__init__.py +0 -0
  80. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/_export_signals.py +0 -0
  81. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/_out_stream.py +0 -0
  82. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/_timing.py +0 -0
  83. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/__init__.py +0 -0
  84. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_ai_channel.py +0 -0
  85. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_ao_channel.py +0 -0
  86. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_channel.py +0 -0
  87. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_ci_channel.py +0 -0
  88. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_co_channel.py +0 -0
  89. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_di_channel.py +0 -0
  90. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/channels/_do_channel.py +0 -0
  91. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/__init__.py +0 -0
  92. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_ai_channel_collection.py +0 -0
  93. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_ao_channel_collection.py +0 -0
  94. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_ci_channel_collection.py +0 -0
  95. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_co_channel_collection.py +0 -0
  96. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_di_channel_collection.py +0 -0
  97. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/collections/_do_channel_collection.py +0 -0
  98. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/__init__.py +0 -0
  99. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/_arm_start_trigger.py +0 -0
  100. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/_handshake_trigger.py +0 -0
  101. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/_pause_trigger.py +0 -0
  102. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/_reference_trigger.py +0 -0
  103. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/_start_trigger.py +0 -0
  104. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/task/triggering/_triggers.py +0 -0
  105. {nidaqmx-1.3.0.dev0 → nidaqmx-1.4.0.dev0}/generated/nidaqmx/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nidaqmx
3
- Version: 1.3.0.dev0
3
+ Version: 1.4.0.dev0
4
4
  Summary: NI-DAQmx Python API
5
5
  License: MIT
6
6
  Keywords: nidaqmx,nidaq,daqmx,daq
@@ -8,7 +8,7 @@ Author: NI
8
8
  Author-email: opensource@ni.com
9
9
  Maintainer: Zach Hindes
10
10
  Maintainer-email: zach.hindes@ni.com
11
- Requires-Python: >=3.9,<4.0
11
+ Requires-Python: >=3.10,<4.0
12
12
  Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Manufacturing
@@ -17,11 +17,11 @@ Classifier: License :: OSI Approved :: MIT License
17
17
  Classifier: Operating System :: Microsoft :: Windows
18
18
  Classifier: Operating System :: POSIX
19
19
  Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.9
21
20
  Classifier: Programming Language :: Python :: 3.10
22
21
  Classifier: Programming Language :: Python :: 3.11
23
22
  Classifier: Programming Language :: Python :: 3.12
24
23
  Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
25
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
26
  Classifier: Programming Language :: Python :: Implementation :: PyPy
27
27
  Classifier: Topic :: System :: Hardware :: Hardware Drivers
@@ -31,8 +31,10 @@ Requires-Dist: deprecation (>=2.1)
31
31
  Requires-Dist: distro (>=1.9.0) ; sys_platform == "linux"
32
32
  Requires-Dist: grpcio (>=1.49.0,<2.0) ; extra == "grpc"
33
33
  Requires-Dist: hightime (>=0.2.2)
34
- Requires-Dist: nitypes (>=0.1.0dev10)
35
- Requires-Dist: numpy (>=1.22) ; python_version >= "3.9" and python_version < "3.13"
34
+ Requires-Dist: ni-grpcdevice-v1-proto (>=1.0.0) ; extra == "grpc"
35
+ Requires-Dist: ni-protobuf-types (>=1.0.0) ; extra == "grpc"
36
+ Requires-Dist: nitypes (>=1.0.0)
37
+ Requires-Dist: numpy (>=1.22) ; python_version >= "3.10" and python_version < "3.13"
36
38
  Requires-Dist: numpy (>=2.1) ; python_version >= "3.13" and python_version < "4.0"
37
39
  Requires-Dist: protobuf (>=4.21) ; extra == "grpc"
38
40
  Requires-Dist: python-decouple (>=3.8)
@@ -100,7 +102,7 @@ system.
100
102
  Python Version Support
101
103
  ----------------------
102
104
 
103
- **nidaqmx** supports CPython 3.9+.
105
+ **nidaqmx** supports CPython 3.10+.
104
106
 
105
107
  **nidaqmx** supports PyPy3 for non-gRPC use cases. For the status of PyPy support for gRPC,
106
108
  see `PyPy support (grpc/grpc#4221) <https://github.com/grpc/grpc/issues/4221>`_.
@@ -55,7 +55,7 @@ system.
55
55
  Python Version Support
56
56
  ----------------------
57
57
 
58
- **nidaqmx** supports CPython 3.9+.
58
+ **nidaqmx** supports CPython 3.10+.
59
59
 
60
60
  **nidaqmx** supports PyPy3 for non-gRPC use cases. For the status of PyPy support for gRPC,
61
61
  see `PyPy support (grpc/grpc#4221) <https://github.com/grpc/grpc/issues/4221>`_.
@@ -4,7 +4,9 @@ from __future__ import annotations
4
4
  import abc
5
5
  import numpy
6
6
  from nitypes.waveform import AnalogWaveform, DigitalWaveform
7
- from typing import Any, Sequence
7
+ from typing import Any
8
+
9
+ from collections.abc import Sequence
8
10
  from nidaqmx.constants import WaveformAttributeMode
9
11
 
10
12
 
@@ -1093,6 +1095,10 @@ class BaseInterpreter(abc.ABC):
1093
1095
  def get_timing_attribute_string(self, task, attribute):
1094
1096
  raise NotImplementedError
1095
1097
 
1098
+ @abc.abstractmethod
1099
+ def get_timing_attribute_timestamp(self, task, attribute):
1100
+ raise NotImplementedError
1101
+
1096
1102
  @abc.abstractmethod
1097
1103
  def get_timing_attribute_uint32(self, task, attribute):
1098
1104
  raise NotImplementedError
@@ -1852,6 +1858,11 @@ class BaseInterpreter(abc.ABC):
1852
1858
  def hash_task_handle(self, task_handle):
1853
1859
  raise NotImplementedError
1854
1860
 
1861
+ @property
1862
+ @abc.abstractmethod
1863
+ def driver_version(self):
1864
+ raise NotImplementedError
1865
+
1855
1866
  @abc.abstractmethod
1856
1867
  def read_analog_waveform(
1857
1868
  self,
@@ -1873,7 +1884,7 @@ class BaseInterpreter(abc.ABC):
1873
1884
  waveform_attribute_mode: WaveformAttributeMode
1874
1885
  ) -> int:
1875
1886
  raise NotImplementedError
1876
-
1887
+
1877
1888
  @abc.abstractmethod
1878
1889
  def read_digital_waveform(
1879
1890
  self,
@@ -1929,7 +1940,7 @@ class BaseInterpreter(abc.ABC):
1929
1940
  timeout: float
1930
1941
  ) -> int:
1931
1942
  raise NotImplementedError
1932
-
1943
+
1933
1944
  @abc.abstractmethod
1934
1945
  def write_digital_waveform(
1935
1946
  self,
@@ -1939,7 +1950,7 @@ class BaseInterpreter(abc.ABC):
1939
1950
  timeout: float,
1940
1951
  ) -> int:
1941
1952
  raise NotImplementedError
1942
-
1953
+
1943
1954
  def write_digital_waveforms(
1944
1955
  self,
1945
1956
  task_handle: object,
@@ -45,27 +45,12 @@ def _get_caller_path() -> Path | None:
45
45
  for frame, _ in traceback.walk_stack(inspect.currentframe()):
46
46
  if frame.f_code.co_filename:
47
47
  module_path = Path(frame.f_code.co_filename)
48
- if _exists(module_path) and not module_path.is_relative_to(package_path):
48
+ if module_path.exists() and not module_path.is_relative_to(package_path):
49
49
  return module_path
50
50
 
51
51
  return None
52
52
 
53
53
 
54
- # Path.exists() throws OSError when the path has invalid file characters.
55
- # https://github.com/python/cpython/issues/79487
56
- if sys.version_info >= (3, 10):
57
-
58
- def _exists(path: Path) -> bool:
59
- return path.exists()
60
-
61
- else:
62
-
63
- def _exists(path: Path) -> bool:
64
- import os
65
-
66
- return os.path.exists(path)
67
-
68
-
69
54
  def _get_package_path() -> Path:
70
55
  """Get the path of this package."""
71
56
  module = sys.modules[__package__]
@@ -4,8 +4,9 @@ from __future__ import annotations
4
4
 
5
5
  import functools
6
6
  import sys
7
+ from collections.abc import Callable
7
8
  from enum import Enum
8
- from typing import TYPE_CHECKING, Callable, TypeVar
9
+ from typing import TYPE_CHECKING, TypeVar
9
10
 
10
11
  from decouple import AutoConfig, Undefined, undefined
11
12
 
@@ -13,10 +14,7 @@ from nidaqmx._dotenvpath import get_dotenv_search_path
13
14
  from nidaqmx.errors import FeatureNotSupportedError
14
15
 
15
16
  if TYPE_CHECKING:
16
- if sys.version_info >= (3, 10):
17
- from typing import ParamSpec
18
- else:
19
- from typing_extensions import ParamSpec
17
+ from typing import ParamSpec
20
18
 
21
19
  if sys.version_info >= (3, 11):
22
20
  from typing import Self
@@ -6,10 +6,11 @@ import threading
6
6
  import typing
7
7
  import warnings
8
8
  from nitypes.waveform import AnalogWaveform, DigitalWaveform
9
- from typing import Any, Callable, Generic, Sequence, TypeVar
9
+ from typing import Any, Generic, TypeVar
10
+
11
+ from collections.abc import Callable, Sequence
10
12
 
11
13
  import google.protobuf.message
12
- from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
13
14
  import grpc
14
15
  import numpy
15
16
 
@@ -17,10 +18,18 @@ from . import errors as errors
17
18
  from nidaqmx._base_interpreter import BaseEventHandler, BaseInterpreter
18
19
  from nidaqmx._stubs import nidaqmx_pb2 as grpc_types
19
20
  from nidaqmx._stubs import nidaqmx_pb2_grpc as nidaqmx_grpc
20
- from nidaqmx._stubs import session_pb2 as session_grpc_types
21
+ from ni.protobuf.types.waveform_conversion import (
22
+ digital_waveform_from_protobuf,
23
+ digital_waveform_to_protobuf,
24
+ float64_analog_waveform_from_protobuf,
25
+ float64_analog_waveform_to_protobuf
26
+ )
21
27
  from nidaqmx.constants import WaveformAttributeMode
22
28
  from nidaqmx.error_codes import DAQmxErrors
29
+ from nidaqmx.types import DriverVersion
23
30
  from nidaqmx._grpc_time import convert_time_to_timestamp, convert_timestamp_to_time
31
+ from nidaqmx._waveform_utils import get_num_samps_per_chan
32
+ from session_pb2 import Session
24
33
 
25
34
  _logger = logging.getLogger(__name__)
26
35
 
@@ -86,11 +95,21 @@ class GrpcStubInterpreter(BaseInterpreter):
86
95
  __slots__ = [
87
96
  '_grpc_options',
88
97
  '_client',
98
+ '_driver_version',
89
99
  ]
90
100
 
91
101
  def __init__(self, grpc_options):
92
102
  self._grpc_options = grpc_options
93
103
  self._client = nidaqmx_grpc.NiDAQmxStub(grpc_options.grpc_channel)
104
+ try:
105
+ major_version = self.get_system_info_attribute_uint32(0x1272)
106
+ minor_version = self.get_system_info_attribute_uint32(0x1923)
107
+ update_version = self.get_system_info_attribute_uint32(0x2f22)
108
+ except Exception:
109
+ major_version = 0
110
+ minor_version = 0
111
+ update_version = 0
112
+ self._driver_version = DriverVersion(major_version, minor_version, update_version)
94
113
 
95
114
  def _invoke(self, func, request, metadata=None):
96
115
  try:
@@ -169,6 +188,10 @@ class GrpcStubInterpreter(BaseInterpreter):
169
188
  except grpc.RpcError as rpc_error:
170
189
  self._handle_rpc_error(rpc_error)
171
190
 
191
+ @property
192
+ def driver_version(self):
193
+ return self._driver_version
194
+
172
195
  def add_cdaq_sync_connection(self, port_list):
173
196
  response = self._invoke(
174
197
  self._client.AddCDAQSyncConnection,
@@ -2181,6 +2204,12 @@ class GrpcStubInterpreter(BaseInterpreter):
2181
2204
  grpc_types.GetTimingAttributeStringRequest(task=task, attribute_raw=attribute))
2182
2205
  return response.value
2183
2206
 
2207
+ def get_timing_attribute_timestamp(self, task, attribute):
2208
+ response = self._invoke(
2209
+ self._client.GetTimingAttributeTimestamp,
2210
+ grpc_types.GetTimingAttributeTimestampRequest(task=task, attribute_raw=attribute))
2211
+ return convert_timestamp_to_time(response.value)
2212
+
2184
2213
  def get_timing_attribute_uint32(self, task, attribute):
2185
2214
  response = self._invoke(
2186
2215
  self._client.GetTimingAttributeUInt32,
@@ -3610,7 +3639,13 @@ class GrpcStubInterpreter(BaseInterpreter):
3610
3639
  waveform: AnalogWaveform[numpy.float64],
3611
3640
  waveform_attribute_mode: WaveformAttributeMode
3612
3641
  ) -> int:
3613
- raise NotImplementedError
3642
+ return self.read_analog_waveforms(
3643
+ task_handle,
3644
+ number_of_samples_per_channel,
3645
+ timeout,
3646
+ [waveform],
3647
+ waveform_attribute_mode
3648
+ )
3614
3649
 
3615
3650
  def read_analog_waveforms(
3616
3651
  self,
@@ -3620,7 +3655,30 @@ class GrpcStubInterpreter(BaseInterpreter):
3620
3655
  waveforms: Sequence[AnalogWaveform[numpy.float64]],
3621
3656
  waveform_attribute_mode: WaveformAttributeMode
3622
3657
  ) -> int:
3623
- raise NotImplementedError
3658
+ assert isinstance(task_handle, Session)
3659
+ response = self._invoke(
3660
+ self._client.ReadAnalogWaveforms,
3661
+ grpc_types.ReadAnalogWaveformsRequest(
3662
+ task=task_handle,
3663
+ num_samps_per_chan=number_of_samples_per_channel,
3664
+ timeout=timeout,
3665
+ waveform_attribute_mode_raw=waveform_attribute_mode.value
3666
+ ))
3667
+
3668
+ if len(response.waveforms) != len(waveforms):
3669
+ raise ValueError(f"Expected {len(waveforms)} waveforms but received {len(response.waveforms)} from server")
3670
+
3671
+ for i, grpc_waveform in enumerate(response.waveforms):
3672
+ temp_waveform = float64_analog_waveform_from_protobuf(grpc_waveform)
3673
+ waveforms[i].load_data(temp_waveform.scaled_data)
3674
+
3675
+ waveforms[i].scale_mode = temp_waveform.scale_mode
3676
+ waveforms[i].timing = temp_waveform.timing
3677
+ waveforms[i].extended_properties.clear()
3678
+ waveforms[i].extended_properties.update(temp_waveform.extended_properties)
3679
+
3680
+ self._check_for_error_from_response(response.status, samps_per_chan_read=response.samps_per_chan_read)
3681
+ return response.samps_per_chan_read
3624
3682
 
3625
3683
  def read_digital_waveform(
3626
3684
  self,
@@ -3630,7 +3688,15 @@ class GrpcStubInterpreter(BaseInterpreter):
3630
3688
  waveform: DigitalWaveform[Any],
3631
3689
  waveform_attribute_mode: WaveformAttributeMode
3632
3690
  ) -> int:
3633
- raise NotImplementedError
3691
+ return self.read_digital_waveforms(
3692
+ task_handle,
3693
+ 1, # channel_count
3694
+ number_of_samples_per_channel,
3695
+ waveform.signal_count, # number_of_signals_per_sample
3696
+ timeout,
3697
+ [waveform],
3698
+ waveform_attribute_mode
3699
+ )
3634
3700
 
3635
3701
  def read_digital_waveforms(
3636
3702
  self,
@@ -3642,7 +3708,32 @@ class GrpcStubInterpreter(BaseInterpreter):
3642
3708
  waveforms: Sequence[DigitalWaveform[Any]],
3643
3709
  waveform_attribute_mode: WaveformAttributeMode,
3644
3710
  ) -> int:
3645
- raise NotImplementedError
3711
+ assert isinstance(task_handle, Session)
3712
+ response = self._invoke(
3713
+ self._client.ReadDigitalWaveforms,
3714
+ grpc_types.ReadDigitalWaveformsRequest(
3715
+ task=task_handle,
3716
+ num_samps_per_chan=number_of_samples_per_channel,
3717
+ timeout=timeout,
3718
+ waveform_attribute_mode_raw=waveform_attribute_mode.value
3719
+ ))
3720
+
3721
+ if len(response.waveforms) != len(waveforms):
3722
+ raise ValueError(f"Expected {len(waveforms)} waveforms but received {len(response.waveforms)} from server")
3723
+
3724
+ for i, grpc_waveform in enumerate(response.waveforms):
3725
+ temp_waveform = digital_waveform_from_protobuf(grpc_waveform)
3726
+ data = temp_waveform.data
3727
+ if data.dtype != waveforms[i].dtype:
3728
+ data = data.view(waveforms[i].dtype)
3729
+ waveforms[i].load_data(data)
3730
+
3731
+ waveforms[i].timing = temp_waveform.timing
3732
+ waveforms[i].extended_properties.clear()
3733
+ waveforms[i].extended_properties.update(temp_waveform.extended_properties)
3734
+
3735
+ self._check_for_error_from_response(response.status, samps_per_chan_read=response.samps_per_chan_read)
3736
+ return response.samps_per_chan_read
3646
3737
 
3647
3738
  def read_new_digital_waveforms(
3648
3739
  self,
@@ -3653,7 +3744,20 @@ class GrpcStubInterpreter(BaseInterpreter):
3653
3744
  timeout: float,
3654
3745
  waveform_attribute_mode: WaveformAttributeMode,
3655
3746
  ) -> Sequence[DigitalWaveform[numpy.uint8]]:
3656
- raise NotImplementedError
3747
+ assert isinstance(task_handle, Session)
3748
+ response = self._invoke(
3749
+ self._client.ReadDigitalWaveforms,
3750
+ grpc_types.ReadDigitalWaveformsRequest(
3751
+ task=task_handle,
3752
+ num_samps_per_chan=number_of_samples_per_channel,
3753
+ timeout=timeout,
3754
+ waveform_attribute_mode_raw=waveform_attribute_mode.value
3755
+ ))
3756
+
3757
+ waveforms = [digital_waveform_from_protobuf(grpc_waveform) for grpc_waveform in response.waveforms]
3758
+
3759
+ self._check_for_error_from_response(response.status, samps_per_chan_read=response.samps_per_chan_read)
3760
+ return waveforms
3657
3761
 
3658
3762
  def write_analog_waveform(
3659
3763
  self,
@@ -3662,7 +3766,7 @@ class GrpcStubInterpreter(BaseInterpreter):
3662
3766
  auto_start: bool,
3663
3767
  timeout: float
3664
3768
  ) -> int:
3665
- raise NotImplementedError
3769
+ return self.write_analog_waveforms(task_handle, [waveform], auto_start, timeout)
3666
3770
 
3667
3771
  def write_analog_waveforms(
3668
3772
  self,
@@ -3671,7 +3775,22 @@ class GrpcStubInterpreter(BaseInterpreter):
3671
3775
  auto_start: bool,
3672
3776
  timeout: float
3673
3777
  ) -> int:
3674
- raise NotImplementedError
3778
+ assert isinstance(task_handle, Session)
3779
+ num_samps_per_chan = get_num_samps_per_chan(waveforms)
3780
+
3781
+ grpc_waveforms = [float64_analog_waveform_to_protobuf(waveform) for waveform in waveforms]
3782
+
3783
+ response = self._invoke(
3784
+ self._client.WriteAnalogWaveforms,
3785
+ grpc_types.WriteAnalogWaveformsRequest(
3786
+ task=task_handle,
3787
+ auto_start=auto_start,
3788
+ timeout=timeout,
3789
+ waveforms=grpc_waveforms
3790
+ ))
3791
+
3792
+ self._check_for_error_from_response(response.status, samps_per_chan_written=response.samps_per_chan_written)
3793
+ return response.samps_per_chan_written
3675
3794
 
3676
3795
  def write_digital_waveform(
3677
3796
  self,
@@ -3680,16 +3799,31 @@ class GrpcStubInterpreter(BaseInterpreter):
3680
3799
  auto_start: bool,
3681
3800
  timeout: float,
3682
3801
  ) -> int:
3683
- raise NotImplementedError
3802
+ return self.write_digital_waveforms(task_handle, [waveform], auto_start, timeout)
3684
3803
 
3685
3804
  def write_digital_waveforms(
3686
3805
  self,
3687
3806
  task_handle: object,
3688
- waveform: Sequence[DigitalWaveform[Any]],
3807
+ waveforms: Sequence[DigitalWaveform[Any]],
3689
3808
  auto_start: bool,
3690
3809
  timeout: float,
3691
3810
  ) -> int:
3692
- raise NotImplementedError
3811
+ assert isinstance(task_handle, Session)
3812
+ num_samps_per_chan = get_num_samps_per_chan(waveforms)
3813
+
3814
+ grpc_waveforms = [digital_waveform_to_protobuf(waveform) for waveform in waveforms]
3815
+
3816
+ response = self._invoke(
3817
+ self._client.WriteDigitalWaveforms,
3818
+ grpc_types.WriteDigitalWaveformsRequest(
3819
+ task=task_handle,
3820
+ auto_start=auto_start,
3821
+ timeout=timeout,
3822
+ waveforms=grpc_waveforms
3823
+ ))
3824
+
3825
+ self._check_for_error_from_response(response.status, samps_per_chan_written=response.samps_per_chan_written)
3826
+ return response.samps_per_chan_written
3693
3827
 
3694
3828
  def _assign_numpy_array(numpy_array, grpc_array):
3695
3829
  """
@@ -10,7 +10,7 @@ import subprocess # nosec: B404
10
10
  import sys
11
11
  import tempfile
12
12
  import zipfile
13
- from typing import Generator
13
+ from collections.abc import Generator
14
14
  from urllib.parse import urlparse
15
15
 
16
16
  import click
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "Windows": [
3
3
  {
4
- "Version": "25.5.0",
5
- "Release": "2025Q3",
6
- "Location": "https://download.ni.com/support/nipkg/products/ni-d/ni-daqmx/25.5/online/ni-daqmx_25.5_online.exe",
4
+ "Version": "25.8.0",
5
+ "Release": "2025Q4",
6
+ "Location": "https://download.ni.com/support/nipkg/products/ni-d/ni-daqmx/25.8/online/ni-daqmx_25.8_online.exe",
7
7
  "supportedOS": [
8
8
  "Windows 11",
9
9
  "Windows Server 2022 64-bit",
@@ -15,10 +15,10 @@
15
15
  ],
16
16
  "Linux": [
17
17
  {
18
- "Version": "25.5.0",
19
- "Release": "2025Q3",
18
+ "Version": "25.8.0",
19
+ "Release": "2025Q4",
20
20
  "_comment": "Location url must be of the format 'https://download.ni.com/support/softlib/MasterRepository/LinuxDrivers<Release>/NILinux<Release>DeviceDrivers.zip'. Any change to the format will require a change in the code.",
21
- "Location": "https://download.ni.com/support/softlib/MasterRepository/LinuxDrivers2025Q3/NILinux2025Q3DeviceDrivers.zip",
21
+ "Location": "https://download.ni.com/support/softlib/MasterRepository/LinuxDrivers2025Q4/NILinux2025Q4DeviceDrivers.zip",
22
22
  "supportedOS": [
23
23
  "ubuntu 20.04",
24
24
  "ubuntu 22.04",
@@ -17,7 +17,7 @@ from nidaqmx.errors import (
17
17
  )
18
18
 
19
19
  if TYPE_CHECKING:
20
- from typing_extensions import TypeAlias
20
+ from typing import TypeAlias
21
21
 
22
22
 
23
23
  _DAQ_NOT_FOUND_MESSAGE = (