ni.measurementlink.sessionmanagement.v1.client 0.1.0.dev0__py3-none-any.whl → 0.1.0.dev2__py3-none-any.whl
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.
Potentially problematic release.
This version of ni.measurementlink.sessionmanagement.v1.client might be problematic. Click here for more details.
- ni/measurementlink/sessionmanagement/v1/client/_annotations.py +81 -0
- ni/measurementlink/sessionmanagement/v1/client/_client.py +44 -52
- ni/measurementlink/sessionmanagement/v1/client/_client_base.py +100 -0
- ni/measurementlink/sessionmanagement/v1/client/_drivers/_configuration.py +3 -2
- ni/measurementlink/sessionmanagement/v1/client/_reservation.py +8 -8
- ni/measurementlink/sessionmanagement/v1/client/_types.py +18 -0
- {ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev0.dist-info → ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev2.dist-info}/METADATA +4 -3
- {ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev0.dist-info → ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev2.dist-info}/RECORD +9 -7
- {ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev0.dist-info → ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import socket
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from ni.measurementlink.sessionmanagement.v1.annotations import (
|
|
8
|
+
REGISTERED_HOSTNAME,
|
|
9
|
+
REGISTERED_IPADDRESS,
|
|
10
|
+
REGISTERED_USERNAME,
|
|
11
|
+
RESERVED_HOSTNAME,
|
|
12
|
+
RESERVED_IPADDRESS,
|
|
13
|
+
RESERVED_USERNAME,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_machine_details() -> tuple[dict[str, str], dict[str, str]]:
|
|
18
|
+
"""Get the machine details for reserved and registered annotations."""
|
|
19
|
+
hostname = _get_hostname()
|
|
20
|
+
username = _get_username()
|
|
21
|
+
ip_address = _get_ip_address()
|
|
22
|
+
|
|
23
|
+
reserved = {
|
|
24
|
+
RESERVED_HOSTNAME: hostname,
|
|
25
|
+
RESERVED_USERNAME: username,
|
|
26
|
+
RESERVED_IPADDRESS: ip_address,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
registered = {
|
|
30
|
+
REGISTERED_HOSTNAME: hostname,
|
|
31
|
+
REGISTERED_USERNAME: username,
|
|
32
|
+
REGISTERED_IPADDRESS: ip_address,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return reserved, registered
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def remove_reservation_annotations(annotations: dict[str, str] | None) -> dict[str, str]:
|
|
39
|
+
"""Remove reserved annotations from the provided annotations."""
|
|
40
|
+
if annotations is None:
|
|
41
|
+
return {}
|
|
42
|
+
reservation_keys = {
|
|
43
|
+
RESERVED_HOSTNAME,
|
|
44
|
+
RESERVED_USERNAME,
|
|
45
|
+
RESERVED_IPADDRESS,
|
|
46
|
+
}
|
|
47
|
+
return {k: v for k, v in annotations.items() if k not in reservation_keys}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _get_hostname() -> str:
|
|
51
|
+
if sys.platform == "win32":
|
|
52
|
+
try:
|
|
53
|
+
import win32api # pyright: ignore[reportMissingModuleSource]
|
|
54
|
+
|
|
55
|
+
return win32api.GetComputerName()
|
|
56
|
+
except Exception:
|
|
57
|
+
return ""
|
|
58
|
+
else:
|
|
59
|
+
return socket.gethostname()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _get_username() -> str:
|
|
63
|
+
if sys.platform == "win32":
|
|
64
|
+
try:
|
|
65
|
+
import win32api # pyright: ignore[reportMissingModuleSource]
|
|
66
|
+
|
|
67
|
+
return win32api.GetUserName()
|
|
68
|
+
except Exception:
|
|
69
|
+
return ""
|
|
70
|
+
else:
|
|
71
|
+
return os.environ.get("USER", "")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _get_ip_address() -> str:
|
|
75
|
+
try:
|
|
76
|
+
ipv4_addresses = [
|
|
77
|
+
info[4][0] for info in socket.getaddrinfo(socket.gethostname(), None, socket.AF_INET)
|
|
78
|
+
]
|
|
79
|
+
return str(ipv4_addresses[0]) if ipv4_addresses else ""
|
|
80
|
+
except Exception:
|
|
81
|
+
return ""
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
-
import threading
|
|
7
6
|
import warnings
|
|
8
7
|
from collections.abc import Iterable, Mapping
|
|
9
8
|
|
|
@@ -14,6 +13,13 @@ import ni.measurementlink.sessionmanagement.v1.session_management_service_pb2_gr
|
|
|
14
13
|
from ni.measurementlink.discovery.v1.client import DiscoveryClient
|
|
15
14
|
from ni_grpc_extensions.channelpool import GrpcChannelPool
|
|
16
15
|
|
|
16
|
+
from ni.measurementlink.sessionmanagement.v1.client._annotations import (
|
|
17
|
+
get_machine_details,
|
|
18
|
+
remove_reservation_annotations,
|
|
19
|
+
)
|
|
20
|
+
from ni.measurementlink.sessionmanagement.v1.client._client_base import (
|
|
21
|
+
GrpcServiceClientBase,
|
|
22
|
+
)
|
|
17
23
|
from ni.measurementlink.sessionmanagement.v1.client._constants import (
|
|
18
24
|
GRPC_SERVICE_CLASS,
|
|
19
25
|
GRPC_SERVICE_INTERFACE_NAME,
|
|
@@ -32,8 +38,12 @@ from ni.measurementlink.sessionmanagement.v1.client._types import (
|
|
|
32
38
|
_logger = logging.getLogger(__name__)
|
|
33
39
|
|
|
34
40
|
|
|
35
|
-
class SessionManagementClient
|
|
36
|
-
|
|
41
|
+
class SessionManagementClient(
|
|
42
|
+
GrpcServiceClientBase[session_management_service_pb2_grpc.SessionManagementServiceStub]
|
|
43
|
+
):
|
|
44
|
+
"""Client for accessing the NI Session Management Service via gRPC."""
|
|
45
|
+
|
|
46
|
+
__slots__ = ("_reserved_annotations", "_registered_annotations")
|
|
37
47
|
|
|
38
48
|
def __init__(
|
|
39
49
|
self,
|
|
@@ -42,54 +52,16 @@ class SessionManagementClient:
|
|
|
42
52
|
grpc_channel: grpc.Channel | None = None,
|
|
43
53
|
grpc_channel_pool: GrpcChannelPool | None = None,
|
|
44
54
|
) -> None:
|
|
45
|
-
"""Initialize
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
discovery_client
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self._discovery_client = discovery_client
|
|
56
|
-
self._grpc_channel_pool = grpc_channel_pool
|
|
57
|
-
self._stub: session_management_service_pb2_grpc.SessionManagementServiceStub | None = None
|
|
58
|
-
|
|
59
|
-
if grpc_channel is not None:
|
|
60
|
-
self._stub = session_management_service_pb2_grpc.SessionManagementServiceStub(
|
|
61
|
-
grpc_channel
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
def _get_stub(self) -> session_management_service_pb2_grpc.SessionManagementServiceStub:
|
|
65
|
-
if self._stub is None:
|
|
66
|
-
with self._initialization_lock:
|
|
67
|
-
if self._grpc_channel_pool is None:
|
|
68
|
-
_logger.debug("Creating unshared GrpcChannelPool.")
|
|
69
|
-
self._grpc_channel_pool = GrpcChannelPool()
|
|
70
|
-
if self._discovery_client is None:
|
|
71
|
-
_logger.debug("Creating unshared DiscoveryClient.")
|
|
72
|
-
self._discovery_client = DiscoveryClient(
|
|
73
|
-
grpc_channel_pool=self._grpc_channel_pool
|
|
74
|
-
)
|
|
75
|
-
if self._stub is None:
|
|
76
|
-
compute_nodes = self._discovery_client.enumerate_compute_nodes()
|
|
77
|
-
remote_compute_nodes = [node for node in compute_nodes if not node.is_local]
|
|
78
|
-
# Use remote node URL as deployment target if only one remote node is found.
|
|
79
|
-
# If more than one remote node exists, use empty string for deployment target.
|
|
80
|
-
first_remote_node_url = (
|
|
81
|
-
remote_compute_nodes[0].url if len(remote_compute_nodes) == 1 else ""
|
|
82
|
-
)
|
|
83
|
-
service_location = self._discovery_client.resolve_service(
|
|
84
|
-
provided_interface=GRPC_SERVICE_INTERFACE_NAME,
|
|
85
|
-
deployment_target=first_remote_node_url,
|
|
86
|
-
service_class=GRPC_SERVICE_CLASS,
|
|
87
|
-
)
|
|
88
|
-
channel = self._grpc_channel_pool.get_channel(service_location.insecure_address)
|
|
89
|
-
self._stub = session_management_service_pb2_grpc.SessionManagementServiceStub(
|
|
90
|
-
channel
|
|
91
|
-
)
|
|
92
|
-
return self._stub
|
|
55
|
+
"""Initialize a SessionManagementClient instance."""
|
|
56
|
+
self._reserved_annotations, self._registered_annotations = get_machine_details()
|
|
57
|
+
super().__init__(
|
|
58
|
+
discovery_client=discovery_client,
|
|
59
|
+
grpc_channel=grpc_channel,
|
|
60
|
+
grpc_channel_pool=grpc_channel_pool,
|
|
61
|
+
service_interface_name=GRPC_SERVICE_INTERFACE_NAME,
|
|
62
|
+
service_class=GRPC_SERVICE_CLASS,
|
|
63
|
+
stub_class=session_management_service_pb2_grpc.SessionManagementServiceStub,
|
|
64
|
+
)
|
|
93
65
|
|
|
94
66
|
def reserve_session(
|
|
95
67
|
self,
|
|
@@ -214,6 +186,7 @@ class SessionManagementClient:
|
|
|
214
186
|
request = session_management_service_pb2.ReserveSessionsRequest(
|
|
215
187
|
pin_map_context=context._to_grpc(),
|
|
216
188
|
timeout_in_milliseconds=_timeout_to_milliseconds(timeout),
|
|
189
|
+
annotations=self._reserved_annotations,
|
|
217
190
|
)
|
|
218
191
|
if instrument_type_id is not None:
|
|
219
192
|
request.instrument_type_id = instrument_type_id
|
|
@@ -239,6 +212,15 @@ class SessionManagementClient:
|
|
|
239
212
|
Args:
|
|
240
213
|
session_info: Sessions to register.
|
|
241
214
|
"""
|
|
215
|
+
session_info = [
|
|
216
|
+
info._replace(
|
|
217
|
+
annotations={
|
|
218
|
+
**remove_reservation_annotations(info.annotations),
|
|
219
|
+
**self._registered_annotations,
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
for info in session_info
|
|
223
|
+
]
|
|
242
224
|
request = session_management_service_pb2.RegisterSessionsRequest(
|
|
243
225
|
sessions=(info._to_grpc_v1() for info in session_info),
|
|
244
226
|
)
|
|
@@ -287,7 +269,8 @@ class SessionManagementClient:
|
|
|
287
269
|
unreserve them.
|
|
288
270
|
"""
|
|
289
271
|
request = session_management_service_pb2.ReserveAllRegisteredSessionsRequest(
|
|
290
|
-
timeout_in_milliseconds=_timeout_to_milliseconds(timeout)
|
|
272
|
+
timeout_in_milliseconds=_timeout_to_milliseconds(timeout),
|
|
273
|
+
annotations=self._reserved_annotations,
|
|
291
274
|
)
|
|
292
275
|
if instrument_type_id is not None:
|
|
293
276
|
request.instrument_type_id = instrument_type_id
|
|
@@ -307,6 +290,15 @@ class SessionManagementClient:
|
|
|
307
290
|
Args:
|
|
308
291
|
multiplexer_session_info: Sessions to register.
|
|
309
292
|
"""
|
|
293
|
+
multiplexer_session_info = [
|
|
294
|
+
info._replace(
|
|
295
|
+
annotations={
|
|
296
|
+
**remove_reservation_annotations(info.annotations),
|
|
297
|
+
**self._registered_annotations,
|
|
298
|
+
}
|
|
299
|
+
)
|
|
300
|
+
for info in multiplexer_session_info
|
|
301
|
+
]
|
|
310
302
|
request = session_management_service_pb2.RegisterMultiplexerSessionsRequest(
|
|
311
303
|
multiplexer_sessions=(info._to_grpc_v1() for info in multiplexer_session_info),
|
|
312
304
|
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import threading
|
|
5
|
+
from typing import Generic, Protocol, TypeVar
|
|
6
|
+
|
|
7
|
+
import grpc
|
|
8
|
+
from ni.measurementlink.discovery.v1.client import DiscoveryClient
|
|
9
|
+
from ni_grpc_extensions.channelpool import GrpcChannelPool
|
|
10
|
+
|
|
11
|
+
_logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class StubProtocol(Protocol):
|
|
15
|
+
"""Protocol for gRPC stub classes."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, channel: grpc.Channel) -> None:
|
|
18
|
+
"""Initialize the gRPC client."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
TStub = TypeVar("TStub", bound=StubProtocol)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GrpcServiceClientBase(Generic[TStub]):
|
|
25
|
+
"""Base class for NI gRPC service clients."""
|
|
26
|
+
|
|
27
|
+
__slots__ = (
|
|
28
|
+
"_initialization_lock",
|
|
29
|
+
"_discovery_client",
|
|
30
|
+
"_grpc_channel_pool",
|
|
31
|
+
"_stub",
|
|
32
|
+
"_service_interface_name",
|
|
33
|
+
"_service_class",
|
|
34
|
+
"_stub_class",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
_initialization_lock: threading.Lock
|
|
38
|
+
_discovery_client: DiscoveryClient | None
|
|
39
|
+
_grpc_channel_pool: GrpcChannelPool | None
|
|
40
|
+
_stub: TStub | None
|
|
41
|
+
_service_interface_name: str
|
|
42
|
+
_service_class: str
|
|
43
|
+
_stub_class: type[TStub]
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
service_interface_name: str,
|
|
48
|
+
service_class: str,
|
|
49
|
+
stub_class: type[TStub],
|
|
50
|
+
*,
|
|
51
|
+
discovery_client: DiscoveryClient | None = None,
|
|
52
|
+
grpc_channel: grpc.Channel | None = None,
|
|
53
|
+
grpc_channel_pool: GrpcChannelPool | None = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Initialize the gRPC client.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
service_interface_name: The fully qualified name of the service interface.
|
|
59
|
+
service_class: The name of the service class.
|
|
60
|
+
stub_class: The gRPC stub class for the service.
|
|
61
|
+
discovery_client: An optional discovery client (recommended).
|
|
62
|
+
grpc_channel: An optional pin map gRPC channel.
|
|
63
|
+
grpc_channel_pool: An optional gRPC channel pool (recommended).
|
|
64
|
+
"""
|
|
65
|
+
self._initialization_lock = threading.Lock()
|
|
66
|
+
self._discovery_client = discovery_client
|
|
67
|
+
self._grpc_channel_pool = grpc_channel_pool
|
|
68
|
+
self._stub = stub_class(grpc_channel) if grpc_channel is not None else None
|
|
69
|
+
self._service_interface_name = service_interface_name
|
|
70
|
+
self._service_class = service_class
|
|
71
|
+
self._stub_class = stub_class
|
|
72
|
+
|
|
73
|
+
def _get_stub(self) -> TStub:
|
|
74
|
+
if self._stub is None:
|
|
75
|
+
with self._initialization_lock:
|
|
76
|
+
if self._grpc_channel_pool is None:
|
|
77
|
+
_logger.debug("Creating unshared GrpcChannelPool.")
|
|
78
|
+
self._grpc_channel_pool = GrpcChannelPool()
|
|
79
|
+
|
|
80
|
+
if self._discovery_client is None:
|
|
81
|
+
_logger.debug("Creating unshared DiscoveryClient.")
|
|
82
|
+
self._discovery_client = DiscoveryClient(
|
|
83
|
+
grpc_channel_pool=self._grpc_channel_pool
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if self._stub is None:
|
|
87
|
+
compute_nodes = self._discovery_client.enumerate_compute_nodes()
|
|
88
|
+
remote_nodes = [node for node in compute_nodes if not node.is_local]
|
|
89
|
+
target_url = remote_nodes[0].url if len(remote_nodes) == 1 else ""
|
|
90
|
+
|
|
91
|
+
service_location = self._discovery_client.resolve_service(
|
|
92
|
+
provided_interface=self._service_interface_name,
|
|
93
|
+
deployment_target=target_url,
|
|
94
|
+
service_class=self._service_class,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
channel = self._grpc_channel_pool.get_channel(service_location.insecure_address)
|
|
98
|
+
self._stub = self._stub_class(channel)
|
|
99
|
+
|
|
100
|
+
return self._stub
|
|
@@ -20,8 +20,6 @@ if TYPE_CHECKING:
|
|
|
20
20
|
|
|
21
21
|
_PREFIX = "MEASUREMENT_PLUGIN"
|
|
22
22
|
|
|
23
|
-
_config = AutoConfig(str(get_dotenv_search_path()))
|
|
24
|
-
|
|
25
23
|
if TYPE_CHECKING:
|
|
26
24
|
# Work around decouple's lack of type hints.
|
|
27
25
|
_T = TypeVar("_T")
|
|
@@ -32,6 +30,9 @@ if TYPE_CHECKING:
|
|
|
32
30
|
cast: Callable[[str], _T] | Undefined = undefined,
|
|
33
31
|
) -> _T: ...
|
|
34
32
|
|
|
33
|
+
else:
|
|
34
|
+
_config = AutoConfig(str(get_dotenv_search_path()))
|
|
35
|
+
|
|
35
36
|
|
|
36
37
|
# ----------------------------------------------------------------------
|
|
37
38
|
# NI Modular Instrument Driver Options
|
|
@@ -172,15 +172,17 @@ class _BaseSessionContainer(abc.ABC):
|
|
|
172
172
|
|
|
173
173
|
@property
|
|
174
174
|
def _discovery_client(self) -> DiscoveryClient:
|
|
175
|
-
|
|
175
|
+
client = self._session_management_client._discovery_client
|
|
176
|
+
if client is None:
|
|
176
177
|
raise ValueError("This method requires a discovery client.")
|
|
177
|
-
return
|
|
178
|
+
return client
|
|
178
179
|
|
|
179
180
|
@property
|
|
180
181
|
def _grpc_channel_pool(self) -> GrpcChannelPool:
|
|
181
|
-
|
|
182
|
+
pool = self._session_management_client._grpc_channel_pool
|
|
183
|
+
if pool is None:
|
|
182
184
|
raise ValueError("This method requires a gRPC channel pool.")
|
|
183
|
-
return
|
|
185
|
+
return pool
|
|
184
186
|
|
|
185
187
|
|
|
186
188
|
class MultiplexerSessionContainer(_BaseSessionContainer):
|
|
@@ -274,9 +276,7 @@ class MultiplexerSessionContainer(_BaseSessionContainer):
|
|
|
274
276
|
return multiplexer_session_infos
|
|
275
277
|
|
|
276
278
|
@contextlib.contextmanager
|
|
277
|
-
def _cache_multiplexer_session(
|
|
278
|
-
self, session_name: str, session: TMultiplexerSession
|
|
279
|
-
) -> Generator[None]: # pyright: ignore[reportInvalidTypeVarUse]
|
|
279
|
+
def _cache_multiplexer_session(self, session_name: str, session: object) -> Generator[None]:
|
|
280
280
|
if session_name in self._multiplexer_session_cache:
|
|
281
281
|
raise RuntimeError(f"Multiplexer session '{session_name}' already exists.")
|
|
282
282
|
self._multiplexer_session_cache[session_name] = session
|
|
@@ -664,7 +664,7 @@ class BaseReservation(_BaseSessionContainer):
|
|
|
664
664
|
self._session_management_client._unreserve_sessions(self._grpc_session_info)
|
|
665
665
|
|
|
666
666
|
@contextlib.contextmanager
|
|
667
|
-
def _cache_session(self, session_name: str, session:
|
|
667
|
+
def _cache_session(self, session_name: str, session: object) -> Generator[None]:
|
|
668
668
|
if session_name in self._session_cache:
|
|
669
669
|
raise RuntimeError(f"Session '{session_name}' already exists.")
|
|
670
670
|
self._session_cache[session_name] = session
|
|
@@ -139,6 +139,13 @@ class SessionInformation(NamedTuple):
|
|
|
139
139
|
This field is None until the appropriate initialize_session(s) method is called.
|
|
140
140
|
"""
|
|
141
141
|
|
|
142
|
+
annotations: dict[str, str] | None = None
|
|
143
|
+
"""Annotations to attach to the session.
|
|
144
|
+
|
|
145
|
+
This field is optional and can be used to store any additional metadata
|
|
146
|
+
related to the session.
|
|
147
|
+
"""
|
|
148
|
+
|
|
142
149
|
def _check_runtime_type(self, session_type: type) -> None:
|
|
143
150
|
if not isinstance(self.session, session_type):
|
|
144
151
|
raise TypeError(
|
|
@@ -162,6 +169,7 @@ class SessionInformation(NamedTuple):
|
|
|
162
169
|
instrument_type_id=other.instrument_type_id,
|
|
163
170
|
session_exists=other.session_exists,
|
|
164
171
|
channel_mappings=[ChannelMapping._from_grpc_v1(m) for m in other.channel_mappings],
|
|
172
|
+
annotations=dict(other.annotations) if other.annotations else None,
|
|
165
173
|
)
|
|
166
174
|
|
|
167
175
|
def _to_grpc_v1(
|
|
@@ -174,6 +182,7 @@ class SessionInformation(NamedTuple):
|
|
|
174
182
|
instrument_type_id=self.instrument_type_id,
|
|
175
183
|
session_exists=self.session_exists,
|
|
176
184
|
channel_mappings=[m._to_grpc_v1() for m in self.channel_mappings],
|
|
185
|
+
annotations=self.annotations if self.annotations else {},
|
|
177
186
|
)
|
|
178
187
|
|
|
179
188
|
|
|
@@ -253,6 +262,13 @@ class MultiplexerSessionInformation(NamedTuple):
|
|
|
253
262
|
This field is None until the appropriate initialize_multiplexer_session(s) method is called.
|
|
254
263
|
"""
|
|
255
264
|
|
|
265
|
+
annotations: dict[str, str] = {}
|
|
266
|
+
"""Annotations to attach to the session.
|
|
267
|
+
|
|
268
|
+
This field is optional and can be used to store any additional metadata
|
|
269
|
+
related to the session.
|
|
270
|
+
"""
|
|
271
|
+
|
|
256
272
|
def _check_runtime_type(self, multiplexer_session_type: type) -> None:
|
|
257
273
|
if not isinstance(self.session, multiplexer_session_type):
|
|
258
274
|
raise TypeError(
|
|
@@ -274,6 +290,7 @@ class MultiplexerSessionInformation(NamedTuple):
|
|
|
274
290
|
resource_name=other.resource_name,
|
|
275
291
|
multiplexer_type_id=other.multiplexer_type_id,
|
|
276
292
|
session_exists=other.session_exists,
|
|
293
|
+
annotations=dict(other.annotations),
|
|
277
294
|
)
|
|
278
295
|
|
|
279
296
|
def _to_grpc_v1(self) -> session_management_service_pb2.MultiplexerSessionInformation:
|
|
@@ -282,6 +299,7 @@ class MultiplexerSessionInformation(NamedTuple):
|
|
|
282
299
|
resource_name=self.resource_name,
|
|
283
300
|
multiplexer_type_id=self.multiplexer_type_id,
|
|
284
301
|
session_exists=self.session_exists,
|
|
302
|
+
annotations=self.annotations,
|
|
285
303
|
)
|
|
286
304
|
|
|
287
305
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ni.measurementlink.sessionmanagement.v1.client
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
4
|
Summary: Client gRPC APIs for the session management service
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: ni-apis,sessionmanagement
|
|
7
7
|
Author: NI
|
|
8
8
|
Author-email: opensource@ni.com
|
|
9
|
-
Maintainer:
|
|
10
|
-
Maintainer-email:
|
|
9
|
+
Maintainer: Joe Friedrichsen
|
|
10
|
+
Maintainer-email: joe.friedrichsen@emerson.com
|
|
11
11
|
Requires-Python: >=3.9,<4.0
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -49,6 +49,7 @@ Requires-Dist: protobuf (>=4.21)
|
|
|
49
49
|
Requires-Dist: python-decouple (>=3.8)
|
|
50
50
|
Requires-Dist: pywin32 (>=303) ; sys_platform == "win32"
|
|
51
51
|
Requires-Dist: traceloggingdynamic (>=1.0) ; sys_platform == "win32"
|
|
52
|
+
Project-URL: Documentation, https://nimeasurementlinksessionmanagementclient.readthedocs.io/en/latest/
|
|
52
53
|
Project-URL: Repository, https://github.com/ni/ni-apis-python
|
|
53
54
|
Description-Content-Type: text/markdown
|
|
54
55
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
ni/measurementlink/sessionmanagement/v1/client/__init__.py,sha256=cUrRh3Be6kKh9KVZ5xeZgxzR-dMcJvIc5Xgq5tf3Xwg,3141
|
|
2
|
-
ni/measurementlink/sessionmanagement/v1/client/
|
|
2
|
+
ni/measurementlink/sessionmanagement/v1/client/_annotations.py,sha256=rmUu2zyqnJSOaDhGwMO3iqu_s_lr4XZgWVYssMYaZ0Y,2106
|
|
3
|
+
ni/measurementlink/sessionmanagement/v1/client/_client.py,sha256=C6A7F8hB0U6nP5jTMH9XfUP37zVZ1GKk9-lA6bycV3k,16509
|
|
4
|
+
ni/measurementlink/sessionmanagement/v1/client/_client_base.py,sha256=tL0kkDQdKwrWEI34Y7DnoqIXv_EGA39q7YPWrN9lpJs,3606
|
|
3
5
|
ni/measurementlink/sessionmanagement/v1/client/_constants.py,sha256=rGRguoyy-ovtkP4jMtVoab4WFdj5WOWn65rkV-1DqkM,1243
|
|
4
6
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/__init__.py,sha256=7p6Ap81Hyfg_qIMZPPeKuQXf3eMhgpKHBwsFbjWZvXc,1707
|
|
5
|
-
ni/measurementlink/sessionmanagement/v1/client/_drivers/_configuration.py,sha256=
|
|
7
|
+
ni/measurementlink/sessionmanagement/v1/client/_drivers/_configuration.py,sha256=FWvPOuDIcJ_GdkpPDWO2m2sFdq27bB7SsbJey6g5q68,3873
|
|
6
8
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/_dotenvpath.py,sha256=dKGHIb_M60z8FkNN0_3Gl2Xk_GoufnXZy3McmjU8d_c,2347
|
|
7
9
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/_grpcdevice.py,sha256=zMcUJe1WHSqNd09BIkNj6pcdC5jRdRYA-4fo4jmvq5k,3798
|
|
8
10
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/_nidaqmx.py,sha256=Q1U-yYvc8bSh4EKZUvVqqXi4qgja6lACgcYqWGY-aeg,2230
|
|
@@ -12,9 +14,9 @@ ni/measurementlink/sessionmanagement/v1/client/_drivers/_nidmm.py,sha256=wJJzIZB
|
|
|
12
14
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/_nifgen.py,sha256=zauQkkgTur8Ww0vhWPvwEi2zC9kTcmu-wqlh-DMAP2s,2605
|
|
13
15
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/_niscope.py,sha256=V0EVuSj08DaeUAQ3uB7GEAWZM19Si49wuPA-PW6pKDQ,2667
|
|
14
16
|
ni/measurementlink/sessionmanagement/v1/client/_drivers/_niswitch.py,sha256=TXE--U5xIlyumBMkqRx8S6qDu6OI1-BH8gRosVgT7t0,3394
|
|
15
|
-
ni/measurementlink/sessionmanagement/v1/client/_reservation.py,sha256=
|
|
16
|
-
ni/measurementlink/sessionmanagement/v1/client/_types.py,sha256=
|
|
17
|
+
ni/measurementlink/sessionmanagement/v1/client/_reservation.py,sha256=CVm07PHqC9LAEVsSKLbPnF3Vxh4NV02utJIA7uxyP_A,109897
|
|
18
|
+
ni/measurementlink/sessionmanagement/v1/client/_types.py,sha256=plIrRwSFZNK-ivtKkmU4pn5WG_2wb3Ves19MP4e88_o,18534
|
|
17
19
|
ni/measurementlink/sessionmanagement/v1/client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
ni_measurementlink_sessionmanagement_v1_client-0.1.0.
|
|
19
|
-
ni_measurementlink_sessionmanagement_v1_client-0.1.0.
|
|
20
|
-
ni_measurementlink_sessionmanagement_v1_client-0.1.0.
|
|
20
|
+
ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev2.dist-info/METADATA,sha256=cuc3oaj1siSkUYHz45k0EIWsTXTRPYAbYWOgmPE0Wz4,3524
|
|
21
|
+
ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
22
|
+
ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev2.dist-info/RECORD,,
|