nidaqmx 1.2.0.dev1__tar.gz → 1.3.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.
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/PKG-INFO +9 -6
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/README.rst +4 -1
- nidaqmx-1.3.0.dev0/generated/nidaqmx/__init__.py +31 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/__main__.py +6 -3
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_base_interpreter.py +104 -2
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_bitfield_utils.py +8 -11
- nidaqmx-1.3.0.dev0/generated/nidaqmx/_dotenvpath.py +73 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/_feature_toggles.py +162 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_grpc_interpreter.py +91 -1
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_grpc_time.py +13 -10
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_install_daqmx.py +23 -64
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_installer_metadata.json +6 -6
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_lib.py +72 -62
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_lib_time.py +31 -19
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_library_interpreter.py +766 -5
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_linux_installation_commands.py +5 -6
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_time.py +10 -9
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/constants.py +11 -1
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/errors.py +73 -71
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/grpc_session_options.py +19 -14
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/__init__.py +37 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_analog_multi_channel_reader.py +235 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_analog_single_channel_reader.py +193 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_analog_unscaled_reader.py +352 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_channel_reader_base.py +128 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_counter_reader.py +529 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_digital_multi_channel_reader.py +581 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_digital_single_channel_reader.py +472 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_readers/_power_readers.py +397 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/__init__.py +34 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_analog_multi_channel_writer.py +137 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_analog_single_channel_writer.py +119 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_analog_unscaled_writer.py +185 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_channel_writer_base.py +172 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_counter_writer.py +254 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_digital_multi_channel_writer.py +365 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/stream_writers/_digital_single_channel_writer.py +322 -0
- nidaqmx-1.3.0.dev0/generated/nidaqmx/system/__init__.py +19 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_collections/device_collection.py +27 -26
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_collections/persisted_channel_collection.py +36 -29
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_collections/persisted_scale_collection.py +30 -26
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_collections/persisted_task_collection.py +30 -25
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_collections/physical_channel_collection.py +86 -75
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_watchdog_modules/expiration_states_collection.py +14 -12
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/storage/__init__.py +3 -1
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/storage/persisted_channel.py +27 -34
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/storage/persisted_scale.py +28 -36
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/storage/persisted_task.py +28 -36
- nidaqmx-1.3.0.dev0/generated/nidaqmx/task/__init__.py +15 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/_in_stream.py +18 -2
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/_task.py +718 -331
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/_timing.py +454 -39
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/__init__.py +12 -2
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/__init__.py +12 -2
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_channel_collection.py +30 -34
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/__init__.py +11 -2
- nidaqmx-1.3.0.dev0/generated/nidaqmx/types.py +71 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/utils.py +41 -39
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/pyproject.toml +70 -31
- nidaqmx-1.2.0.dev1/generated/nidaqmx/__init__.py +0 -17
- nidaqmx-1.2.0.dev1/generated/nidaqmx/stream_readers.py +0 -2454
- nidaqmx-1.2.0.dev1/generated/nidaqmx/stream_writers.py +0 -1401
- nidaqmx-1.2.0.dev1/generated/nidaqmx/system/__init__.py +0 -9
- nidaqmx-1.2.0.dev1/generated/nidaqmx/task/__init__.py +0 -9
- nidaqmx-1.2.0.dev1/generated/nidaqmx/types.py +0 -69
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/LICENSE +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/__init__.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2.pyi +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2_grpc.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/data_moniker_pb2_grpc.pyi +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2.pyi +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2_grpc.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/nidaqmx_pb2_grpc.pyi +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/session_pb2.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/session_pb2.pyi +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/session_pb2_grpc.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/_stubs/session_pb2_grpc.pyi +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/error_codes.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/scale.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_collections/__init__.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_watchdog_modules/__init__.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/_watchdog_modules/expiration_state.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/device.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/physical_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/system.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/system/watchdog.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/_export_signals.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/_out_stream.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_ai_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_ao_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_ci_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_co_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_di_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/channels/_do_channel.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_ai_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_ao_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_ci_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_co_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_di_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/collections/_do_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/_arm_start_trigger.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/_handshake_trigger.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/_pause_trigger.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/_reference_trigger.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/_start_trigger.py +0 -0
- {nidaqmx-1.2.0.dev1 → nidaqmx-1.3.0.dev0}/generated/nidaqmx/task/triggering/_triggers.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: nidaqmx
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0.dev0
|
|
4
4
|
Summary: NI-DAQmx Python API
|
|
5
|
-
Home-page: https://github.com/ni/nidaqmx-python
|
|
6
5
|
License: MIT
|
|
7
6
|
Keywords: nidaqmx,nidaq,daqmx,daq
|
|
8
7
|
Author: NI
|
|
@@ -32,12 +31,13 @@ Requires-Dist: deprecation (>=2.1)
|
|
|
32
31
|
Requires-Dist: distro (>=1.9.0) ; sys_platform == "linux"
|
|
33
32
|
Requires-Dist: grpcio (>=1.49.0,<2.0) ; extra == "grpc"
|
|
34
33
|
Requires-Dist: hightime (>=0.2.2)
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist: numpy (>=1.
|
|
34
|
+
Requires-Dist: nitypes (>=0.1.0dev10)
|
|
35
|
+
Requires-Dist: numpy (>=1.22) ; python_version >= "3.9" and python_version < "3.13"
|
|
37
36
|
Requires-Dist: numpy (>=2.1) ; python_version >= "3.13" and python_version < "4.0"
|
|
38
37
|
Requires-Dist: protobuf (>=4.21) ; extra == "grpc"
|
|
39
38
|
Requires-Dist: python-decouple (>=3.8)
|
|
40
39
|
Requires-Dist: requests (>=2.25.0)
|
|
40
|
+
Requires-Dist: typing_extensions (>=4.0.0)
|
|
41
41
|
Requires-Dist: tzlocal (>=5.0,<6.0)
|
|
42
42
|
Project-URL: Documentation, https://nidaqmx-python.readthedocs.io
|
|
43
43
|
Project-URL: Repository, https://github.com/ni/nidaqmx-python
|
|
@@ -100,7 +100,10 @@ system.
|
|
|
100
100
|
Python Version Support
|
|
101
101
|
----------------------
|
|
102
102
|
|
|
103
|
-
**nidaqmx** supports CPython 3.9
|
|
103
|
+
**nidaqmx** supports CPython 3.9+.
|
|
104
|
+
|
|
105
|
+
**nidaqmx** supports PyPy3 for non-gRPC use cases. For the status of PyPy support for gRPC,
|
|
106
|
+
see `PyPy support (grpc/grpc#4221) <https://github.com/grpc/grpc/issues/4221>`_.
|
|
104
107
|
|
|
105
108
|
Installation
|
|
106
109
|
============
|
|
@@ -55,7 +55,10 @@ system.
|
|
|
55
55
|
Python Version Support
|
|
56
56
|
----------------------
|
|
57
57
|
|
|
58
|
-
**nidaqmx** supports CPython 3.9
|
|
58
|
+
**nidaqmx** supports CPython 3.9+.
|
|
59
|
+
|
|
60
|
+
**nidaqmx** supports PyPy3 for non-gRPC use cases. For the status of PyPy support for gRPC,
|
|
61
|
+
see `PyPy support (grpc/grpc#4221) <https://github.com/grpc/grpc/issues/4221>`_.
|
|
59
62
|
|
|
60
63
|
Installation
|
|
61
64
|
============
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""The NI-DAQmx API for Python."""
|
|
2
|
+
|
|
3
|
+
from nidaqmx.errors import (
|
|
4
|
+
DaqError,
|
|
5
|
+
DaqReadError,
|
|
6
|
+
DaqResourceWarning,
|
|
7
|
+
DaqWarning,
|
|
8
|
+
DaqWriteError,
|
|
9
|
+
)
|
|
10
|
+
from nidaqmx.grpc_session_options import * # noqa: F403 - 'from nidaqmx.grpc_session_options import *' used; unable to detect undefined names (auto-generated noqa)
|
|
11
|
+
from nidaqmx.scale import Scale
|
|
12
|
+
from nidaqmx.task import Task
|
|
13
|
+
from nidaqmx.types import CtrFreq, CtrTick, CtrTime
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from importlib.metadata import version
|
|
17
|
+
except ImportError:
|
|
18
|
+
from importlib_metadata import version # type: ignore[no-redef]
|
|
19
|
+
|
|
20
|
+
__version__ = version(__name__)
|
|
21
|
+
|
|
22
|
+
__all__ = [ # noqa: F405 - 'errors' may be undefined, or defined from star imports: nidaqmx.grpc_session_options (auto-generated noqa)
|
|
23
|
+
"errors",
|
|
24
|
+
"scale",
|
|
25
|
+
"stream_readers",
|
|
26
|
+
"stream_writers",
|
|
27
|
+
"task",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Do not add a null logging handler. If the application has not configured logging, the
|
|
31
|
+
# default behavior is to log warnings and errors to stderr.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
"""'nidaqmx' command line utility."""
|
|
2
|
+
|
|
1
3
|
from __future__ import annotations
|
|
2
4
|
|
|
3
5
|
import logging
|
|
4
|
-
from typing import Optional
|
|
5
6
|
|
|
6
7
|
import click
|
|
7
8
|
|
|
@@ -16,12 +17,14 @@ from . import _install_daqmx
|
|
|
16
17
|
count=True,
|
|
17
18
|
help="Enable verbose logging. Repeat to increase verbosity.",
|
|
18
19
|
)
|
|
19
|
-
def main(
|
|
20
|
+
def main( # noqa: D103 - Missing docstring in public function (auto-generated noqa)
|
|
21
|
+
verbosity: int,
|
|
22
|
+
) -> None:
|
|
20
23
|
_configure_logging(verbosity)
|
|
21
24
|
|
|
22
25
|
|
|
23
26
|
@main.command()
|
|
24
|
-
def installdriver():
|
|
27
|
+
def installdriver(): # noqa: D103 - Missing docstring in public function (auto-generated noqa)
|
|
25
28
|
_install_daqmx.installdriver()
|
|
26
29
|
|
|
27
30
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# Do not edit this file; it was automatically generated.
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
2
4
|
import abc
|
|
3
|
-
|
|
5
|
+
import numpy
|
|
6
|
+
from nitypes.waveform import AnalogWaveform, DigitalWaveform
|
|
7
|
+
from typing import Any, Sequence
|
|
8
|
+
from nidaqmx.constants import WaveformAttributeMode
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
class BaseEventHandler(abc.ABC):
|
|
@@ -1845,4 +1850,101 @@ class BaseInterpreter(abc.ABC):
|
|
|
1845
1850
|
|
|
1846
1851
|
@abc.abstractmethod
|
|
1847
1852
|
def hash_task_handle(self, task_handle):
|
|
1848
|
-
raise NotImplementedError
|
|
1853
|
+
raise NotImplementedError
|
|
1854
|
+
|
|
1855
|
+
@abc.abstractmethod
|
|
1856
|
+
def read_analog_waveform(
|
|
1857
|
+
self,
|
|
1858
|
+
task_handle: object,
|
|
1859
|
+
number_of_samples_per_channel: int,
|
|
1860
|
+
timeout: float,
|
|
1861
|
+
waveform: AnalogWaveform[numpy.float64],
|
|
1862
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
1863
|
+
) -> int:
|
|
1864
|
+
raise NotImplementedError
|
|
1865
|
+
|
|
1866
|
+
@abc.abstractmethod
|
|
1867
|
+
def read_analog_waveforms(
|
|
1868
|
+
self,
|
|
1869
|
+
task_handle: object,
|
|
1870
|
+
number_of_samples_per_channel: int,
|
|
1871
|
+
timeout: float,
|
|
1872
|
+
waveforms: Sequence[AnalogWaveform[numpy.float64]],
|
|
1873
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
1874
|
+
) -> int:
|
|
1875
|
+
raise NotImplementedError
|
|
1876
|
+
|
|
1877
|
+
@abc.abstractmethod
|
|
1878
|
+
def read_digital_waveform(
|
|
1879
|
+
self,
|
|
1880
|
+
task_handle: object,
|
|
1881
|
+
number_of_samples_per_channel: int,
|
|
1882
|
+
timeout: float,
|
|
1883
|
+
waveform: DigitalWaveform[Any],
|
|
1884
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
1885
|
+
) -> int:
|
|
1886
|
+
raise NotImplementedError
|
|
1887
|
+
|
|
1888
|
+
@abc.abstractmethod
|
|
1889
|
+
def read_digital_waveforms(
|
|
1890
|
+
self,
|
|
1891
|
+
task_handle: object,
|
|
1892
|
+
channel_count: int,
|
|
1893
|
+
number_of_samples_per_channel: int,
|
|
1894
|
+
number_of_signals_per_sample: int,
|
|
1895
|
+
timeout: float,
|
|
1896
|
+
waveforms: Sequence[DigitalWaveform[Any]],
|
|
1897
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
1898
|
+
) -> int:
|
|
1899
|
+
raise NotImplementedError
|
|
1900
|
+
|
|
1901
|
+
@abc.abstractmethod
|
|
1902
|
+
def read_new_digital_waveforms(
|
|
1903
|
+
self,
|
|
1904
|
+
task_handle: object,
|
|
1905
|
+
channel_count: int,
|
|
1906
|
+
number_of_samples_per_channel: int,
|
|
1907
|
+
number_of_signals_per_sample: int,
|
|
1908
|
+
timeout: float,
|
|
1909
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
1910
|
+
) -> Sequence[DigitalWaveform[numpy.uint8]]:
|
|
1911
|
+
raise NotImplementedError
|
|
1912
|
+
|
|
1913
|
+
@abc.abstractmethod
|
|
1914
|
+
def write_analog_waveform(
|
|
1915
|
+
self,
|
|
1916
|
+
task_handle: object,
|
|
1917
|
+
waveform: AnalogWaveform[Any],
|
|
1918
|
+
auto_start: bool,
|
|
1919
|
+
timeout: float
|
|
1920
|
+
) -> int:
|
|
1921
|
+
raise NotImplementedError
|
|
1922
|
+
|
|
1923
|
+
@abc.abstractmethod
|
|
1924
|
+
def write_analog_waveforms(
|
|
1925
|
+
self,
|
|
1926
|
+
task_handle: object,
|
|
1927
|
+
waveforms: Sequence[AnalogWaveform[Any]],
|
|
1928
|
+
auto_start: bool,
|
|
1929
|
+
timeout: float
|
|
1930
|
+
) -> int:
|
|
1931
|
+
raise NotImplementedError
|
|
1932
|
+
|
|
1933
|
+
@abc.abstractmethod
|
|
1934
|
+
def write_digital_waveform(
|
|
1935
|
+
self,
|
|
1936
|
+
task_handle: object,
|
|
1937
|
+
waveform: DigitalWaveform[Any],
|
|
1938
|
+
auto_start: bool,
|
|
1939
|
+
timeout: float,
|
|
1940
|
+
) -> int:
|
|
1941
|
+
raise NotImplementedError
|
|
1942
|
+
|
|
1943
|
+
def write_digital_waveforms(
|
|
1944
|
+
self,
|
|
1945
|
+
task_handle: object,
|
|
1946
|
+
waveform: Sequence[DigitalWaveform[Any]],
|
|
1947
|
+
auto_start: bool,
|
|
1948
|
+
timeout: float,
|
|
1949
|
+
) -> int:
|
|
1950
|
+
raise NotImplementedError
|
|
@@ -1,41 +1,38 @@
|
|
|
1
|
-
def enum_bitfield_to_list(bitfield_value, bitfield_enum_type,
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Converts a bitfield value to a list of enums.
|
|
1
|
+
def enum_bitfield_to_list(bitfield_value, bitfield_enum_type, actual_enum_type):
|
|
2
|
+
"""Converts a bitfield value to a list of enums.
|
|
5
3
|
|
|
6
4
|
Args:
|
|
7
5
|
bitfield_value (int): Specifies the value of the bitfield.
|
|
8
6
|
bitfield_enum_type (enum.Enum): Specifies the bitfield enum type
|
|
9
7
|
from which to mask and extract the enum values.
|
|
10
8
|
actual_enum_type (enum.Enum): Specifies the actual enum type.
|
|
9
|
+
|
|
11
10
|
Returns:
|
|
12
11
|
List[enum.Enum]: Indicates the converted list of enums.
|
|
13
12
|
"""
|
|
14
13
|
supported_values = []
|
|
15
14
|
for bitfield_mask in bitfield_enum_type:
|
|
16
15
|
if bitfield_value & bitfield_mask.value:
|
|
17
|
-
enum_value = next(
|
|
18
|
-
e for e in actual_enum_type if e.name == bitfield_mask.name)
|
|
16
|
+
enum_value = next(e for e in actual_enum_type if e.name == bitfield_mask.name)
|
|
19
17
|
supported_values.append(enum_value)
|
|
20
18
|
|
|
21
19
|
return supported_values
|
|
22
20
|
|
|
23
21
|
|
|
24
22
|
def enum_list_to_bitfield(enum_list, bitfield_enum_type):
|
|
25
|
-
"""
|
|
26
|
-
Converts a list of enums to a bitfield value.
|
|
23
|
+
"""Converts a list of enums to a bitfield value.
|
|
27
24
|
|
|
28
25
|
Args:
|
|
29
26
|
enum_list (List[enum.Enum]): Specifies the list of enums.
|
|
30
27
|
bitfield_enum_type (enum.Enum): Specifies the bitfield enum type
|
|
31
28
|
from which to mask and extract the enum values.
|
|
29
|
+
|
|
32
30
|
Returns:
|
|
33
31
|
int: Indicates the value of the bitfield.
|
|
34
32
|
"""
|
|
35
33
|
bitfield_value = 0
|
|
36
34
|
for enum_value in enum_list:
|
|
37
|
-
bitfield_mask = next(
|
|
38
|
-
b for b in bitfield_enum_type if b.name == enum_value.name)
|
|
35
|
+
bitfield_mask = next(b for b in bitfield_enum_type if b.name == enum_value.name)
|
|
39
36
|
bitfield_value |= bitfield_mask.value
|
|
40
37
|
|
|
41
|
-
return bitfield_value
|
|
38
|
+
return bitfield_value
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import sys
|
|
5
|
+
import traceback
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_dotenv_search_path() -> Path:
|
|
10
|
+
"""Get the search path for loading the `.env` file."""
|
|
11
|
+
# Prefer to load the `.env` file from the current directory or its parents.
|
|
12
|
+
# If the current directory doesn't have a `.env` file, fall back to the
|
|
13
|
+
# script/EXE path or the TestStand code module path.
|
|
14
|
+
cwd = Path.cwd()
|
|
15
|
+
if not _has_dotenv_file(cwd):
|
|
16
|
+
if script_or_exe_path := _get_script_or_exe_path():
|
|
17
|
+
return script_or_exe_path.resolve().parent
|
|
18
|
+
if caller_path := _get_caller_path():
|
|
19
|
+
return caller_path.resolve().parent
|
|
20
|
+
return cwd
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _has_dotenv_file(dir: Path) -> bool:
|
|
24
|
+
"""Check whether the dir or its parents contains a `.env` file."""
|
|
25
|
+
return (dir / ".env").exists() or any((p / ".env").exists() for p in dir.parents)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _get_script_or_exe_path() -> Path | None:
|
|
29
|
+
"""Get the path of the top-level script or PyInstaller EXE, if possible."""
|
|
30
|
+
if getattr(sys, "frozen", False):
|
|
31
|
+
return Path(sys.executable)
|
|
32
|
+
|
|
33
|
+
main_module = sys.modules.get("__main__")
|
|
34
|
+
if main_module:
|
|
35
|
+
script_path = getattr(main_module, "__file__", "")
|
|
36
|
+
if script_path:
|
|
37
|
+
return Path(script_path)
|
|
38
|
+
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_caller_path() -> Path | None:
|
|
43
|
+
"""Get the path of the module calling into this package, if possible."""
|
|
44
|
+
package_path = _get_package_path()
|
|
45
|
+
for frame, _ in traceback.walk_stack(inspect.currentframe()):
|
|
46
|
+
if frame.f_code.co_filename:
|
|
47
|
+
module_path = Path(frame.f_code.co_filename)
|
|
48
|
+
if _exists(module_path) and not module_path.is_relative_to(package_path):
|
|
49
|
+
return module_path
|
|
50
|
+
|
|
51
|
+
return None
|
|
52
|
+
|
|
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
|
+
def _get_package_path() -> Path:
|
|
70
|
+
"""Get the path of this package."""
|
|
71
|
+
module = sys.modules[__package__]
|
|
72
|
+
assert module.__file__ and module.__file__.endswith("__init__.py")
|
|
73
|
+
return Path(module.__file__).parent
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""nidaqmx feature toggles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
import sys
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import TYPE_CHECKING, Callable, TypeVar
|
|
9
|
+
|
|
10
|
+
from decouple import AutoConfig, Undefined, undefined
|
|
11
|
+
|
|
12
|
+
from nidaqmx._dotenvpath import get_dotenv_search_path
|
|
13
|
+
from nidaqmx.errors import FeatureNotSupportedError
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
if sys.version_info >= (3, 10):
|
|
17
|
+
from typing import ParamSpec
|
|
18
|
+
else:
|
|
19
|
+
from typing_extensions import ParamSpec
|
|
20
|
+
|
|
21
|
+
if sys.version_info >= (3, 11):
|
|
22
|
+
from typing import Self
|
|
23
|
+
else:
|
|
24
|
+
from typing_extensions import Self
|
|
25
|
+
|
|
26
|
+
_P = ParamSpec("_P")
|
|
27
|
+
_T = TypeVar("_T")
|
|
28
|
+
|
|
29
|
+
_PREFIX = "NIDAQMX"
|
|
30
|
+
|
|
31
|
+
_config = AutoConfig(str(get_dotenv_search_path()))
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
# Work around decouple's lack of type hints.
|
|
35
|
+
def _config(
|
|
36
|
+
option: str,
|
|
37
|
+
default: _T | Undefined = undefined,
|
|
38
|
+
cast: Callable[[str], _T] | Undefined = undefined,
|
|
39
|
+
) -> _T: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Based on the recipe at https://docs.python.org/3/howto/enum.html
|
|
43
|
+
class _OrderedEnum(Enum):
|
|
44
|
+
def __ge__(self, other: Self) -> bool:
|
|
45
|
+
if self.__class__ is other.__class__:
|
|
46
|
+
return self.value >= other.value
|
|
47
|
+
return NotImplemented
|
|
48
|
+
|
|
49
|
+
def __gt__(self, other: Self) -> bool:
|
|
50
|
+
if self.__class__ is other.__class__:
|
|
51
|
+
return self.value > other.value
|
|
52
|
+
return NotImplemented
|
|
53
|
+
|
|
54
|
+
def __le__(self, other: Self) -> bool:
|
|
55
|
+
if self.__class__ is other.__class__:
|
|
56
|
+
return self.value <= other.value
|
|
57
|
+
return NotImplemented
|
|
58
|
+
|
|
59
|
+
def __lt__(self, other: Self) -> bool:
|
|
60
|
+
if self.__class__ is other.__class__:
|
|
61
|
+
return self.value < other.value
|
|
62
|
+
return NotImplemented
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CodeReadiness(_OrderedEnum):
|
|
66
|
+
"""Indicates whether code is ready to be supported."""
|
|
67
|
+
|
|
68
|
+
RELEASE = 0
|
|
69
|
+
NEXT_RELEASE = 1
|
|
70
|
+
INCOMPLETE = 2
|
|
71
|
+
PROTOTYPE = 3
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _init_code_readiness_level() -> CodeReadiness:
|
|
75
|
+
if _config(f"{_PREFIX}_ALLOW_INCOMPLETE", default=False, cast=bool):
|
|
76
|
+
return CodeReadiness.INCOMPLETE
|
|
77
|
+
elif _config(f"{_PREFIX}_ALLOW_NEXT_RELEASE", default=False, cast=bool):
|
|
78
|
+
return CodeReadiness.NEXT_RELEASE
|
|
79
|
+
else:
|
|
80
|
+
return CodeReadiness.RELEASE
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# This is not public because `from _feature_toggles import CODE_READINESS_LEVEL`
|
|
84
|
+
# is incompatible with the patching performed by the use_code_readiness mark.
|
|
85
|
+
_CODE_READINESS_LEVEL = _init_code_readiness_level()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_code_readiness_level() -> CodeReadiness:
|
|
89
|
+
"""Get the current code readiness level.
|
|
90
|
+
|
|
91
|
+
You can override this in tests by specifying the ``use_code_readiness``
|
|
92
|
+
mark.
|
|
93
|
+
"""
|
|
94
|
+
return _CODE_READINESS_LEVEL
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class FeatureToggle:
|
|
98
|
+
"""A run-time feature toggle."""
|
|
99
|
+
|
|
100
|
+
name: str
|
|
101
|
+
"""The name of the feature."""
|
|
102
|
+
|
|
103
|
+
readiness: CodeReadiness
|
|
104
|
+
"""The code readiness at which this feature is enabled."""
|
|
105
|
+
|
|
106
|
+
def __init__(self, name: str, readiness: CodeReadiness) -> None:
|
|
107
|
+
"""Initialize the feature toggle."""
|
|
108
|
+
assert name == name.upper()
|
|
109
|
+
self.name = name
|
|
110
|
+
self.readiness = readiness
|
|
111
|
+
self._is_enabled_override = None
|
|
112
|
+
# Only read the env var at initialization time.
|
|
113
|
+
if _config(f"{_PREFIX}_ENABLE_{name}", default=False, cast=bool):
|
|
114
|
+
self._is_enabled_override = True
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def is_enabled(self) -> bool:
|
|
118
|
+
"""Indicates whether the feature is currently enabled.
|
|
119
|
+
|
|
120
|
+
You can enable/disable features in tests by specifying the
|
|
121
|
+
``enable_feature_toggle`` or ``disable_feature_toggle`` marks.
|
|
122
|
+
"""
|
|
123
|
+
if self._is_enabled_override is not None:
|
|
124
|
+
return self._is_enabled_override
|
|
125
|
+
return self.readiness <= get_code_readiness_level()
|
|
126
|
+
|
|
127
|
+
def raise_if_disabled(self) -> None:
|
|
128
|
+
"""Raises an error if the feature is disabled."""
|
|
129
|
+
if self.is_enabled:
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
env_vars = f"{_PREFIX}_ENABLE_{self.name}"
|
|
133
|
+
if self.readiness in [CodeReadiness.NEXT_RELEASE, CodeReadiness.INCOMPLETE]:
|
|
134
|
+
env_vars += f" or {_PREFIX}_ALLOW_{self.readiness.name}"
|
|
135
|
+
message = (
|
|
136
|
+
f"The {self.name} feature is not supported at the current code readiness level. "
|
|
137
|
+
f" To enable it, set {env_vars}."
|
|
138
|
+
)
|
|
139
|
+
raise FeatureNotSupportedError(message)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def requires_feature(
|
|
143
|
+
feature_toggle: FeatureToggle,
|
|
144
|
+
) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]:
|
|
145
|
+
"""Decorator specifying that the function requires the specified feature toggle."""
|
|
146
|
+
|
|
147
|
+
def decorator(func: Callable[_P, _T]) -> Callable[_P, _T]:
|
|
148
|
+
@functools.wraps(func)
|
|
149
|
+
def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _T:
|
|
150
|
+
feature_toggle.raise_if_disabled()
|
|
151
|
+
return func(*args, **kwargs)
|
|
152
|
+
|
|
153
|
+
return wrapper
|
|
154
|
+
|
|
155
|
+
return decorator
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# --------------------------------------
|
|
159
|
+
# Define feature toggle constants here:
|
|
160
|
+
# --------------------------------------
|
|
161
|
+
|
|
162
|
+
WAVEFORM_SUPPORT = FeatureToggle("WAVEFORM_SUPPORT", CodeReadiness.INCOMPLETE)
|
|
@@ -5,7 +5,8 @@ import logging
|
|
|
5
5
|
import threading
|
|
6
6
|
import typing
|
|
7
7
|
import warnings
|
|
8
|
-
from
|
|
8
|
+
from nitypes.waveform import AnalogWaveform, DigitalWaveform
|
|
9
|
+
from typing import Any, Callable, Generic, Sequence, TypeVar
|
|
9
10
|
|
|
10
11
|
import google.protobuf.message
|
|
11
12
|
from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
|
|
@@ -17,6 +18,7 @@ from nidaqmx._base_interpreter import BaseEventHandler, BaseInterpreter
|
|
|
17
18
|
from nidaqmx._stubs import nidaqmx_pb2 as grpc_types
|
|
18
19
|
from nidaqmx._stubs import nidaqmx_pb2_grpc as nidaqmx_grpc
|
|
19
20
|
from nidaqmx._stubs import session_pb2 as session_grpc_types
|
|
21
|
+
from nidaqmx.constants import WaveformAttributeMode
|
|
20
22
|
from nidaqmx.error_codes import DAQmxErrors
|
|
21
23
|
from nidaqmx._grpc_time import convert_time_to_timestamp, convert_timestamp_to_time
|
|
22
24
|
|
|
@@ -3600,6 +3602,94 @@ class GrpcStubInterpreter(BaseInterpreter):
|
|
|
3600
3602
|
def internal_get_last_created_chan(self):
|
|
3601
3603
|
raise NotImplementedError
|
|
3602
3604
|
|
|
3605
|
+
def read_analog_waveform(
|
|
3606
|
+
self,
|
|
3607
|
+
task_handle: object,
|
|
3608
|
+
number_of_samples_per_channel: int,
|
|
3609
|
+
timeout: float,
|
|
3610
|
+
waveform: AnalogWaveform[numpy.float64],
|
|
3611
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
3612
|
+
) -> int:
|
|
3613
|
+
raise NotImplementedError
|
|
3614
|
+
|
|
3615
|
+
def read_analog_waveforms(
|
|
3616
|
+
self,
|
|
3617
|
+
task_handle: object,
|
|
3618
|
+
number_of_samples_per_channel: int,
|
|
3619
|
+
timeout: float,
|
|
3620
|
+
waveforms: Sequence[AnalogWaveform[numpy.float64]],
|
|
3621
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
3622
|
+
) -> int:
|
|
3623
|
+
raise NotImplementedError
|
|
3624
|
+
|
|
3625
|
+
def read_digital_waveform(
|
|
3626
|
+
self,
|
|
3627
|
+
task_handle: object,
|
|
3628
|
+
number_of_samples_per_channel: int,
|
|
3629
|
+
timeout: float,
|
|
3630
|
+
waveform: DigitalWaveform[Any],
|
|
3631
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
3632
|
+
) -> int:
|
|
3633
|
+
raise NotImplementedError
|
|
3634
|
+
|
|
3635
|
+
def read_digital_waveforms(
|
|
3636
|
+
self,
|
|
3637
|
+
task_handle: object,
|
|
3638
|
+
channel_count: int,
|
|
3639
|
+
number_of_samples_per_channel: int,
|
|
3640
|
+
number_of_signals_per_sample: int,
|
|
3641
|
+
timeout: float,
|
|
3642
|
+
waveforms: Sequence[DigitalWaveform[Any]],
|
|
3643
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
3644
|
+
) -> int:
|
|
3645
|
+
raise NotImplementedError
|
|
3646
|
+
|
|
3647
|
+
def read_new_digital_waveforms(
|
|
3648
|
+
self,
|
|
3649
|
+
task_handle: object,
|
|
3650
|
+
channel_count: int,
|
|
3651
|
+
number_of_samples_per_channel: int,
|
|
3652
|
+
number_of_signals_per_sample: int,
|
|
3653
|
+
timeout: float,
|
|
3654
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
3655
|
+
) -> Sequence[DigitalWaveform[numpy.uint8]]:
|
|
3656
|
+
raise NotImplementedError
|
|
3657
|
+
|
|
3658
|
+
def write_analog_waveform(
|
|
3659
|
+
self,
|
|
3660
|
+
task_handle: object,
|
|
3661
|
+
waveform: AnalogWaveform[typing.Any],
|
|
3662
|
+
auto_start: bool,
|
|
3663
|
+
timeout: float
|
|
3664
|
+
) -> int:
|
|
3665
|
+
raise NotImplementedError
|
|
3666
|
+
|
|
3667
|
+
def write_analog_waveforms(
|
|
3668
|
+
self,
|
|
3669
|
+
task_handle: object,
|
|
3670
|
+
waveforms: Sequence[AnalogWaveform[typing.Any]],
|
|
3671
|
+
auto_start: bool,
|
|
3672
|
+
timeout: float
|
|
3673
|
+
) -> int:
|
|
3674
|
+
raise NotImplementedError
|
|
3675
|
+
|
|
3676
|
+
def write_digital_waveform(
|
|
3677
|
+
self,
|
|
3678
|
+
task_handle: object,
|
|
3679
|
+
waveform: DigitalWaveform[Any],
|
|
3680
|
+
auto_start: bool,
|
|
3681
|
+
timeout: float,
|
|
3682
|
+
) -> int:
|
|
3683
|
+
raise NotImplementedError
|
|
3684
|
+
|
|
3685
|
+
def write_digital_waveforms(
|
|
3686
|
+
self,
|
|
3687
|
+
task_handle: object,
|
|
3688
|
+
waveform: Sequence[DigitalWaveform[Any]],
|
|
3689
|
+
auto_start: bool,
|
|
3690
|
+
timeout: float,
|
|
3691
|
+
) -> int:
|
|
3692
|
+
raise NotImplementedError
|
|
3603
3693
|
|
|
3604
3694
|
def _assign_numpy_array(numpy_array, grpc_array):
|
|
3605
3695
|
"""
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from datetime import timezone
|
|
4
|
-
from datetime import datetime as std_datetime
|
|
5
|
-
from datetime import tzinfo as dt_tzinfo
|
|
6
|
-
from hightime import datetime as ht_datetime
|
|
7
|
-
from hightime import timedelta as ht_timedelta
|
|
8
|
-
from typing import Optional, Union
|
|
9
|
-
from nidaqmx._time import _convert_to_desired_timezone
|
|
3
|
+
from datetime import datetime as std_datetime, timezone, tzinfo as dt_tzinfo
|
|
10
4
|
|
|
11
5
|
from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
|
|
6
|
+
from hightime import datetime as ht_datetime, timedelta as ht_timedelta
|
|
7
|
+
|
|
8
|
+
from nidaqmx._time import _convert_to_desired_timezone
|
|
12
9
|
|
|
13
10
|
# 66 years, 17 leap days = 24107 days = 2082844800 seconds
|
|
14
11
|
_BIAS_FROM_1970_EPOCH = 2082844800
|
|
@@ -22,7 +19,10 @@ _YS_PER_FS = 10**9
|
|
|
22
19
|
|
|
23
20
|
_EPOCH_1970 = ht_datetime(1970, 1, 1, tzinfo=timezone.utc)
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
|
|
23
|
+
def convert_time_to_timestamp( # noqa: D103 - Missing docstring in public function (auto-generated noqa)
|
|
24
|
+
dt: std_datetime | ht_datetime, ts: GrpcTimestamp | None = None
|
|
25
|
+
) -> GrpcTimestamp:
|
|
26
26
|
seconds_since_1970 = 0
|
|
27
27
|
|
|
28
28
|
if ts is None:
|
|
@@ -44,10 +44,13 @@ def convert_time_to_timestamp(dt: std_datetime | ht_datetime, ts: GrpcTimestamp
|
|
|
44
44
|
ts.FromNanoseconds(seconds_since_1970 * _NS_PER_S + nanos)
|
|
45
45
|
return ts
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
|
|
48
|
+
def convert_timestamp_to_time( # noqa: D103 - Missing docstring in public function (auto-generated noqa)
|
|
49
|
+
ts: GrpcTimestamp, tzinfo: dt_tzinfo | None = None
|
|
50
|
+
) -> ht_datetime:
|
|
48
51
|
total_nanos = ts.ToNanoseconds()
|
|
49
52
|
seconds, nanos = divmod(total_nanos, _NS_PER_S)
|
|
50
53
|
# Convert the nanoseconds to yoctoseconds.
|
|
51
54
|
total_yoctoseconds = int(round(_YS_PER_NS * nanos))
|
|
52
|
-
dt = _EPOCH_1970 + ht_timedelta(seconds
|
|
55
|
+
dt = _EPOCH_1970 + ht_timedelta(seconds=seconds) + ht_timedelta(yoctoseconds=total_yoctoseconds)
|
|
53
56
|
return _convert_to_desired_timezone(dt, tzinfo)
|