ni.measurementlink.sessionmanagement.v1.client 0.1.0.dev0__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.

Files changed (20) hide show
  1. ni/measurementlink/sessionmanagement/v1/client/__init__.py +107 -0
  2. ni/measurementlink/sessionmanagement/v1/client/_client.py +405 -0
  3. ni/measurementlink/sessionmanagement/v1/client/_constants.py +32 -0
  4. ni/measurementlink/sessionmanagement/v1/client/_drivers/__init__.py +46 -0
  5. ni/measurementlink/sessionmanagement/v1/client/_drivers/_configuration.py +111 -0
  6. ni/measurementlink/sessionmanagement/v1/client/_drivers/_dotenvpath.py +73 -0
  7. ni/measurementlink/sessionmanagement/v1/client/_drivers/_grpcdevice.py +96 -0
  8. ni/measurementlink/sessionmanagement/v1/client/_drivers/_nidaqmx.py +54 -0
  9. ni/measurementlink/sessionmanagement/v1/client/_drivers/_nidcpower.py +63 -0
  10. ni/measurementlink/sessionmanagement/v1/client/_drivers/_nidigital.py +64 -0
  11. ni/measurementlink/sessionmanagement/v1/client/_drivers/_nidmm.py +64 -0
  12. ni/measurementlink/sessionmanagement/v1/client/_drivers/_nifgen.py +63 -0
  13. ni/measurementlink/sessionmanagement/v1/client/_drivers/_niscope.py +64 -0
  14. ni/measurementlink/sessionmanagement/v1/client/_drivers/_niswitch.py +82 -0
  15. ni/measurementlink/sessionmanagement/v1/client/_reservation.py +2769 -0
  16. ni/measurementlink/sessionmanagement/v1/client/_types.py +507 -0
  17. ni/measurementlink/sessionmanagement/v1/client/py.typed +0 -0
  18. ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev0.dist-info/METADATA +80 -0
  19. ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev0.dist-info/RECORD +20 -0
  20. ni_measurementlink_sessionmanagement_v1_client-0.1.0.dev0.dist-info/WHEEL +4 -0
@@ -0,0 +1,2769 @@
1
+ """Session management reservation classes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import abc
6
+ import contextlib
7
+ import functools
8
+ import sys
9
+ from collections.abc import Generator, Iterable, Mapping, Sequence
10
+ from contextlib import ExitStack
11
+ from functools import cached_property
12
+ from types import TracebackType
13
+ from typing import (
14
+ TYPE_CHECKING,
15
+ AbstractSet,
16
+ Any,
17
+ Callable,
18
+ ContextManager,
19
+ Literal,
20
+ NamedTuple,
21
+ TypeVar,
22
+ cast,
23
+ )
24
+
25
+ import ni.measurementlink.sessionmanagement.v1.session_management_service_pb2 as session_management_service_pb2
26
+ from ni.measurementlink.discovery.v1.client import DiscoveryClient
27
+ from ni_grpc_extensions.channelpool import GrpcChannelPool
28
+
29
+ from ni.measurementlink.sessionmanagement.v1.client._constants import (
30
+ INSTRUMENT_TYPE_NI_DAQMX,
31
+ INSTRUMENT_TYPE_NI_DCPOWER,
32
+ INSTRUMENT_TYPE_NI_DIGITAL_PATTERN,
33
+ INSTRUMENT_TYPE_NI_DMM,
34
+ INSTRUMENT_TYPE_NI_FGEN,
35
+ INSTRUMENT_TYPE_NI_RELAY_DRIVER,
36
+ INSTRUMENT_TYPE_NI_SCOPE,
37
+ SITE_SYSTEM_PINS,
38
+ )
39
+ from ni.measurementlink.sessionmanagement.v1.client._drivers import (
40
+ closing_session,
41
+ closing_session_with_ts_code_module_support,
42
+ )
43
+ from ni.measurementlink.sessionmanagement.v1.client._types import (
44
+ Connection,
45
+ MultiplexerSessionInformation,
46
+ SessionInformation,
47
+ SessionInitializationBehavior,
48
+ TMultiplexerSession,
49
+ TSession,
50
+ TypedConnection,
51
+ TypedConnectionWithMultiplexer,
52
+ TypedMultiplexerSessionInformation,
53
+ TypedSessionInformation,
54
+ )
55
+
56
+ if TYPE_CHECKING:
57
+ # Driver API packages are optional dependencies, so only import them lazily
58
+ # at run time or when type-checking.
59
+ import nidaqmx
60
+ import nidcpower
61
+ import nidigital
62
+ import nidmm
63
+ import nifgen
64
+ import niscope
65
+ import niswitch
66
+
67
+ from ni.measurementlink.sessionmanagement.v1.client._client import ( # circular import
68
+ SessionManagementClient,
69
+ )
70
+
71
+ if sys.version_info >= (3, 11):
72
+ from typing import Self
73
+ else:
74
+ from typing_extensions import Self
75
+
76
+ _T = TypeVar("_T")
77
+
78
+
79
+ def _to_iterable(
80
+ value: _T | Iterable[_T] | None, default: Iterable[_T] | None = None
81
+ ) -> Iterable[_T]:
82
+ if value is None:
83
+ return default or []
84
+ elif isinstance(value, Iterable) and not isinstance(value, str):
85
+ return value
86
+ else:
87
+ return [value] # pyright: ignore[reportReturnType]
88
+
89
+
90
+ # The `dict_view` type is a set-like type. In Python 3.7 and later, dictionaries
91
+ # preserve insertion order.
92
+ #
93
+ # Note: the set difference operator does not preserve order.
94
+ def _to_ordered_set(values: Iterable[_T]) -> AbstractSet[_T]:
95
+ return dict.fromkeys(values).keys()
96
+
97
+
98
+ def _quote(value: str) -> str:
99
+ return f"'{value}'"
100
+
101
+
102
+ def _quote_if_str(value: object) -> str:
103
+ return _quote(value) if isinstance(value, str) else str(value)
104
+
105
+
106
+ def _check_optional_str_param(name: str, value: str | None) -> None:
107
+ if value is not None and not isinstance(value, str):
108
+ raise TypeError(f"The {name} parameter must be a str or None, not {value!r}.")
109
+
110
+
111
+ # Why not generic: the error messages differ by "a" vs. "an"
112
+ def _check_optional_int_param(name: str, value: int | None) -> None:
113
+ if value is not None and not isinstance(value, int):
114
+ raise TypeError(f"The {name} parameter must be an int or None, not {value!r}.")
115
+
116
+
117
+ def _check_matching_criterion(
118
+ name: str, requested_values: Iterable[_T], expected_values: AbstractSet[_T]
119
+ ) -> None:
120
+ if not all(value in expected_values for value in requested_values):
121
+ extra_values_str = ", ".join(
122
+ _quote_if_str(value) for value in requested_values if value not in expected_values
123
+ )
124
+ raise ValueError(f"No reserved connections matched {name} {extra_values_str}.")
125
+
126
+
127
+ # Why not generic: the error messages differ by "reserved connection" vs. "multiplexer session"
128
+ def _check_matching_multiplexer_criterion(
129
+ name: str, requested_values: Iterable[_T], expected_values: AbstractSet[_T]
130
+ ) -> None:
131
+ if not all(value in expected_values for value in requested_values):
132
+ extra_values_str = ", ".join(
133
+ _quote_if_str(value) for value in requested_values if value not in expected_values
134
+ )
135
+ raise ValueError(f"No multiplexer sessions matched {name} {extra_values_str}.")
136
+
137
+
138
+ def _describe_matching_criteria(
139
+ pin_or_relay_names: str | Iterable[str] | None = None,
140
+ sites: int | Iterable[int] | None = None,
141
+ instrument_type_id: str | None = None,
142
+ ) -> str:
143
+ criteria = []
144
+ if pin_or_relay_names is not None:
145
+ pin_or_relay_names = _to_iterable(pin_or_relay_names)
146
+ pin_or_relay_names_str = ", ".join(_quote(pin) for pin in pin_or_relay_names)
147
+ criteria.append(f"pin or relay name(s) {pin_or_relay_names_str}")
148
+ if sites is not None:
149
+ sites = _to_iterable(sites)
150
+ sites_str = ", ".join(str(site) for site in sites)
151
+ criteria.append(f"site(s) {sites_str}")
152
+ if instrument_type_id is not None:
153
+ criteria.append(f"instrument type ID '{instrument_type_id}'")
154
+ return "; ".join(criteria)
155
+
156
+
157
+ class _ConnectionKey(NamedTuple):
158
+ pin_or_relay_name: str
159
+ site: int
160
+ instrument_type_id: str
161
+
162
+
163
+ class _BaseSessionContainer(abc.ABC):
164
+ """Contains session management client and related properties."""
165
+
166
+ def __init__(
167
+ self,
168
+ session_management_client: SessionManagementClient,
169
+ ) -> None:
170
+ """Initialize the base session container."""
171
+ self._session_management_client = session_management_client
172
+
173
+ @property
174
+ def _discovery_client(self) -> DiscoveryClient:
175
+ if not self._session_management_client._discovery_client:
176
+ raise ValueError("This method requires a discovery client.")
177
+ return self._session_management_client._discovery_client
178
+
179
+ @property
180
+ def _grpc_channel_pool(self) -> GrpcChannelPool:
181
+ if not self._session_management_client._grpc_channel_pool:
182
+ raise ValueError("This method requires a gRPC channel pool.")
183
+ return self._session_management_client._grpc_channel_pool
184
+
185
+
186
+ class MultiplexerSessionContainer(_BaseSessionContainer):
187
+ """Manages multiplexer session information."""
188
+
189
+ def __init__(
190
+ self,
191
+ session_management_client: SessionManagementClient,
192
+ multiplexer_session_info: None | (
193
+ Sequence[session_management_service_pb2.MultiplexerSessionInformation]
194
+ ),
195
+ ) -> None:
196
+ """Initialize multiplexer object."""
197
+ super().__init__(session_management_client)
198
+ self._multiplexer_session_cache: dict[str, object] = {}
199
+
200
+ if multiplexer_session_info is not None:
201
+ self._multiplexer_session_info = [
202
+ MultiplexerSessionInformation._from_grpc_v1(info)
203
+ for info in multiplexer_session_info
204
+ ]
205
+ else:
206
+ self._multiplexer_session_info = []
207
+
208
+ @cached_property
209
+ def _multiplexer_type_ids(self) -> AbstractSet[str]:
210
+ return _to_ordered_set(
211
+ sorted(info.multiplexer_type_id for info in self._multiplexer_session_info)
212
+ )
213
+
214
+ @property
215
+ def multiplexer_session_info(self) -> Sequence[MultiplexerSessionInformation]:
216
+ """Multiplexer session information object."""
217
+ if not self._multiplexer_session_cache:
218
+ return self._multiplexer_session_info
219
+
220
+ return [
221
+ info._with_session(self._multiplexer_session_cache.get(info.session_name))
222
+ for info in self._multiplexer_session_info
223
+ ]
224
+
225
+ def __enter__(self: Self) -> Self:
226
+ """Context management protocol. Returns self."""
227
+ return self
228
+
229
+ def __exit__(
230
+ self,
231
+ exc_type: type[BaseException] | None,
232
+ exc_val: BaseException | None,
233
+ traceback: TracebackType | None,
234
+ ) -> None:
235
+ """Context management protocol."""
236
+ pass
237
+
238
+ def _get_multiplexer_session_info_for_resource_name(
239
+ self, multiplexer_resource_name: str
240
+ ) -> MultiplexerSessionInformation | None:
241
+ return next(
242
+ (
243
+ info
244
+ for info in self._multiplexer_session_info
245
+ if info.resource_name == multiplexer_resource_name
246
+ ),
247
+ None,
248
+ )
249
+
250
+ def _get_multiplexer_session_infos_for_type_id(
251
+ self, multiplexer_type_id: str
252
+ ) -> list[MultiplexerSessionInformation]:
253
+ return [
254
+ info
255
+ for info in self._multiplexer_session_info
256
+ if info.multiplexer_type_id == multiplexer_type_id
257
+ ]
258
+
259
+ def _validate_and_get_matching_multiplexer_session_infos(
260
+ self,
261
+ multiplexer_type_ids: Iterable[str],
262
+ ) -> list[MultiplexerSessionInformation]:
263
+ if len(self.multiplexer_session_info) == 0:
264
+ raise ValueError(f"No multiplexer sessions available to initialize.")
265
+ _check_matching_multiplexer_criterion(
266
+ "multiplexer type id", multiplexer_type_ids, self._multiplexer_type_ids
267
+ )
268
+
269
+ multiplexer_session_infos: list[MultiplexerSessionInformation] = []
270
+ for type_id in multiplexer_type_ids:
271
+ matching_session_info = self._get_multiplexer_session_infos_for_type_id(type_id)
272
+ if matching_session_info:
273
+ multiplexer_session_infos.extend(matching_session_info)
274
+ return multiplexer_session_infos
275
+
276
+ @contextlib.contextmanager
277
+ def _cache_multiplexer_session(
278
+ self, session_name: str, session: TMultiplexerSession
279
+ ) -> Generator[None]: # pyright: ignore[reportInvalidTypeVarUse]
280
+ if session_name in self._multiplexer_session_cache:
281
+ raise RuntimeError(f"Multiplexer session '{session_name}' already exists.")
282
+ self._multiplexer_session_cache[session_name] = session
283
+ try:
284
+ yield
285
+ finally:
286
+ del self._multiplexer_session_cache[session_name]
287
+
288
+ @contextlib.contextmanager
289
+ def _initialize_multiplexer_session_core(
290
+ self,
291
+ session_constructor: Callable[[MultiplexerSessionInformation], TMultiplexerSession],
292
+ multiplexer_type_id: str | None,
293
+ closing_function: None | (
294
+ Callable[[TMultiplexerSession], ContextManager[TMultiplexerSession]]
295
+ ) = None,
296
+ ) -> Generator[TypedMultiplexerSessionInformation[TMultiplexerSession]]:
297
+ _check_optional_str_param("multiplexer_type_id", multiplexer_type_id)
298
+ multiplexer_session_infos = self._validate_and_get_matching_multiplexer_session_infos(
299
+ _to_iterable(multiplexer_type_id, self._multiplexer_type_ids),
300
+ )
301
+ if len(multiplexer_session_infos) > 1:
302
+ raise ValueError(
303
+ f"Too many multiplexer sessions matched the specified criteria. "
304
+ f"Expected single multiplexer session, got {len(multiplexer_session_infos)} sessions."
305
+ )
306
+
307
+ if closing_function is None:
308
+ closing_function = closing_session
309
+
310
+ multiplexer_session_info = multiplexer_session_infos[0]
311
+ with closing_function(session_constructor(multiplexer_session_info)) as session:
312
+ with self._cache_multiplexer_session(multiplexer_session_info.session_name, session):
313
+ new_session_info = multiplexer_session_info._with_session(session)
314
+ yield cast(
315
+ TypedMultiplexerSessionInformation[TMultiplexerSession], new_session_info
316
+ )
317
+
318
+ @contextlib.contextmanager
319
+ def _initialize_multiplexer_sessions_core(
320
+ self,
321
+ session_constructor: Callable[[MultiplexerSessionInformation], TMultiplexerSession],
322
+ multiplexer_type_id: str | None,
323
+ closing_function: None | (
324
+ Callable[[TMultiplexerSession], ContextManager[TMultiplexerSession]]
325
+ ) = None,
326
+ ) -> Generator[Sequence[TypedMultiplexerSessionInformation[TMultiplexerSession]]]:
327
+ _check_optional_str_param("multiplexer_type_id", multiplexer_type_id)
328
+ multiplexer_session_infos = self._validate_and_get_matching_multiplexer_session_infos(
329
+ _to_iterable(multiplexer_type_id, self._multiplexer_type_ids),
330
+ )
331
+
332
+ if closing_function is None:
333
+ closing_function = closing_session
334
+
335
+ multiplexer_session_infos = sorted(
336
+ multiplexer_session_infos, key=lambda x: (x.resource_name)
337
+ )
338
+ with ExitStack() as stack:
339
+ typed_multiplexer_session_infos: list[
340
+ TypedMultiplexerSessionInformation[TMultiplexerSession]
341
+ ] = []
342
+ for multiplexer_session_info in multiplexer_session_infos:
343
+ session = stack.enter_context(
344
+ closing_function(session_constructor(multiplexer_session_info))
345
+ )
346
+ stack.enter_context(
347
+ self._cache_multiplexer_session(multiplexer_session_info.session_name, session)
348
+ )
349
+ new_session_info = multiplexer_session_info._with_session(session)
350
+ typed_multiplexer_session_infos.append(
351
+ cast(TypedMultiplexerSessionInformation[TMultiplexerSession], new_session_info)
352
+ )
353
+ yield typed_multiplexer_session_infos
354
+
355
+ def initialize_multiplexer_session(
356
+ self,
357
+ session_constructor: Callable[[MultiplexerSessionInformation], TMultiplexerSession],
358
+ multiplexer_type_id: str | None = None,
359
+ ) -> ContextManager[TypedMultiplexerSessionInformation[TMultiplexerSession]]:
360
+ """Initialize a single multiplexer session.
361
+
362
+ This is a generic method that supports any multiplexer driver.
363
+
364
+ Args:
365
+ session_constructor: A function that constructs multiplexer sessions
366
+ based on multiplexer session information.
367
+
368
+ multiplexer_type_id: User-defined identifier for the multiplexer
369
+ type in the pin map editor. If not specified, the multiplexer
370
+ type id is ignored when matching multiplexer sessions.
371
+
372
+ Returns:
373
+ A context manager that yields a multiplexer session information
374
+ object. The session object is available via the ``session`` field.
375
+
376
+ Raises:
377
+ TypeError: If the argument types are incorrect.
378
+
379
+ ValueError: If no multiplexer sessions are available or
380
+ too many multiplexer sessions are available.
381
+ """
382
+ return self._initialize_multiplexer_session_core(session_constructor, multiplexer_type_id)
383
+
384
+ def initialize_multiplexer_sessions(
385
+ self,
386
+ session_constructor: Callable[[MultiplexerSessionInformation], TMultiplexerSession],
387
+ multiplexer_type_id: str | None = None,
388
+ ) -> ContextManager[Sequence[TypedMultiplexerSessionInformation[TMultiplexerSession]]]:
389
+ """Initialize multiple multiplexer sessions.
390
+
391
+ This is a generic method that supports any multiplexer driver.
392
+
393
+ Args:
394
+ session_constructor: A function that constructs multiplexer sessions
395
+ based on multiplexer session information.
396
+
397
+ multiplexer_type_id: User-defined identifier for the multiplexer
398
+ type in the pin map editor. If not specified, the multiplexer
399
+ type id is ignored when matching multiplexer sessions.
400
+
401
+ Returns:
402
+ A context manager that yields a sequence of multiplexer session information
403
+ objects. The session objects are available via the ``session`` field.
404
+
405
+ Raises:
406
+ TypeError: If the argument types are incorrect.
407
+
408
+ ValueError: If no multiplexer sessions are available.
409
+ """
410
+ return self._initialize_multiplexer_sessions_core(session_constructor, multiplexer_type_id)
411
+
412
+ def initialize_niswitch_multiplexer_session(
413
+ self,
414
+ topology: str | None = None,
415
+ simulate: bool | None = None,
416
+ reset_device: bool = False,
417
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
418
+ multiplexer_type_id: str | None = None,
419
+ ) -> ContextManager[TypedMultiplexerSessionInformation[niswitch.Session]]:
420
+ """Initialize a single NI-SWITCH multiplexer session.
421
+
422
+ Args:
423
+ topology: Specifies the switch topology. If this argument is not
424
+ specified, the default value is "Configured Topology", which you
425
+ may override by setting ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_TOPOLOGY`` in
426
+ the configuration file (``.env``).
427
+
428
+ simulate: Enables or disables simulation of the switch module. If
429
+ this argument is not specified, the default value is ``False``,
430
+ which you may override by setting
431
+ ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_SIMULATE`` in the
432
+ configuration file (``.env``).
433
+
434
+ reset_device: Specifies whether to reset the switch module during
435
+ the initialization procedure.
436
+
437
+ initialization_behavior: Specifies whether the NI gRPC Device Server
438
+ will initialize a new session or attach to an existing session.
439
+
440
+ multiplexer_type_id: User-defined identifier for the multiplexer
441
+ type in the pin map editor. If not specified, the multiplexer
442
+ type id is ignored when matching multiplexer sessions.
443
+
444
+ Returns:
445
+ A context manager that yields a session information object. The
446
+ multiplexer session object is available via the ``session`` field.
447
+
448
+ Raises:
449
+ TypeError: If the argument types are incorrect.
450
+
451
+ ValueError: If no multiplexer sessions are available or
452
+ too many multiplexer sessions are available.
453
+
454
+ See Also:
455
+ For more details, see :py:class:`niswitch.Session`.
456
+ """
457
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._niswitch import (
458
+ SessionConstructor,
459
+ )
460
+
461
+ session_constructor = SessionConstructor(
462
+ self._discovery_client,
463
+ self._grpc_channel_pool,
464
+ topology,
465
+ simulate,
466
+ reset_device,
467
+ initialization_behavior,
468
+ is_multiplexer=True,
469
+ )
470
+ closing_function = functools.partial(
471
+ closing_session_with_ts_code_module_support, initialization_behavior
472
+ )
473
+ return self._initialize_multiplexer_session_core(
474
+ session_constructor, multiplexer_type_id, closing_function
475
+ )
476
+
477
+ def initialize_niswitch_multiplexer_sessions(
478
+ self,
479
+ topology: str | None = None,
480
+ simulate: bool | None = None,
481
+ reset_device: bool = False,
482
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
483
+ multiplexer_type_id: str | None = None,
484
+ ) -> ContextManager[Sequence[TypedMultiplexerSessionInformation[niswitch.Session]]]:
485
+ """Initialize multiple NI-SWITCH multiplexer sessions.
486
+
487
+ Args:
488
+ topology: Specifies the switch topology. If this argument is not
489
+ specified, the default value is "Configured Topology", which you
490
+ may override by setting ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_TOPOLOGY`` in
491
+ the configuration file (``.env``).
492
+
493
+ simulate: Enables or disables simulation of the switch module. If
494
+ this argument is not specified, the default value is ``False``,
495
+ which you may override by setting
496
+ ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_SIMULATE`` in the
497
+ configuration file (``.env``).
498
+
499
+ reset_device: Specifies whether to reset the switch module during
500
+ the initialization procedure.
501
+
502
+ initialization_behavior: Specifies whether the NI gRPC Device Server
503
+ will initialize a new session or attach to an existing session.
504
+
505
+ multiplexer_type_id: User-defined identifier for the multiplexer
506
+ type in the pin map editor. If not specified, the multiplexer
507
+ type id is ignored when matching multiplexer sessions.
508
+
509
+ Returns:
510
+ A context manager that yields a sequence of multiplexer session
511
+ information objects. The session objects are available via
512
+ the ``session`` field.
513
+
514
+ Raises:
515
+ TypeError: If the argument types are incorrect.
516
+
517
+ ValueError: If no multiplexer sessions are available.
518
+
519
+ See Also:
520
+ For more details, see :py:class:`niswitch.Session`.
521
+ """
522
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._niswitch import (
523
+ SessionConstructor,
524
+ )
525
+
526
+ session_constructor = SessionConstructor(
527
+ self._discovery_client,
528
+ self._grpc_channel_pool,
529
+ topology,
530
+ simulate,
531
+ reset_device,
532
+ initialization_behavior,
533
+ is_multiplexer=True,
534
+ )
535
+ closing_function = functools.partial(
536
+ closing_session_with_ts_code_module_support, initialization_behavior
537
+ )
538
+ return self._initialize_multiplexer_sessions_core(
539
+ session_constructor, multiplexer_type_id, closing_function
540
+ )
541
+
542
+
543
+ class BaseReservation(_BaseSessionContainer):
544
+ """Manages session reservation."""
545
+
546
+ def __init__(
547
+ self,
548
+ session_management_client: SessionManagementClient,
549
+ session_info: Sequence[session_management_service_pb2.SessionInformation],
550
+ multiplexer_session_info: None | (
551
+ Sequence[session_management_service_pb2.MultiplexerSessionInformation]
552
+ ) = None,
553
+ pin_or_relay_group_mappings: Mapping[str, Iterable[str]] | None = None,
554
+ reserved_pin_or_relay_names: str | Iterable[str] | None = None,
555
+ reserved_sites: Iterable[int] | None = None,
556
+ ) -> None:
557
+ """Initialize reservation object."""
558
+ super().__init__(session_management_client)
559
+
560
+ self._grpc_session_info = session_info # required for unreserve
561
+ self._session_info = [
562
+ SessionInformation._from_grpc_v1(info) for info in self._grpc_session_info
563
+ ]
564
+ self._session_cache: dict[str, object] = {}
565
+ self._multiplexer_session_container = MultiplexerSessionContainer(
566
+ session_management_client, multiplexer_session_info
567
+ )
568
+ self._pin_or_relay_group_mappings: Mapping[str, Iterable[str]] = {}
569
+ if pin_or_relay_group_mappings is not None:
570
+ self._pin_or_relay_group_mappings = pin_or_relay_group_mappings
571
+
572
+ # If __init__ doesn't initialize _reserved_pin_or_relay_names or
573
+ # _reserved_sites, the cached properties lazily initialize them.
574
+ if reserved_pin_or_relay_names is not None:
575
+ self._reserved_pin_or_relay_names = _to_ordered_set(
576
+ self._get_resolved_pin_or_relay_names(_to_iterable(reserved_pin_or_relay_names))
577
+ )
578
+
579
+ if reserved_sites is not None:
580
+ self._reserved_sites = _to_ordered_set(reserved_sites)
581
+
582
+ @cached_property
583
+ def _reserved_pin_or_relay_names(self) -> AbstractSet[str]:
584
+ # If __init__ doesn't initialize reserved_pin_or_relay_names, this
585
+ # cached property initializes it to the pin/relay names listed in the
586
+ # session info (in insertion order, no duplicates).
587
+ return _to_ordered_set(
588
+ channel_mapping.pin_or_relay_name
589
+ for session_info in self._session_info
590
+ for channel_mapping in session_info.channel_mappings
591
+ )
592
+
593
+ @cached_property
594
+ def _reserved_sites(self) -> AbstractSet[int]:
595
+ # If __init__ doesn't initialize reserved_sites, this cached property
596
+ # initializes it to the sites listed in the session info (in insertion
597
+ # order, no duplicates).
598
+ return _to_ordered_set(
599
+ channel_mapping.site
600
+ for session_info in self._session_info
601
+ for channel_mapping in session_info.channel_mappings
602
+ )
603
+
604
+ @cached_property
605
+ def _reserved_instrument_type_ids(self) -> AbstractSet[str]:
606
+ # Initialize to the instrument type ids listed in the session info (in
607
+ # alphabetical order, no duplicates).
608
+ return _to_ordered_set(
609
+ sorted(session_info.instrument_type_id for session_info in self._session_info)
610
+ )
611
+
612
+ @cached_property
613
+ def _connection_cache(self) -> dict[_ConnectionKey, Connection]:
614
+ cache = {}
615
+ for session_info in self._session_info:
616
+ for channel_mapping in session_info.channel_mappings:
617
+ key = _ConnectionKey(
618
+ channel_mapping.pin_or_relay_name,
619
+ channel_mapping.site,
620
+ session_info.instrument_type_id,
621
+ )
622
+ value = Connection(
623
+ pin_or_relay_name=channel_mapping.pin_or_relay_name,
624
+ site=channel_mapping.site,
625
+ channel_name=channel_mapping.channel,
626
+ session_info=session_info,
627
+ multiplexer_resource_name=channel_mapping.multiplexer_resource_name,
628
+ multiplexer_route=channel_mapping.multiplexer_route,
629
+ multiplexer_session_info=(
630
+ self._multiplexer_session_container._get_multiplexer_session_info_for_resource_name(
631
+ channel_mapping.multiplexer_resource_name
632
+ )
633
+ ),
634
+ )
635
+ assert key not in cache
636
+ cache[key] = value
637
+ return cache
638
+
639
+ @property
640
+ def _multiplexer_session_cache(self) -> dict[str, object]:
641
+ return self._multiplexer_session_container._multiplexer_session_cache
642
+
643
+ @property
644
+ def multiplexer_session_info(self) -> Sequence[MultiplexerSessionInformation]:
645
+ """Multiplexer session information object."""
646
+ return self._multiplexer_session_container.multiplexer_session_info
647
+
648
+ def __enter__(self: Self) -> Self:
649
+ """Context management protocol. Returns self."""
650
+ return self
651
+
652
+ def __exit__(
653
+ self,
654
+ exc_type: type[BaseException] | None,
655
+ exc_val: BaseException | None,
656
+ traceback: TracebackType | None,
657
+ ) -> Literal[False]:
658
+ """Context management protocol. Calls unreserve()."""
659
+ self.unreserve()
660
+ return False
661
+
662
+ def unreserve(self) -> None:
663
+ """Unreserve sessions."""
664
+ self._session_management_client._unreserve_sessions(self._grpc_session_info)
665
+
666
+ @contextlib.contextmanager
667
+ def _cache_session(self, session_name: str, session: TSession) -> Generator[None]:
668
+ if session_name in self._session_cache:
669
+ raise RuntimeError(f"Session '{session_name}' already exists.")
670
+ self._session_cache[session_name] = session
671
+ try:
672
+ yield
673
+ finally:
674
+ del self._session_cache[session_name]
675
+
676
+ def _get_matching_session_infos(self, instrument_type_id: str) -> list[SessionInformation]:
677
+ return [
678
+ info for info in self._session_info if instrument_type_id == info.instrument_type_id
679
+ ]
680
+
681
+ def _get_resolved_pin_or_relay_names(
682
+ self, reserved_pin_or_relay_names: Iterable[str]
683
+ ) -> Iterable[str]:
684
+ resolved_pin_or_relay_names: list[str] = []
685
+ for pin_or_relay_name in reserved_pin_or_relay_names:
686
+ if pin_or_relay_name in self._pin_or_relay_group_mappings:
687
+ resolved_pin_or_relay_names.extend(
688
+ self._pin_or_relay_group_mappings[pin_or_relay_name]
689
+ )
690
+ else:
691
+ resolved_pin_or_relay_names.append(pin_or_relay_name)
692
+
693
+ return resolved_pin_or_relay_names
694
+
695
+ @contextlib.contextmanager
696
+ def _initialize_session_core(
697
+ self,
698
+ session_constructor: Callable[[SessionInformation], TSession],
699
+ instrument_type_id: str,
700
+ closing_function: Callable[[TSession], ContextManager[TSession]] | None = None,
701
+ ) -> Generator[TypedSessionInformation[TSession]]:
702
+ if not instrument_type_id:
703
+ raise ValueError("This method requires an instrument type ID.")
704
+ session_infos = self._get_matching_session_infos(instrument_type_id)
705
+ if len(session_infos) == 0:
706
+ raise ValueError(
707
+ f"No reserved sessions matched instrument type ID '{instrument_type_id}'. "
708
+ "Expected single session, got 0 sessions."
709
+ )
710
+ elif len(session_infos) > 1:
711
+ raise ValueError(
712
+ f"Too many reserved sessions matched instrument type ID '{instrument_type_id}'. "
713
+ f"Expected single session, got {len(session_infos)} sessions."
714
+ )
715
+
716
+ if closing_function is None:
717
+ closing_function = closing_session
718
+
719
+ session_info = session_infos[0]
720
+ with closing_function(session_constructor(session_info)) as session:
721
+ with self._cache_session(session_info.session_name, session):
722
+ new_session_info = session_info._with_session(session)
723
+ yield cast(TypedSessionInformation[TSession], new_session_info)
724
+
725
+ @contextlib.contextmanager
726
+ def _initialize_sessions_core(
727
+ self,
728
+ session_constructor: Callable[[SessionInformation], TSession],
729
+ instrument_type_id: str,
730
+ closing_function: Callable[[TSession], ContextManager[TSession]] | None = None,
731
+ ) -> Generator[Sequence[TypedSessionInformation[TSession]]]:
732
+ if not instrument_type_id:
733
+ raise ValueError("This method requires an instrument type ID.")
734
+ session_infos = self._get_matching_session_infos(instrument_type_id)
735
+ if len(session_infos) == 0:
736
+ raise ValueError(
737
+ f"No reserved sessions matched instrument type ID '{instrument_type_id}'. "
738
+ "Expected single or multiple sessions, got 0 sessions."
739
+ )
740
+
741
+ if closing_function is None:
742
+ closing_function = closing_session
743
+
744
+ with ExitStack() as stack:
745
+ typed_session_infos: list[TypedSessionInformation[TSession]] = []
746
+ for session_info in session_infos:
747
+ session = stack.enter_context(closing_function(session_constructor(session_info)))
748
+ stack.enter_context(self._cache_session(session_info.session_name, session))
749
+ new_session_info = session_info._with_session(session)
750
+ typed_session_infos.append(
751
+ cast(TypedSessionInformation[TSession], new_session_info)
752
+ )
753
+ yield typed_session_infos
754
+
755
+ def _get_connection_core(
756
+ self,
757
+ session_type: type[TSession],
758
+ pin_or_relay_name: str | None = None,
759
+ site: int | None = None,
760
+ instrument_type_id: str | None = None,
761
+ multiplexer_session_type: type[TMultiplexerSession] | None = None,
762
+ ) -> TypedConnection[TSession]:
763
+ _check_optional_str_param("pin_or_relay_name", pin_or_relay_name)
764
+ _check_optional_int_param("site", site)
765
+ # _get_connections_core() checks instrument_type_id.
766
+
767
+ results = self._get_connections_core(
768
+ session_type, pin_or_relay_name, site, instrument_type_id, multiplexer_session_type
769
+ )
770
+
771
+ if not results:
772
+ raise ValueError(
773
+ "No reserved connections matched the specified criteria. "
774
+ "Expected single connection, got 0 connections."
775
+ )
776
+ elif len(results) > 1:
777
+ raise ValueError(
778
+ "Too many reserved connections matched the specified criteria. "
779
+ f"Expected single connection, got {len(results)} connections."
780
+ )
781
+
782
+ return results[0]
783
+
784
+ def _get_connections_core(
785
+ self,
786
+ session_type: type[TSession],
787
+ pin_or_relay_names: str | Iterable[str] | None = None,
788
+ sites: int | Iterable[int] | None = None,
789
+ instrument_type_id: str | None = None,
790
+ multiplexer_session_type: type[TMultiplexerSession] | None = None,
791
+ ) -> Sequence[TypedConnection[TSession]]:
792
+ _check_optional_str_param("instrument_type_id", instrument_type_id)
793
+
794
+ requested_pin_or_relay_names = _to_iterable(
795
+ pin_or_relay_names, self._reserved_pin_or_relay_names
796
+ )
797
+ requested_sites = _to_iterable(sites, self._reserved_sites)
798
+ requested_instrument_type_ids = _to_iterable(
799
+ instrument_type_id, self._reserved_instrument_type_ids
800
+ )
801
+
802
+ resolved_pin_or_relay_names = _to_ordered_set(
803
+ self._get_resolved_pin_or_relay_names(requested_pin_or_relay_names)
804
+ )
805
+
806
+ # Validate that each requested pin, site, or instrument type ID is
807
+ # present in the reserved pins, reserved sites, and reserved instrument
808
+ # type IDs. This rejects unknown or invalid inputs such as
809
+ # pin_or_relay_names="NonExistentPin" or sites=[0, 1, 65535].
810
+ if pin_or_relay_names is not None:
811
+ _check_matching_criterion(
812
+ "pin or relay name(s)",
813
+ resolved_pin_or_relay_names,
814
+ self._reserved_pin_or_relay_names,
815
+ )
816
+ if sites is not None:
817
+ _check_matching_criterion("site(s)", requested_sites, self._reserved_sites)
818
+ if instrument_type_id is not None:
819
+ _check_matching_criterion(
820
+ "instrument type ID",
821
+ requested_instrument_type_ids,
822
+ self._reserved_instrument_type_ids,
823
+ )
824
+
825
+ requested_sites_with_system = requested_sites
826
+ if SITE_SYSTEM_PINS not in requested_sites_with_system:
827
+ requested_sites_with_system = list(requested_sites_with_system)
828
+ requested_sites_with_system.append(SITE_SYSTEM_PINS)
829
+
830
+ # Sort the results by site, then by pin, then by instrument type (as a tiebreaker).
831
+ results: list[TypedConnection[TSession]] = []
832
+ matching_pins: set[str] = set()
833
+ for site in requested_sites_with_system:
834
+ for pin in resolved_pin_or_relay_names:
835
+ for instrument_type in requested_instrument_type_ids:
836
+ key = _ConnectionKey(pin, site, instrument_type)
837
+ value = self._connection_cache.get(key)
838
+ if value is not None:
839
+ session = self._session_cache.get(value.session_info.session_name)
840
+ value = value._with_session(session)
841
+ value._check_runtime_type(session_type)
842
+ if multiplexer_session_type is not None:
843
+ if value.multiplexer_session_info is not None:
844
+ multiplexer_session = self._multiplexer_session_cache.get(
845
+ value.multiplexer_session_info.session_name
846
+ )
847
+ value = value._with_multiplexer_session(multiplexer_session)
848
+ value._check_runtime_multiplexer_type(multiplexer_session_type)
849
+ results.append(cast(TypedConnection[TSession], value))
850
+ matching_pins.add(pin)
851
+
852
+ # If the user specified pins to match, validate that each one matched a connection.
853
+ if pin_or_relay_names is not None and not all(
854
+ pin in matching_pins for pin in resolved_pin_or_relay_names
855
+ ):
856
+ extra_pins_str = ", ".join(
857
+ _quote(pin) for pin in resolved_pin_or_relay_names if pin not in matching_pins
858
+ )
859
+ criteria = _describe_matching_criteria(None, sites, instrument_type_id)
860
+ # Emphasize the extra pin/relay names, but also list the other criteria.
861
+ raise ValueError(
862
+ f"No reserved connections matched pin or relay name(s) {extra_pins_str} "
863
+ f"with the specified criteria: {criteria}"
864
+ )
865
+
866
+ # If the user specified any matching criteria, validate that matches
867
+ # were found.
868
+ if (pin_or_relay_names or sites or instrument_type_id) is not None and not results:
869
+ criteria = _describe_matching_criteria(pin_or_relay_names, sites, instrument_type_id)
870
+ raise ValueError(f"No reserved connections matched the specified criteria: {criteria}")
871
+
872
+ return results
873
+
874
+ def initialize_session(
875
+ self,
876
+ session_constructor: Callable[[SessionInformation], TSession],
877
+ instrument_type_id: str,
878
+ ) -> ContextManager[TypedSessionInformation[TSession]]:
879
+ """Initialize a single instrument session.
880
+
881
+ This is a generic method that supports any instrument driver.
882
+
883
+ Args:
884
+ session_constructor: A function that constructs sessions based on
885
+ session information.
886
+
887
+ instrument_type_id: Instrument type ID for the session.
888
+
889
+ For custom instruments, use the instrument type id defined in
890
+ the pin map file.
891
+
892
+ Returns:
893
+ A context manager that yields a session information object. The
894
+ session object is available via the ``session`` field.
895
+
896
+ Raises:
897
+ ValueError: If the instrument type ID is empty, no reserved sessions
898
+ match the instrument type ID, or too many reserved sessions
899
+ match the instrument type ID.
900
+ """
901
+ return self._initialize_session_core(session_constructor, instrument_type_id)
902
+
903
+ def initialize_multiplexer_session(
904
+ self,
905
+ session_constructor: Callable[[MultiplexerSessionInformation], TMultiplexerSession],
906
+ multiplexer_type_id: str | None = None,
907
+ ) -> ContextManager[TypedMultiplexerSessionInformation[TMultiplexerSession]]:
908
+ """Initialize a single multiplexer session.
909
+
910
+ This is a generic method that supports any multiplexer driver.
911
+
912
+ Args:
913
+ session_constructor: A function that constructs multiplexer sessions
914
+ based on multiplexer session information.
915
+
916
+ multiplexer_type_id: User-defined identifier for the multiplexer
917
+ type in the pin map editor. If not specified, the multiplexer
918
+ type id is ignored when matching multiplexer sessions.
919
+
920
+ Returns:
921
+ A context manager that yields a multiplexer session information
922
+ object. The session object is available via the ``session`` field.
923
+
924
+ Raises:
925
+ TypeError: If the argument types are incorrect.
926
+
927
+ ValueError: If no multiplexer sessions are available or
928
+ too many multiplexer sessions are available.
929
+ """
930
+ return self._multiplexer_session_container.initialize_multiplexer_session(
931
+ session_constructor, multiplexer_type_id
932
+ )
933
+
934
+ def initialize_sessions(
935
+ self,
936
+ session_constructor: Callable[[SessionInformation], TSession],
937
+ instrument_type_id: str,
938
+ ) -> ContextManager[Sequence[TypedSessionInformation[TSession]]]:
939
+ """Initialize multiple instrument sessions.
940
+
941
+ This is a generic method that supports any instrument driver.
942
+
943
+ Args:
944
+ session_constructor: A function that constructs sessions based on
945
+ session information.
946
+
947
+ instrument_type_id: Instrument type ID for the session.
948
+
949
+ For custom instruments, use the instrument type id defined in
950
+ the pin map file.
951
+
952
+ Returns:
953
+ A context manager that yields a sequence of session information
954
+ objects. The session objects are available via the ``session``
955
+ field.
956
+
957
+ Raises:
958
+ ValueError: If the instrument type ID is empty or no reserved
959
+ sessions matched the instrument type ID.
960
+ """
961
+ return self._initialize_sessions_core(session_constructor, instrument_type_id)
962
+
963
+ def initialize_multiplexer_sessions(
964
+ self,
965
+ session_constructor: Callable[[MultiplexerSessionInformation], TMultiplexerSession],
966
+ multiplexer_type_id: str | None = None,
967
+ ) -> ContextManager[Sequence[TypedMultiplexerSessionInformation[TMultiplexerSession]]]:
968
+ """Initialize multiple multiplexer sessions.
969
+
970
+ This is a generic method that supports any multiplexer driver.
971
+
972
+ Args:
973
+ session_constructor: A function that constructs multiplexer sessions
974
+ based on multiplexer session information.
975
+
976
+ multiplexer_type_id: User-defined identifier for the multiplexer
977
+ type in the pin map editor. If not specified, the multiplexer
978
+ type id is ignored when matching multiplexer sessions.
979
+
980
+ Returns:
981
+ A context manager that yields a sequence of multiplexer session information
982
+ objects. The session objects are available via the ``session`` field.
983
+
984
+ Raises:
985
+ TypeError: If the argument types are incorrect.
986
+
987
+ ValueError: If no multiplexer sessions are available.
988
+ """
989
+ return self._multiplexer_session_container.initialize_multiplexer_sessions(
990
+ session_constructor, multiplexer_type_id
991
+ )
992
+
993
+ def get_connection(
994
+ self,
995
+ session_type: type[TSession],
996
+ pin_or_relay_name: str | None = None,
997
+ site: int | None = None,
998
+ instrument_type_id: str | None = None,
999
+ ) -> TypedConnection[TSession]:
1000
+ """Get the connection matching the specified criteria.
1001
+
1002
+ This is a generic method that supports any instrument driver.
1003
+
1004
+ Args:
1005
+ session_type: The session type.
1006
+
1007
+ pin_or_relay_name: The pin or relay name to match against. If not
1008
+ specified, the pin or relay name is ignored when matching
1009
+ connections.
1010
+
1011
+ site: The site number to match against. If not specified, the
1012
+ site number is ignored when matching connections.
1013
+
1014
+ instrument_type_id: The instrument type ID to match against. If not
1015
+ specified, the instrument type ID is ignored when matching
1016
+ connections.
1017
+
1018
+ Returns:
1019
+ The matching connection.
1020
+
1021
+ Raises:
1022
+ TypeError: If the argument types or session type are incorrect.
1023
+
1024
+ ValueError: If no reserved connections match or too many reserved
1025
+ connections match.
1026
+ """
1027
+ return self._get_connection_core(session_type, pin_or_relay_name, site, instrument_type_id)
1028
+
1029
+ def get_connection_with_multiplexer(
1030
+ self,
1031
+ session_type: type[TSession],
1032
+ multiplexer_session_type: type[TMultiplexerSession],
1033
+ pin_or_relay_name: str | None = None,
1034
+ site: int | None = None,
1035
+ instrument_type_id: str | None = None,
1036
+ ) -> TypedConnectionWithMultiplexer[TSession, TMultiplexerSession]:
1037
+ """Get the connection matching the specified criteria.
1038
+
1039
+ This is a generic method that supports any instrument driver.
1040
+
1041
+ Args:
1042
+ session_type: The instrument session type.
1043
+
1044
+ multiplexer_session_type: The multiplexer session type.
1045
+
1046
+ pin_or_relay_name: The pin or relay name to match against. If not
1047
+ specified, the pin or relay name is ignored when matching
1048
+ connections.
1049
+
1050
+ site: The site number to match against. If not specified, the
1051
+ site number is ignored when matching connections.
1052
+
1053
+ instrument_type_id: The instrument type ID to match against. If not
1054
+ specified, the instrument type ID is ignored when matching
1055
+ connections.
1056
+
1057
+ Returns:
1058
+ The matching connection along with its multiplexer info.
1059
+
1060
+ Raises:
1061
+ TypeError: If the argument types or session type are incorrect.
1062
+
1063
+ ValueError: If no reserved connections match or too many reserved
1064
+ connections match.
1065
+ """
1066
+ connection = self._get_connection_core(
1067
+ session_type, pin_or_relay_name, site, instrument_type_id, multiplexer_session_type
1068
+ )
1069
+ return cast(TypedConnectionWithMultiplexer[TSession, TMultiplexerSession], connection)
1070
+
1071
+ def get_connections(
1072
+ self,
1073
+ session_type: type[TSession],
1074
+ pin_or_relay_names: str | Iterable[str] | None = None,
1075
+ sites: int | Iterable[int] | None = None,
1076
+ instrument_type_id: str | None = None,
1077
+ ) -> Sequence[TypedConnection[TSession]]:
1078
+ """Get all connections matching the specified criteria.
1079
+
1080
+ This is a generic method that supports any instrument driver.
1081
+
1082
+ Args:
1083
+ session_type: The expected session type.
1084
+
1085
+ pin_or_relay_names: The pin or relay name(s) to match against. If
1086
+ not specified, the pin or relay name is ignored when matching
1087
+ connections.
1088
+
1089
+ sites: The site number(s) to match against. If not specified, the
1090
+ site number is ignored when matching connections.
1091
+
1092
+ instrument_type_id: The instrument type ID to match against. If not
1093
+ specified, the instrument type ID is ignored when matching
1094
+ connections.
1095
+
1096
+ Returns:
1097
+ The matching connections.
1098
+
1099
+ Raises:
1100
+ TypeError: If the argument types or session type are incorrect.
1101
+
1102
+ ValueError: If no reserved connections match.
1103
+ """
1104
+ return self._get_connections_core(
1105
+ session_type, pin_or_relay_names, sites, instrument_type_id
1106
+ )
1107
+
1108
+ def get_connections_with_multiplexer(
1109
+ self,
1110
+ session_type: type[TSession],
1111
+ multiplexer_session_type: type[TMultiplexerSession],
1112
+ pin_or_relay_names: str | Iterable[str] | None = None,
1113
+ sites: int | Iterable[int] | None = None,
1114
+ instrument_type_id: str | None = None,
1115
+ ) -> Sequence[TypedConnectionWithMultiplexer[TSession, TMultiplexerSession]]:
1116
+ """Get all connections matching the specified criteria.
1117
+
1118
+ This is a generic method that supports any instrument driver.
1119
+
1120
+ Args:
1121
+ session_type: The instrument session type.
1122
+
1123
+ multiplexer_session_type: The multiplexer session type.
1124
+
1125
+ pin_or_relay_names: The pin or relay name(s) to match against. If
1126
+ not specified, the pin or relay name is ignored when matching
1127
+ connections.
1128
+
1129
+ sites: The site number(s) to match against. If not specified, the
1130
+ site number is ignored when matching connections.
1131
+
1132
+ instrument_type_id: The instrument type ID to match against. If not
1133
+ specified, the instrument type ID is ignored when matching
1134
+ connections.
1135
+
1136
+ Returns:
1137
+ The matching connections along with their multiplexer(s) info.
1138
+
1139
+ Raises:
1140
+ TypeError: If the argument types or session type are incorrect.
1141
+
1142
+ ValueError: If no reserved connections match.
1143
+ """
1144
+ connections = self._get_connections_core(
1145
+ session_type, pin_or_relay_names, sites, instrument_type_id, multiplexer_session_type
1146
+ )
1147
+ return [
1148
+ cast(TypedConnectionWithMultiplexer[TSession, TMultiplexerSession], conn)
1149
+ for conn in connections
1150
+ ]
1151
+
1152
+ def create_nidaqmx_task(
1153
+ self,
1154
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1155
+ ) -> ContextManager[TypedSessionInformation[nidaqmx.Task]]:
1156
+ """Create a single NI-DAQmx task.
1157
+
1158
+ Args:
1159
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1160
+ will create a new task or attach to an existing task.
1161
+
1162
+ Returns:
1163
+ A context manager that yields a session information object. The task
1164
+ object is available via the ``session`` field.
1165
+
1166
+ Raises:
1167
+ ValueError: If no NI-DAQmx tasks are reserved or too many
1168
+ NI-DAQmx tasks are reserved.
1169
+
1170
+ Note:
1171
+ If the ``session_exists`` field is ``False``, the returned task is
1172
+ empty and the caller is expected to add channels to it.
1173
+
1174
+ See Also:
1175
+ For more details, see :py:class:`nidaqmx.Task`.
1176
+ """
1177
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidaqmx import (
1178
+ SessionConstructor,
1179
+ )
1180
+
1181
+ session_constructor = SessionConstructor(
1182
+ self._discovery_client, self._grpc_channel_pool, initialization_behavior
1183
+ )
1184
+ closing_function = functools.partial(
1185
+ closing_session_with_ts_code_module_support, initialization_behavior
1186
+ )
1187
+ return self._initialize_session_core(
1188
+ session_constructor, INSTRUMENT_TYPE_NI_DAQMX, closing_function
1189
+ )
1190
+
1191
+ def create_nidaqmx_tasks(
1192
+ self,
1193
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1194
+ ) -> ContextManager[Sequence[TypedSessionInformation[nidaqmx.Task]]]:
1195
+ """Create multiple NI-DAQmx tasks.
1196
+
1197
+ Args:
1198
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1199
+ will create a new task or attach to an existing task.
1200
+
1201
+ Returns:
1202
+ A context manager that yields a sequence of session information
1203
+ objects. The task objects are available via the ``session`` field.
1204
+
1205
+ Raises:
1206
+ ValueError: If no NI-DAQmx tasks are reserved.
1207
+
1208
+ Note:
1209
+ If the ``session_exists`` field is ``False``, the returned tasks are
1210
+ empty and the caller is expected to add channels to them.
1211
+
1212
+ See Also:
1213
+ For more details, see :py:class:`nidaqmx.Task`.
1214
+ """
1215
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidaqmx import (
1216
+ SessionConstructor,
1217
+ )
1218
+
1219
+ session_constructor = SessionConstructor(
1220
+ self._discovery_client, self._grpc_channel_pool, initialization_behavior
1221
+ )
1222
+ closing_function = functools.partial(
1223
+ closing_session_with_ts_code_module_support, initialization_behavior
1224
+ )
1225
+ return self._initialize_sessions_core(
1226
+ session_constructor, INSTRUMENT_TYPE_NI_DAQMX, closing_function
1227
+ )
1228
+
1229
+ def get_nidaqmx_connection(
1230
+ self,
1231
+ pin_name: str | None = None,
1232
+ site: int | None = None,
1233
+ ) -> TypedConnection[nidaqmx.Task]:
1234
+ """Get the NI-DAQmx connection matching the specified criteria.
1235
+
1236
+ Args:
1237
+ pin_name: The pin name to match against. If not specified, the pin
1238
+ name is ignored when matching connections.
1239
+
1240
+ site: The site number to match against. If not specified, the
1241
+ site number is ignored when matching connections.
1242
+
1243
+ Returns:
1244
+ The matching connection.
1245
+
1246
+ Raises:
1247
+ TypeError: If the argument types or session type are incorrect.
1248
+
1249
+ ValueError: If no reserved connections match or too many reserved
1250
+ connections match.
1251
+ """
1252
+ import nidaqmx
1253
+
1254
+ return self._get_connection_core(nidaqmx.Task, pin_name, site, INSTRUMENT_TYPE_NI_DAQMX)
1255
+
1256
+ def get_nidaqmx_connection_with_multiplexer(
1257
+ self,
1258
+ multiplexer_session_type: type[TMultiplexerSession],
1259
+ pin_name: str | None = None,
1260
+ site: int | None = None,
1261
+ ) -> TypedConnectionWithMultiplexer[nidaqmx.Task, TMultiplexerSession]:
1262
+ """Get the NI-DAQmx connection matching the specified criteria.
1263
+
1264
+ Args:
1265
+ multiplexer_session_type: The multiplexer session type.
1266
+
1267
+ pin_name: The pin name to match against. If not specified, the pin
1268
+ name is ignored when matching connections.
1269
+
1270
+ site: The site number to match against. If not specified, the
1271
+ site number is ignored when matching connections.
1272
+
1273
+ Returns:
1274
+ The matching connection with its multiplexer info.
1275
+
1276
+ Raises:
1277
+ TypeError: If the argument types or session type are incorrect.
1278
+
1279
+ ValueError: If no reserved connections match or too many reserved
1280
+ connections match.
1281
+ """
1282
+ import nidaqmx
1283
+
1284
+ connection = self._get_connection_core(
1285
+ nidaqmx.Task, pin_name, site, INSTRUMENT_TYPE_NI_DAQMX, multiplexer_session_type
1286
+ )
1287
+ return cast(TypedConnectionWithMultiplexer[nidaqmx.Task, TMultiplexerSession], connection)
1288
+
1289
+ def get_nidaqmx_connections(
1290
+ self,
1291
+ pin_names: str | Iterable[str] | None = None,
1292
+ sites: int | Iterable[int] | None = None,
1293
+ ) -> Sequence[TypedConnection[nidaqmx.Task]]:
1294
+ """Get all NI-DAQmx connections matching the specified criteria.
1295
+
1296
+ Args:
1297
+ pin_names: The pin name(s) to match against. If not specified, the
1298
+ pin name is ignored when matching connections.
1299
+
1300
+ sites: The site number(s) to match against. If not specified, the
1301
+ site number is ignored when matching connections.
1302
+
1303
+ Returns:
1304
+ The matching connections.
1305
+
1306
+ Raises:
1307
+ TypeError: If the argument types or session type are incorrect.
1308
+
1309
+ ValueError: If no reserved connections match.
1310
+ """
1311
+ import nidaqmx
1312
+
1313
+ return self._get_connections_core(nidaqmx.Task, pin_names, sites, INSTRUMENT_TYPE_NI_DAQMX)
1314
+
1315
+ def get_nidaqmx_connections_with_multiplexer(
1316
+ self,
1317
+ multiplexer_session_type: type[TMultiplexerSession],
1318
+ pin_names: str | Iterable[str] | None = None,
1319
+ sites: int | Iterable[int] | None = None,
1320
+ ) -> Sequence[TypedConnectionWithMultiplexer[nidaqmx.Task, TMultiplexerSession]]:
1321
+ """Get all NI-DAQmx connections matching the specified criteria.
1322
+
1323
+ Args:
1324
+ multiplexer_session_type: The multiplexer session type.
1325
+
1326
+ pin_names: The pin name(s) to match against. If not specified, the
1327
+ pin name is ignored when matching connections.
1328
+
1329
+ sites: The site number(s) to match against. If not specified, the
1330
+ site number is ignored when matching connections.
1331
+
1332
+ Returns:
1333
+ The matching connections with their multiplexer(s) info.
1334
+
1335
+ Raises:
1336
+ TypeError: If the argument types or session type are incorrect.
1337
+
1338
+ ValueError: If no reserved connections match.
1339
+ """
1340
+ import nidaqmx
1341
+
1342
+ connections = self._get_connections_core(
1343
+ nidaqmx.Task, pin_names, sites, INSTRUMENT_TYPE_NI_DAQMX, multiplexer_session_type
1344
+ )
1345
+ return [
1346
+ cast(TypedConnectionWithMultiplexer[nidaqmx.Task, TMultiplexerSession], conn)
1347
+ for conn in connections
1348
+ ]
1349
+
1350
+ def initialize_nidcpower_session(
1351
+ self,
1352
+ reset: bool = False,
1353
+ options: dict[str, Any] | None = None,
1354
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1355
+ ) -> ContextManager[TypedSessionInformation[nidcpower.Session]]:
1356
+ """Initialize a single NI-DCPower instrument session.
1357
+
1358
+ Args:
1359
+ reset: Specifies whether to reset channel(s) during the
1360
+ initialization procedure.
1361
+
1362
+ options: Specifies the initial value of certain properties for the
1363
+ session. If this argument is not specified, the default value is
1364
+ an empty dict, which you may override by specifying
1365
+ ``NIDCPOWER_SIMULATE``, ``NIDCPOWER_BOARD_TYPE``, and
1366
+ ``NIDCPOWER_MODEL`` in the configuration file (``.env``).
1367
+
1368
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1369
+ will initialize a new session or attach to an existing session.
1370
+
1371
+ Returns:
1372
+ A context manager that yields a session information object. The
1373
+ session object is available via the ``session`` field.
1374
+
1375
+ Raises:
1376
+ ValueError: If no NI-DCPower sessions are reserved or too many
1377
+ NI-DCPower sessions are reserved.
1378
+
1379
+ See Also:
1380
+ For more details, see :py:class:`nidcpower.Session`.
1381
+ """
1382
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidcpower import (
1383
+ SessionConstructor,
1384
+ )
1385
+
1386
+ session_constructor = SessionConstructor(
1387
+ self._discovery_client, self._grpc_channel_pool, reset, options, initialization_behavior
1388
+ )
1389
+ closing_function = functools.partial(
1390
+ closing_session_with_ts_code_module_support, initialization_behavior
1391
+ )
1392
+ return self._initialize_session_core(
1393
+ session_constructor, INSTRUMENT_TYPE_NI_DCPOWER, closing_function
1394
+ )
1395
+
1396
+ def initialize_nidcpower_sessions(
1397
+ self,
1398
+ reset: bool = False,
1399
+ options: dict[str, Any] | None = None,
1400
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1401
+ ) -> ContextManager[Sequence[TypedSessionInformation[nidcpower.Session]]]:
1402
+ """Initialize multiple NI-DCPower instrument sessions.
1403
+
1404
+ Args:
1405
+ reset: Specifies whether to reset channel(s) during the
1406
+ initialization procedure.
1407
+
1408
+ options: Specifies the initial value of certain properties for the
1409
+ session. If this argument is not specified, the default value is
1410
+ an empty dict, which you may override by specifying
1411
+ ``NIDCPOWER_SIMULATE``, ``NIDCPOWER_BOARD_TYPE``, and
1412
+ ``NIDCPOWER_MODEL`` in the configuration file (``.env``).
1413
+
1414
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1415
+ will initialize a new session or attach to an existing session.
1416
+
1417
+ Returns:
1418
+ A context manager that yields a sequence of session information
1419
+ objects. The session objects are available via the ``session``
1420
+ field.
1421
+
1422
+ Raises:
1423
+ ValueError: If no NI-DCPower sessions are reserved.
1424
+
1425
+ See Also:
1426
+ For more details, see :py:class:`nidcpower.Session`.
1427
+ """
1428
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidcpower import (
1429
+ SessionConstructor,
1430
+ )
1431
+
1432
+ session_constructor = SessionConstructor(
1433
+ self._discovery_client, self._grpc_channel_pool, reset, options, initialization_behavior
1434
+ )
1435
+ closing_function = functools.partial(
1436
+ closing_session_with_ts_code_module_support, initialization_behavior
1437
+ )
1438
+ return self._initialize_sessions_core(
1439
+ session_constructor, INSTRUMENT_TYPE_NI_DCPOWER, closing_function
1440
+ )
1441
+
1442
+ def get_nidcpower_connection(
1443
+ self,
1444
+ pin_name: str | None = None,
1445
+ site: int | None = None,
1446
+ ) -> TypedConnection[nidcpower.Session]:
1447
+ """Get the NI-DCPower connection matching the specified criteria.
1448
+
1449
+ Args:
1450
+ pin_name: The pin name to match against. If not specified, the pin
1451
+ name is ignored when matching connections.
1452
+
1453
+ site: The site number to match against. If not specified, the
1454
+ site number is ignored when matching connections.
1455
+
1456
+ Returns:
1457
+ The matching connection.
1458
+
1459
+ Raises:
1460
+ TypeError: If the argument types or session type are incorrect.
1461
+
1462
+ ValueError: If no reserved connections match or too many reserved
1463
+ connections match.
1464
+ """
1465
+ import nidcpower
1466
+
1467
+ return self._get_connection_core(
1468
+ nidcpower.Session, pin_name, site, INSTRUMENT_TYPE_NI_DCPOWER
1469
+ )
1470
+
1471
+ def get_nidcpower_connection_with_multiplexer(
1472
+ self,
1473
+ multiplexer_session_type: type[TMultiplexerSession],
1474
+ pin_name: str | None = None,
1475
+ site: int | None = None,
1476
+ ) -> TypedConnectionWithMultiplexer[nidcpower.Session, TMultiplexerSession]:
1477
+ """Get the NI-DCPower connection matching the specified criteria.
1478
+
1479
+ Args:
1480
+ multiplexer_session_type: The multiplexer session type.
1481
+
1482
+ pin_name: The pin name to match against. If not specified, the pin
1483
+ name is ignored when matching connections.
1484
+
1485
+ site: The site number to match against. If not specified, the
1486
+ site number is ignored when matching connections.
1487
+
1488
+ Returns:
1489
+ The matching connection along with its multiplexer info.
1490
+
1491
+ Raises:
1492
+ TypeError: If the argument types or session type are incorrect.
1493
+
1494
+ ValueError: If no reserved connections match or too many reserved
1495
+ connections match.
1496
+ """
1497
+ import nidcpower
1498
+
1499
+ connection = self._get_connection_core(
1500
+ nidcpower.Session, pin_name, site, INSTRUMENT_TYPE_NI_DCPOWER, multiplexer_session_type
1501
+ )
1502
+ return cast(
1503
+ TypedConnectionWithMultiplexer[nidcpower.Session, TMultiplexerSession], connection
1504
+ )
1505
+
1506
+ def get_nidcpower_connections(
1507
+ self,
1508
+ pin_names: str | Iterable[str] | None = None,
1509
+ sites: int | Iterable[int] | None = None,
1510
+ ) -> Sequence[TypedConnection[nidcpower.Session]]:
1511
+ """Get all NI-DCPower connections matching the specified criteria.
1512
+
1513
+ Args:
1514
+ pin_names: The pin name(s) to match against. If not specified, the
1515
+ pin name is ignored when matching connections.
1516
+
1517
+ sites: The site number(s) to match against. If not specified, the
1518
+ site number is ignored when matching connections.
1519
+
1520
+ Returns:
1521
+ The matching connections.
1522
+
1523
+ Raises:
1524
+ TypeError: If the argument types or session type are incorrect.
1525
+
1526
+ ValueError: If no reserved connections match.
1527
+ """
1528
+ import nidcpower
1529
+
1530
+ return self._get_connections_core(
1531
+ nidcpower.Session, pin_names, sites, INSTRUMENT_TYPE_NI_DCPOWER
1532
+ )
1533
+
1534
+ def get_nidcpower_connections_with_multiplexer(
1535
+ self,
1536
+ multiplexer_session_type: type[TMultiplexerSession],
1537
+ pin_names: str | Iterable[str] | None = None,
1538
+ sites: int | Iterable[int] | None = None,
1539
+ ) -> Sequence[TypedConnectionWithMultiplexer[nidcpower.Session, TMultiplexerSession]]:
1540
+ """Get all NI-DCPower connections matching the specified criteria.
1541
+
1542
+ Args:
1543
+ multiplexer_session_type: The multiplexer session type.
1544
+
1545
+ pin_names: The pin name(s) to match against. If not specified, the
1546
+ pin name is ignored when matching connections.
1547
+
1548
+ sites: The site number(s) to match against. If not specified, the
1549
+ site number is ignored when matching connections.
1550
+
1551
+ Returns:
1552
+ The matching connections along with their multiplexer(s) info.
1553
+
1554
+ Raises:
1555
+ TypeError: If the argument types or session type are incorrect.
1556
+
1557
+ ValueError: If no reserved connections match.
1558
+ """
1559
+ import nidcpower
1560
+
1561
+ connections = self._get_connections_core(
1562
+ nidcpower.Session,
1563
+ pin_names,
1564
+ sites,
1565
+ INSTRUMENT_TYPE_NI_DCPOWER,
1566
+ multiplexer_session_type,
1567
+ )
1568
+ return [
1569
+ cast(TypedConnectionWithMultiplexer[nidcpower.Session, TMultiplexerSession], conn)
1570
+ for conn in connections
1571
+ ]
1572
+
1573
+ def initialize_nidigital_session(
1574
+ self,
1575
+ reset_device: bool = False,
1576
+ options: dict[str, Any] | None = None,
1577
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1578
+ ) -> ContextManager[TypedSessionInformation[nidigital.Session]]:
1579
+ """Initialize a single NI-Digital Pattern instrument session.
1580
+
1581
+ Args:
1582
+ reset_device: Specifies whether to reset the instrument during the
1583
+ initialization procedure.
1584
+
1585
+ options: Specifies the initial value of certain properties for the
1586
+ session. If this argument is not specified, the default value is
1587
+ an empty dict, which you may override by specifying
1588
+ ``NIDIGITAL_SIMULATE``, ``NIDIGITAL_BOARD_TYPE``, and
1589
+ ``NIDIGITAL_MODEL`` in the configuration file (``.env``).
1590
+
1591
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1592
+ will initialize a new session or attach to an existing session.
1593
+
1594
+ Returns:
1595
+ A context manager that yields a session information object. The
1596
+ session object is available via the ``session`` field.
1597
+
1598
+ Raises:
1599
+ ValueError: If no NI-Digital sessions are reserved or too many
1600
+ NI-Digital sessions are reserved.
1601
+
1602
+ See Also:
1603
+ For more details, see :py:class:`nidigital.Session`.
1604
+ """
1605
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidigital import (
1606
+ SessionConstructor,
1607
+ )
1608
+
1609
+ session_constructor = SessionConstructor(
1610
+ self._discovery_client,
1611
+ self._grpc_channel_pool,
1612
+ reset_device,
1613
+ options,
1614
+ initialization_behavior,
1615
+ )
1616
+ closing_function = functools.partial(
1617
+ closing_session_with_ts_code_module_support, initialization_behavior
1618
+ )
1619
+ return self._initialize_session_core(
1620
+ session_constructor, INSTRUMENT_TYPE_NI_DIGITAL_PATTERN, closing_function
1621
+ )
1622
+
1623
+ def initialize_nidigital_sessions(
1624
+ self,
1625
+ reset_device: bool = False,
1626
+ options: dict[str, Any] | None = None,
1627
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1628
+ ) -> ContextManager[Sequence[TypedSessionInformation[nidigital.Session]]]:
1629
+ """Initialize multiple NI-Digital Pattern instrument sessions.
1630
+
1631
+ Args:
1632
+ reset_device: Specifies whether to reset the instrument during the
1633
+ initialization procedure.
1634
+
1635
+ options: Specifies the initial value of certain properties for the
1636
+ session. If this argument is not specified, the default value is
1637
+ an empty dict, which you may override by specifying
1638
+ ``NIDIGITAL_SIMULATE``, ``NIDIGITAL_BOARD_TYPE``, and
1639
+ ``NIDIGITAL_MODEL`` in the configuration file (``.env``).
1640
+
1641
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1642
+ will initialize a new session or attach to an existing session.
1643
+
1644
+ Returns:
1645
+ A context manager that yields a sequence of session information
1646
+ objects. The session objects are available via the ``session``
1647
+ field.
1648
+
1649
+ Raises:
1650
+ ValueError: If no NI-Digital sessions are reserved.
1651
+
1652
+ See Also:
1653
+ For more details, see :py:class:`nidigital.Session`.
1654
+ """
1655
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidigital import (
1656
+ SessionConstructor,
1657
+ )
1658
+
1659
+ session_constructor = SessionConstructor(
1660
+ self._discovery_client,
1661
+ self._grpc_channel_pool,
1662
+ reset_device,
1663
+ options,
1664
+ initialization_behavior,
1665
+ )
1666
+ closing_function = functools.partial(
1667
+ closing_session_with_ts_code_module_support, initialization_behavior
1668
+ )
1669
+ return self._initialize_sessions_core(
1670
+ session_constructor, INSTRUMENT_TYPE_NI_DIGITAL_PATTERN, closing_function
1671
+ )
1672
+
1673
+ def get_nidigital_connection(
1674
+ self,
1675
+ pin_name: str | None = None,
1676
+ site: int | None = None,
1677
+ ) -> TypedConnection[nidigital.Session]:
1678
+ """Get the NI-Digital Pattern connection matching the specified criteria.
1679
+
1680
+ Args:
1681
+ pin_name: The pin name to match against. If not specified, the pin
1682
+ name is ignored when matching connections.
1683
+
1684
+ site: The site number to match against. If not specified, the
1685
+ site number is ignored when matching connections.
1686
+
1687
+ Returns:
1688
+ The matching connection.
1689
+
1690
+ Raises:
1691
+ TypeError: If the argument types or session type are incorrect.
1692
+
1693
+ ValueError: If no reserved connections match or too many reserved
1694
+ connections match.
1695
+ """
1696
+ import nidigital
1697
+
1698
+ return self._get_connection_core(
1699
+ nidigital.Session, pin_name, site, INSTRUMENT_TYPE_NI_DIGITAL_PATTERN
1700
+ )
1701
+
1702
+ def get_nidigital_connection_with_multiplexer(
1703
+ self,
1704
+ multiplexer_session_type: type[TMultiplexerSession],
1705
+ pin_name: str | None = None,
1706
+ site: int | None = None,
1707
+ ) -> TypedConnectionWithMultiplexer[nidigital.Session, TMultiplexerSession]:
1708
+ """Get the NI-Digital Pattern connection matching the specified criteria.
1709
+
1710
+ Args:
1711
+ multiplexer_session_type: The multiplexer session type.
1712
+
1713
+ pin_name: The pin name to match against. If not specified, the pin
1714
+ name is ignored when matching connections.
1715
+
1716
+ site: The site number to match against. If not specified, the
1717
+ site number is ignored when matching connections.
1718
+
1719
+ Returns:
1720
+ The matching connection along with its multiplexer info.
1721
+
1722
+ Raises:
1723
+ TypeError: If the argument types or session type are incorrect.
1724
+
1725
+ ValueError: If no reserved connections match or too many reserved
1726
+ connections match.
1727
+ """
1728
+ import nidigital
1729
+
1730
+ connection = self._get_connection_core(
1731
+ nidigital.Session,
1732
+ pin_name,
1733
+ site,
1734
+ INSTRUMENT_TYPE_NI_DIGITAL_PATTERN,
1735
+ multiplexer_session_type,
1736
+ )
1737
+ return cast(
1738
+ TypedConnectionWithMultiplexer[nidigital.Session, TMultiplexerSession], connection
1739
+ )
1740
+
1741
+ def get_nidigital_connections(
1742
+ self,
1743
+ pin_names: str | Iterable[str] | None = None,
1744
+ sites: int | Iterable[int] | None = None,
1745
+ ) -> Sequence[TypedConnection[nidigital.Session]]:
1746
+ """Get all NI-Digital Pattern connections matching the specified criteria.
1747
+
1748
+ Args:
1749
+ pin_names: The pin name(s) to match against. If not specified, the
1750
+ pin name is ignored when matching connections.
1751
+
1752
+ sites: The site number(s) to match against. If not specified, the
1753
+ site number is ignored when matching connections.
1754
+
1755
+ Returns:
1756
+ The matching connections.
1757
+
1758
+ Raises:
1759
+ TypeError: If the argument types or session type are incorrect.
1760
+
1761
+ ValueError: If no reserved connections match.
1762
+ """
1763
+ import nidigital
1764
+
1765
+ return self._get_connections_core(
1766
+ nidigital.Session, pin_names, sites, INSTRUMENT_TYPE_NI_DIGITAL_PATTERN
1767
+ )
1768
+
1769
+ def get_nidigital_connections_with_multiplexer(
1770
+ self,
1771
+ multiplexer_session_type: type[TMultiplexerSession],
1772
+ pin_names: str | Iterable[str] | None = None,
1773
+ sites: int | Iterable[int] | None = None,
1774
+ ) -> Sequence[TypedConnectionWithMultiplexer[nidigital.Session, TMultiplexerSession]]:
1775
+ """Get all NI-Digital Pattern connections matching the specified criteria.
1776
+
1777
+ Args:
1778
+ multiplexer_session_type: The multiplexer session type.
1779
+
1780
+ pin_names: The pin name(s) to match against. If not specified, the
1781
+ pin name is ignored when matching connections.
1782
+
1783
+ sites: The site number(s) to match against. If not specified, the
1784
+ site number is ignored when matching connections.
1785
+
1786
+ Returns:
1787
+ The matching connections along with their multiplexer(s) info.
1788
+
1789
+ Raises:
1790
+ TypeError: If the argument types or session type are incorrect.
1791
+
1792
+ ValueError: If no reserved connections match.
1793
+ """
1794
+ import nidigital
1795
+
1796
+ connections = self._get_connections_core(
1797
+ nidigital.Session,
1798
+ pin_names,
1799
+ sites,
1800
+ INSTRUMENT_TYPE_NI_DIGITAL_PATTERN,
1801
+ multiplexer_session_type,
1802
+ )
1803
+ return [
1804
+ cast(TypedConnectionWithMultiplexer[nidigital.Session, TMultiplexerSession], conn)
1805
+ for conn in connections
1806
+ ]
1807
+
1808
+ def initialize_nidmm_session(
1809
+ self,
1810
+ reset_device: bool = False,
1811
+ options: dict[str, Any] | None = None,
1812
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1813
+ ) -> ContextManager[TypedSessionInformation[nidmm.Session]]:
1814
+ """Initialize a single NI-DMM instrument session.
1815
+
1816
+ Args:
1817
+ reset_device: Specifies whether to reset the instrument during the
1818
+ initialization procedure.
1819
+
1820
+ options: Specifies the initial value of certain properties for the
1821
+ session. If this argument is not specified, the default value is
1822
+ an empty dict, which you may override by specifying
1823
+ ``NIDMM_SIMULATE``, ``NIDMM_BOARD_TYPE``, and ``NIDMM_MODEL`` in
1824
+ the configuration file (``.env``).
1825
+
1826
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1827
+ will initialize a new session or attach to an existing session.
1828
+
1829
+ Returns:
1830
+ A context manager that yields a session information object. The
1831
+ session object is available via the ``session`` field.
1832
+
1833
+ Raises:
1834
+ ValueError: If no NI-DMM sessions are reserved or too many
1835
+ NI-DMM sessions are reserved.
1836
+
1837
+ See Also:
1838
+ For more details, see :py:class:`nidmm.Session`.
1839
+ """
1840
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidmm import (
1841
+ SessionConstructor,
1842
+ )
1843
+
1844
+ session_constructor = SessionConstructor(
1845
+ self._discovery_client,
1846
+ self._grpc_channel_pool,
1847
+ reset_device,
1848
+ options,
1849
+ initialization_behavior,
1850
+ )
1851
+ closing_function = functools.partial(
1852
+ closing_session_with_ts_code_module_support, initialization_behavior
1853
+ )
1854
+ return self._initialize_session_core(
1855
+ session_constructor, INSTRUMENT_TYPE_NI_DMM, closing_function
1856
+ )
1857
+
1858
+ def initialize_nidmm_sessions(
1859
+ self,
1860
+ reset_device: bool = False,
1861
+ options: dict[str, Any] | None = None,
1862
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
1863
+ ) -> ContextManager[Sequence[TypedSessionInformation[nidmm.Session]]]:
1864
+ """Initialize multiple NI-DMM instrument sessions.
1865
+
1866
+ Args:
1867
+ reset_device: Specifies whether to reset the instrument during the
1868
+ initialization procedure.
1869
+
1870
+ options: Specifies the initial value of certain properties for the
1871
+ session. If this argument is not specified, the default value is
1872
+ an empty dict, which you may override by specifying
1873
+ ``NIDMM_SIMULATE``, ``NIDMM_BOARD_TYPE``, and ``NIDMM_MODEL`` in
1874
+ the configuration file (``.env``).
1875
+
1876
+ initialization_behavior: Specifies whether the NI gRPC Device Server
1877
+ will initialize a new session or attach to an existing session.
1878
+
1879
+ Returns:
1880
+ A context manager that yields a sequence of session information
1881
+ objects. The session objects are available via the ``session``
1882
+ field.
1883
+
1884
+ Raises:
1885
+ ValueError: If no NI-DMM sessions are reserved.
1886
+
1887
+ See Also:
1888
+ For more details, see :py:class:`nidmm.Session`.
1889
+ """
1890
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nidmm import (
1891
+ SessionConstructor,
1892
+ )
1893
+
1894
+ session_constructor = SessionConstructor(
1895
+ self._discovery_client,
1896
+ self._grpc_channel_pool,
1897
+ reset_device,
1898
+ options,
1899
+ initialization_behavior,
1900
+ )
1901
+ closing_function = functools.partial(
1902
+ closing_session_with_ts_code_module_support, initialization_behavior
1903
+ )
1904
+ return self._initialize_sessions_core(
1905
+ session_constructor, INSTRUMENT_TYPE_NI_DMM, closing_function
1906
+ )
1907
+
1908
+ def get_nidmm_connection(
1909
+ self,
1910
+ pin_name: str | None = None,
1911
+ site: int | None = None,
1912
+ ) -> TypedConnection[nidmm.Session]:
1913
+ """Get the NI-DMM connection matching the specified criteria.
1914
+
1915
+ Args:
1916
+ pin_name: The pin name to match against. If not specified, the pin
1917
+ name is ignored when matching connections.
1918
+
1919
+ site: The site number to match against. If not specified, the
1920
+ site number is ignored when matching connections.
1921
+
1922
+ Returns:
1923
+ The matching connection.
1924
+
1925
+ Raises:
1926
+ TypeError: If the argument types or session type are incorrect.
1927
+
1928
+ ValueError: If no reserved connections match or too many reserved
1929
+ connections match.
1930
+ """
1931
+ import nidmm
1932
+
1933
+ return self._get_connection_core(nidmm.Session, pin_name, site, INSTRUMENT_TYPE_NI_DMM)
1934
+
1935
+ def get_nidmm_connection_with_multiplexer(
1936
+ self,
1937
+ multiplexer_session_type: type[TMultiplexerSession],
1938
+ pin_name: str | None = None,
1939
+ site: int | None = None,
1940
+ ) -> TypedConnectionWithMultiplexer[nidmm.Session, TMultiplexerSession]:
1941
+ """Get the NI-DMM connection matching the specified criteria.
1942
+
1943
+ Args:
1944
+ multiplexer_session_type: The multiplexer session type.
1945
+
1946
+ pin_name: The pin name to match against. If not specified, the pin
1947
+ name is ignored when matching connections.
1948
+
1949
+ site: The site number to match against. If not specified, the
1950
+ site number is ignored when matching connections.
1951
+
1952
+ Returns:
1953
+ The matching connection along with its multiplexer info.
1954
+
1955
+ Raises:
1956
+ TypeError: If the argument types or session type are incorrect.
1957
+
1958
+ ValueError: If no reserved connections match or too many reserved
1959
+ connections match.
1960
+ """
1961
+ import nidmm
1962
+
1963
+ connection = self._get_connection_core(
1964
+ nidmm.Session, pin_name, site, INSTRUMENT_TYPE_NI_DMM, multiplexer_session_type
1965
+ )
1966
+ return cast(TypedConnectionWithMultiplexer[nidmm.Session, TMultiplexerSession], connection)
1967
+
1968
+ def get_nidmm_connections(
1969
+ self,
1970
+ pin_names: str | Iterable[str] | None = None,
1971
+ sites: int | Iterable[int] | None = None,
1972
+ ) -> Sequence[TypedConnection[nidmm.Session]]:
1973
+ """Get all NI-DMM connections matching the specified criteria.
1974
+
1975
+ Args:
1976
+ pin_names: The pin name(s) to match against. If not specified, the
1977
+ pin name is ignored when matching connections.
1978
+
1979
+ sites: The site number(s) to match against. If not specified, the
1980
+ site number is ignored when matching connections.
1981
+
1982
+ Returns:
1983
+ The matching connections.
1984
+
1985
+ Raises:
1986
+ TypeError: If the argument types or session type are incorrect.
1987
+
1988
+ ValueError: If no reserved connections match.
1989
+ """
1990
+ import nidmm
1991
+
1992
+ return self._get_connections_core(nidmm.Session, pin_names, sites, INSTRUMENT_TYPE_NI_DMM)
1993
+
1994
+ def get_nidmm_connections_with_multiplexer(
1995
+ self,
1996
+ multiplexer_session_type: type[TMultiplexerSession],
1997
+ pin_names: str | Iterable[str] | None = None,
1998
+ sites: int | Iterable[int] | None = None,
1999
+ ) -> Sequence[TypedConnectionWithMultiplexer[nidmm.Session, TMultiplexerSession]]:
2000
+ """Get all NI-DMM connections matching the specified criteria.
2001
+
2002
+ Args:
2003
+ multiplexer_session_type: The multiplexer session type.
2004
+
2005
+ pin_names: The pin name(s) to match against. If not specified, the
2006
+ pin name is ignored when matching connections.
2007
+
2008
+ sites: The site number(s) to match against. If not specified, the
2009
+ site number is ignored when matching connections.
2010
+
2011
+ Returns:
2012
+ The matching connections along with their multiplexer(s) info.
2013
+
2014
+ Raises:
2015
+ TypeError: If the argument types or session type are incorrect.
2016
+
2017
+ ValueError: If no reserved connections match.
2018
+ """
2019
+ import nidmm
2020
+
2021
+ connections = self._get_connections_core(
2022
+ nidmm.Session, pin_names, sites, INSTRUMENT_TYPE_NI_DMM, multiplexer_session_type
2023
+ )
2024
+ return [
2025
+ cast(TypedConnectionWithMultiplexer[nidmm.Session, TMultiplexerSession], conn)
2026
+ for conn in connections
2027
+ ]
2028
+
2029
+ def initialize_nifgen_session(
2030
+ self,
2031
+ reset_device: bool = False,
2032
+ options: dict[str, Any] | None = None,
2033
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2034
+ ) -> ContextManager[TypedSessionInformation[nifgen.Session]]:
2035
+ """Initialize a single NI-FGEN instrument session.
2036
+
2037
+ Args:
2038
+ reset_device: Specifies whether to reset the instrument during the
2039
+ initialization procedure.
2040
+
2041
+ options: Specifies the initial value of certain properties for the
2042
+ session. If this argument is not specified, the default value is
2043
+ an empty dict, which you may override by specifying
2044
+ ``NIFGEN_SIMULATE``, ``NIFGEN_BOARD_TYPE``, and ``NIFGEN_MODEL``
2045
+ in the configuration file (``.env``).
2046
+
2047
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2048
+ will initialize a new session or attach to an existing session.
2049
+
2050
+ Returns:
2051
+ A context manager that yields a session information object. The
2052
+ session object is available via the ``session`` field.
2053
+
2054
+ Raises:
2055
+ ValueError: If no NI-FGEN sessions are reserved or too many NI-FGEN
2056
+ sessions are reserved.
2057
+
2058
+ See Also:
2059
+ For more details, see :py:class:`nifgen.Session`.
2060
+ """
2061
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nifgen import (
2062
+ SessionConstructor,
2063
+ )
2064
+
2065
+ session_constructor = SessionConstructor(
2066
+ self._discovery_client,
2067
+ self._grpc_channel_pool,
2068
+ reset_device,
2069
+ options,
2070
+ initialization_behavior,
2071
+ )
2072
+ closing_function = functools.partial(
2073
+ closing_session_with_ts_code_module_support, initialization_behavior
2074
+ )
2075
+ return self._initialize_session_core(
2076
+ session_constructor, INSTRUMENT_TYPE_NI_FGEN, closing_function
2077
+ )
2078
+
2079
+ def initialize_nifgen_sessions(
2080
+ self,
2081
+ reset_device: bool = False,
2082
+ options: dict[str, Any] | None = None,
2083
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2084
+ ) -> ContextManager[Sequence[TypedSessionInformation[nifgen.Session]]]:
2085
+ """Initialize multiple NI-FGEN instrument sessions.
2086
+
2087
+ Args:
2088
+ reset_device: Specifies whether to reset the instrument during the
2089
+ initialization procedure.
2090
+
2091
+ options: Specifies the initial value of certain properties for the
2092
+ session. If this argument is not specified, the default value is
2093
+ an empty dict, which you may override by specifying
2094
+ ``NIFGEN_SIMULATE``, ``NIFGEN_BOARD_TYPE``, and ``NIFGEN_MODEL``
2095
+ in the configuration file (``.env``).
2096
+
2097
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2098
+ will initialize a new session or attach to an existing session.
2099
+
2100
+ Returns:
2101
+ A context manager that yields a sequence of session information
2102
+ objects. The session objects are available via the ``session``
2103
+ field.
2104
+
2105
+ Raises:
2106
+ ValueError: If no NI-FGEN sessions are reserved.
2107
+
2108
+ See Also:
2109
+ For more details, see :py:class:`nifgen.Session`.
2110
+ """
2111
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._nifgen import (
2112
+ SessionConstructor,
2113
+ )
2114
+
2115
+ session_constructor = SessionConstructor(
2116
+ self._discovery_client,
2117
+ self._grpc_channel_pool,
2118
+ reset_device,
2119
+ options,
2120
+ initialization_behavior,
2121
+ )
2122
+ closing_function = functools.partial(
2123
+ closing_session_with_ts_code_module_support, initialization_behavior
2124
+ )
2125
+ return self._initialize_sessions_core(
2126
+ session_constructor, INSTRUMENT_TYPE_NI_FGEN, closing_function
2127
+ )
2128
+
2129
+ def get_nifgen_connection(
2130
+ self,
2131
+ pin_name: str | None = None,
2132
+ site: int | None = None,
2133
+ ) -> TypedConnection[nifgen.Session]:
2134
+ """Get the NI-FGEN connection matching the specified criteria.
2135
+
2136
+ Args:
2137
+ pin_name: The pin name to match against. If not specified, the pin
2138
+ name is ignored when matching connections.
2139
+
2140
+ site: The site number to match against. If not specified, the
2141
+ site number is ignored when matching connections.
2142
+
2143
+ Returns:
2144
+ The matching connection.
2145
+
2146
+ Raises:
2147
+ TypeError: If the argument types or session type are incorrect.
2148
+
2149
+ ValueError: If no reserved connections match or too many reserved
2150
+ connections match.
2151
+ """
2152
+ import nifgen
2153
+
2154
+ return self._get_connection_core(nifgen.Session, pin_name, site, INSTRUMENT_TYPE_NI_FGEN)
2155
+
2156
+ def get_nifgen_connection_with_multiplexer(
2157
+ self,
2158
+ multiplexer_session_type: type[TMultiplexerSession],
2159
+ pin_name: str | None = None,
2160
+ site: int | None = None,
2161
+ ) -> TypedConnectionWithMultiplexer[nifgen.Session, TMultiplexerSession]:
2162
+ """Get the NI-FGEN connection matching the specified criteria.
2163
+
2164
+ Args:
2165
+ multiplexer_session_type: The multiplexer session type.
2166
+
2167
+ pin_name: The pin name to match against. If not specified, the pin
2168
+ name is ignored when matching connections.
2169
+
2170
+ site: The site number to match against. If not specified, the
2171
+ site number is ignored when matching connections.
2172
+
2173
+ Returns:
2174
+ The matching connection along with its multiplexer info.
2175
+
2176
+ Raises:
2177
+ TypeError: If the argument types or session type are incorrect.
2178
+
2179
+ ValueError: If no reserved connections match or too many reserved
2180
+ connections match.
2181
+ """
2182
+ import nifgen
2183
+
2184
+ connection = self._get_connection_core(
2185
+ nifgen.Session, pin_name, site, INSTRUMENT_TYPE_NI_FGEN, multiplexer_session_type
2186
+ )
2187
+ return cast(TypedConnectionWithMultiplexer[nifgen.Session, TMultiplexerSession], connection)
2188
+
2189
+ def get_nifgen_connections(
2190
+ self,
2191
+ pin_names: str | Iterable[str] | None = None,
2192
+ sites: int | Iterable[int] | None = None,
2193
+ ) -> Sequence[TypedConnection[nifgen.Session]]:
2194
+ """Get all NI-FGEN connections matching the specified criteria.
2195
+
2196
+ Args:
2197
+ pin_names: The pin name(s) to match against. If not specified, the
2198
+ pin name is ignored when matching connections.
2199
+
2200
+ sites: The site number(s) to match against. If not specified, the
2201
+ site number is ignored when matching connections.
2202
+
2203
+ Returns:
2204
+ The matching connections.
2205
+
2206
+ Raises:
2207
+ TypeError: If the argument types or session type are incorrect.
2208
+
2209
+ ValueError: If no reserved connections match.
2210
+ """
2211
+ import nifgen
2212
+
2213
+ return self._get_connections_core(nifgen.Session, pin_names, sites, INSTRUMENT_TYPE_NI_FGEN)
2214
+
2215
+ def get_nifgen_connections_with_multiplexer(
2216
+ self,
2217
+ multiplexer_session_type: type[TMultiplexerSession],
2218
+ pin_names: str | Iterable[str] | None = None,
2219
+ sites: int | Iterable[int] | None = None,
2220
+ ) -> Sequence[TypedConnectionWithMultiplexer[nifgen.Session, TMultiplexerSession]]:
2221
+ """Get all NI-FGEN connections matching the specified criteria.
2222
+
2223
+ Args:
2224
+ multiplexer_session_type: The multiplexer session type.
2225
+
2226
+ pin_names: The pin name(s) to match against. If not specified, the
2227
+ pin name is ignored when matching connections.
2228
+
2229
+ sites: The site number(s) to match against. If not specified, the
2230
+ site number is ignored when matching connections.
2231
+
2232
+ Returns:
2233
+ The matching connections along with their multiplexer(s) info.
2234
+
2235
+ Raises:
2236
+ TypeError: If the argument types or session type are incorrect.
2237
+
2238
+ ValueError: If no reserved connections match.
2239
+ """
2240
+ import nifgen
2241
+
2242
+ connections = self._get_connections_core(
2243
+ nifgen.Session, pin_names, sites, INSTRUMENT_TYPE_NI_FGEN, multiplexer_session_type
2244
+ )
2245
+ return [
2246
+ cast(TypedConnectionWithMultiplexer[nifgen.Session, TMultiplexerSession], conn)
2247
+ for conn in connections
2248
+ ]
2249
+
2250
+ def initialize_niscope_session(
2251
+ self,
2252
+ reset_device: bool = False,
2253
+ options: dict[str, Any] | None = None,
2254
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2255
+ ) -> ContextManager[TypedSessionInformation[niscope.Session]]:
2256
+ """Initialize a single NI-SCOPE instrument session.
2257
+
2258
+ Args:
2259
+ reset_device: Specifies whether to reset the instrument during the
2260
+ initialization procedure.
2261
+
2262
+ options: Specifies the initial value of certain properties for the
2263
+ session. If this argument is not specified, the default value is
2264
+ an empty dict, which you may override by specifying
2265
+ ``NISCOPE_SIMULATE``, ``NISCOPE_BOARD_TYPE``, and
2266
+ ``NISCOPE_MODEL`` in the configuration file (``.env``).
2267
+
2268
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2269
+ will initialize a new session or attach to an existing session.
2270
+
2271
+ Returns:
2272
+ A context manager that yields a session information object. The
2273
+ session object is available via the ``session`` field.
2274
+
2275
+ Raises:
2276
+ ValueError: If no NI-SCOPE sessions are reserved or too many
2277
+ NI-SCOPE sessions are reserved.
2278
+
2279
+ See Also:
2280
+ For more details, see :py:class:`niscope.Session`.
2281
+ """
2282
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._niscope import (
2283
+ SessionConstructor,
2284
+ )
2285
+
2286
+ session_constructor = SessionConstructor(
2287
+ self._discovery_client,
2288
+ self._grpc_channel_pool,
2289
+ reset_device,
2290
+ options,
2291
+ initialization_behavior,
2292
+ )
2293
+ closing_function = functools.partial(
2294
+ closing_session_with_ts_code_module_support, initialization_behavior
2295
+ )
2296
+ return self._initialize_session_core(
2297
+ session_constructor, INSTRUMENT_TYPE_NI_SCOPE, closing_function
2298
+ )
2299
+
2300
+ def initialize_niscope_sessions(
2301
+ self,
2302
+ reset_device: bool = False,
2303
+ options: dict[str, Any] | None = None,
2304
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2305
+ ) -> ContextManager[Sequence[TypedSessionInformation[niscope.Session]]]:
2306
+ """Initialize multiple NI-SCOPE instrument sessions.
2307
+
2308
+ Args:
2309
+ reset_device: Specifies whether to reset the instrument during the
2310
+ initialization procedure.
2311
+
2312
+ options: Specifies the initial value of certain properties for the
2313
+ session. If this argument is not specified, the default value is
2314
+ an empty dict, which you may override by specifying
2315
+ ``NISCOPE_SIMULATE``, ``NISCOPE_BOARD_TYPE``, and
2316
+ ``NISCOPE_MODEL`` in the configuration file (``.env``).
2317
+
2318
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2319
+ will initialize a new session or attach to an existing session.
2320
+
2321
+ Returns:
2322
+ A context manager that yields a sequence of session information
2323
+ objects. The session objects are available via the ``session``
2324
+ field.
2325
+
2326
+ Raises:
2327
+ ValueError: If no NI-SCOPE sessions are reserved.
2328
+
2329
+ See Also:
2330
+ For more details, see :py:class:`niscope.Session`.
2331
+ """
2332
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._niscope import (
2333
+ SessionConstructor,
2334
+ )
2335
+
2336
+ session_constructor = SessionConstructor(
2337
+ self._discovery_client,
2338
+ self._grpc_channel_pool,
2339
+ reset_device,
2340
+ options,
2341
+ initialization_behavior,
2342
+ )
2343
+ closing_function = functools.partial(
2344
+ closing_session_with_ts_code_module_support, initialization_behavior
2345
+ )
2346
+ return self._initialize_sessions_core(
2347
+ session_constructor, INSTRUMENT_TYPE_NI_SCOPE, closing_function
2348
+ )
2349
+
2350
+ def get_niscope_connection(
2351
+ self,
2352
+ pin_name: str | None = None,
2353
+ site: int | None = None,
2354
+ ) -> TypedConnection[niscope.Session]:
2355
+ """Get the NI-SCOPE connection matching the specified criteria.
2356
+
2357
+ Args:
2358
+ pin_name: The pin name to match against. If not specified, the pin
2359
+ name is ignored when matching connections.
2360
+
2361
+ site: The site number to match against. If not specified, the
2362
+ site number is ignored when matching connections.
2363
+
2364
+ Returns:
2365
+ The matching connection.
2366
+
2367
+ Raises:
2368
+ TypeError: If the argument types or session type are incorrect.
2369
+
2370
+ ValueError: If no reserved connections match or too many reserved
2371
+ connections match.
2372
+ """
2373
+ import niscope
2374
+
2375
+ return self._get_connection_core(niscope.Session, pin_name, site, INSTRUMENT_TYPE_NI_SCOPE)
2376
+
2377
+ def get_niscope_connection_with_multiplexer(
2378
+ self,
2379
+ multiplexer_session_type: type[TMultiplexerSession],
2380
+ pin_name: str | None = None,
2381
+ site: int | None = None,
2382
+ ) -> TypedConnectionWithMultiplexer[niscope.Session, TMultiplexerSession]:
2383
+ """Get the NI-SCOPE connection matching the specified criteria.
2384
+
2385
+ Args:
2386
+ multiplexer_session_type: The multiplexer session type.
2387
+
2388
+ pin_name: The pin name to match against. If not specified, the pin
2389
+ name is ignored when matching connections.
2390
+
2391
+ site: The site number to match against. If not specified, the
2392
+ site number is ignored when matching connections.
2393
+
2394
+ Returns:
2395
+ The matching connection along with its multiplexer info.
2396
+
2397
+ Raises:
2398
+ TypeError: If the argument types or session type are incorrect.
2399
+
2400
+ ValueError: If no reserved connections match or too many reserved
2401
+ connections match.
2402
+ """
2403
+ import niscope
2404
+
2405
+ connection = self._get_connection_core(
2406
+ niscope.Session, pin_name, site, INSTRUMENT_TYPE_NI_SCOPE, multiplexer_session_type
2407
+ )
2408
+ return cast(
2409
+ TypedConnectionWithMultiplexer[niscope.Session, TMultiplexerSession], connection
2410
+ )
2411
+
2412
+ def get_niscope_connections(
2413
+ self,
2414
+ pin_names: str | Iterable[str] | None = None,
2415
+ sites: int | Iterable[int] | None = None,
2416
+ ) -> Sequence[TypedConnection[niscope.Session]]:
2417
+ """Get all NI-SCOPE connections matching the specified criteria.
2418
+
2419
+ Args:
2420
+ pin_names: The pin name(s) to match against. If not specified, the
2421
+ pin name is ignored when matching connections.
2422
+
2423
+ sites: The site number(s) to match against. If not specified, the
2424
+ site number is ignored when matching connections.
2425
+
2426
+ Returns:
2427
+ The matching connections.
2428
+
2429
+ Raises:
2430
+ TypeError: If the argument types or session type are incorrect.
2431
+
2432
+ ValueError: If no reserved connections match.
2433
+ """
2434
+ import niscope
2435
+
2436
+ return self._get_connections_core(
2437
+ niscope.Session, pin_names, sites, INSTRUMENT_TYPE_NI_SCOPE
2438
+ )
2439
+
2440
+ def get_niscope_connections_with_multiplexer(
2441
+ self,
2442
+ multiplexer_session_type: type[TMultiplexerSession],
2443
+ pin_names: str | Iterable[str] | None = None,
2444
+ sites: int | Iterable[int] | None = None,
2445
+ ) -> Sequence[TypedConnectionWithMultiplexer[niscope.Session, TMultiplexerSession]]:
2446
+ """Get all NI-SCOPE connections matching the specified criteria.
2447
+
2448
+ Args:
2449
+ multiplexer_session_type: The multiplexer session type.
2450
+
2451
+ pin_names: The pin name(s) to match against. If not specified, the
2452
+ pin name is ignored when matching connections.
2453
+
2454
+ sites: The site number(s) to match against. If not specified, the
2455
+ site number is ignored when matching connections.
2456
+
2457
+ Returns:
2458
+ The matching connections along with their multiplexer(s) info.
2459
+
2460
+ Raises:
2461
+ TypeError: If the argument types or session type are incorrect.
2462
+
2463
+ ValueError: If no reserved connections match.
2464
+ """
2465
+ import niscope
2466
+
2467
+ connections = self._get_connections_core(
2468
+ niscope.Session, pin_names, sites, INSTRUMENT_TYPE_NI_SCOPE, multiplexer_session_type
2469
+ )
2470
+ return [
2471
+ cast(TypedConnectionWithMultiplexer[niscope.Session, TMultiplexerSession], conn)
2472
+ for conn in connections
2473
+ ]
2474
+
2475
+ def initialize_niswitch_session(
2476
+ self,
2477
+ topology: str | None = None,
2478
+ simulate: bool | None = None,
2479
+ reset_device: bool = False,
2480
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2481
+ ) -> ContextManager[TypedSessionInformation[niswitch.Session]]:
2482
+ """Initialize a single NI-SWITCH relay driver instrument session.
2483
+
2484
+ Args:
2485
+ topology: Specifies the switch topology. If this argument is not
2486
+ specified, the default value is "Configured Topology", which you
2487
+ may override by setting ``MEASUREMENT_PLUGIN_NISWITCH_TOPOLOGY`` in
2488
+ the configuration file (``.env``).
2489
+
2490
+ simulate: Enables or disables simulation of the switch module. If
2491
+ this argument is not specified, the default value is ``False``,
2492
+ which you may override by setting
2493
+ ``MEASUREMENT_PLUGIN_NISWITCH_SIMULATE`` in the configuration file
2494
+ (``.env``).
2495
+
2496
+ reset_device: Specifies whether to reset the switch module during
2497
+ the initialization procedure.
2498
+
2499
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2500
+ will initialize a new session or attach to an existing session.
2501
+
2502
+ Returns:
2503
+ A context manager that yields a session information object. The
2504
+ session object is available via the ``session`` field.
2505
+
2506
+ Raises:
2507
+ ValueError: If no relay driver sessions are reserved or
2508
+ too many relay driver sessions are reserved.
2509
+
2510
+ See Also:
2511
+ For more details, see :py:class:`niswitch.Session`.
2512
+ """
2513
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._niswitch import (
2514
+ SessionConstructor,
2515
+ )
2516
+
2517
+ session_constructor = SessionConstructor(
2518
+ self._discovery_client,
2519
+ self._grpc_channel_pool,
2520
+ topology,
2521
+ simulate,
2522
+ reset_device,
2523
+ initialization_behavior,
2524
+ )
2525
+ closing_function = functools.partial(
2526
+ closing_session_with_ts_code_module_support, initialization_behavior
2527
+ )
2528
+ return self._initialize_session_core(
2529
+ session_constructor, INSTRUMENT_TYPE_NI_RELAY_DRIVER, closing_function
2530
+ )
2531
+
2532
+ def initialize_niswitch_sessions(
2533
+ self,
2534
+ topology: str | None = None,
2535
+ simulate: bool | None = None,
2536
+ reset_device: bool = False,
2537
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2538
+ ) -> ContextManager[Sequence[TypedSessionInformation[niswitch.Session]]]:
2539
+ """Initialize multiple NI-SWITCH relay driver instrument sessions.
2540
+
2541
+ Args:
2542
+ topology: Specifies the switch topology. If this argument is not
2543
+ specified, the default value is "Configured Topology", which you
2544
+ may override by setting ``MEASUREMENT_PLUGIN_NISWITCH_TOPOLOGY`` in
2545
+ the configuration file (``.env``).
2546
+
2547
+ simulate: Enables or disables simulation of the switch module. If
2548
+ this argument is not specified, the default value is ``False``,
2549
+ which you may override by setting
2550
+ ``MEASUREMENT_PLUGIN_NISWITCH_SIMULATE`` in the configuration file
2551
+ (``.env``).
2552
+
2553
+ reset_device: Specifies whether to reset the switch module during
2554
+ the initialization procedure.
2555
+
2556
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2557
+ will initialize a new session or attach to an existing session.
2558
+
2559
+ Returns:
2560
+ A context manager that yields a sequence of session information
2561
+ objects. The session objects are available via the ``session``
2562
+ field.
2563
+
2564
+ Raises:
2565
+ ValueError: If no relay driver sessions are reserved.
2566
+
2567
+ See Also:
2568
+ For more details, see :py:class:`niswitch.Session`.
2569
+ """
2570
+ from ni.measurementlink.sessionmanagement.v1.client._drivers._niswitch import (
2571
+ SessionConstructor,
2572
+ )
2573
+
2574
+ session_constructor = SessionConstructor(
2575
+ self._discovery_client,
2576
+ self._grpc_channel_pool,
2577
+ topology,
2578
+ simulate,
2579
+ reset_device,
2580
+ initialization_behavior,
2581
+ )
2582
+ closing_function = functools.partial(
2583
+ closing_session_with_ts_code_module_support, initialization_behavior
2584
+ )
2585
+ return self._initialize_sessions_core(
2586
+ session_constructor, INSTRUMENT_TYPE_NI_RELAY_DRIVER, closing_function
2587
+ )
2588
+
2589
+ def get_niswitch_connection(
2590
+ self,
2591
+ relay_name: str | None = None,
2592
+ site: int | None = None,
2593
+ ) -> TypedConnection[niswitch.Session]:
2594
+ """Get the NI-SWITCH relay driver connection matching the specified criteria.
2595
+
2596
+ Args:
2597
+ relay_name: The relay name to match against. If not specified, the
2598
+ relay name is ignored when matching connections.
2599
+
2600
+ site: The site number to match against. If not specified, the
2601
+ site number is ignored when matching connections.
2602
+
2603
+ Returns:
2604
+ The matching connection.
2605
+
2606
+ Raises:
2607
+ TypeError: If the argument types or session type are incorrect.
2608
+
2609
+ ValueError: If no reserved connections match or too many reserved
2610
+ connections match.
2611
+ """
2612
+ import niswitch
2613
+
2614
+ return self._get_connection_core(
2615
+ niswitch.Session, relay_name, site, INSTRUMENT_TYPE_NI_RELAY_DRIVER
2616
+ )
2617
+
2618
+ def get_niswitch_connections(
2619
+ self,
2620
+ relay_names: str | Iterable[str] | None = None,
2621
+ sites: int | Iterable[int] | None = None,
2622
+ ) -> Sequence[TypedConnection[niswitch.Session]]:
2623
+ """Get all NI-SWITCH relay driver connections matching the specified criteria.
2624
+
2625
+ Args:
2626
+ relay_names: The relay name(s) to match against. If not specified,
2627
+ the relay name is ignored when matching connections.
2628
+
2629
+ sites: The site number(s) to match against. If not specified, the
2630
+ site number is ignored when matching connections.
2631
+
2632
+ Returns:
2633
+ The matching connections.
2634
+
2635
+ Raises:
2636
+ TypeError: If the argument types or session type are incorrect.
2637
+
2638
+ ValueError: If no reserved connections match.
2639
+ """
2640
+ import niswitch
2641
+
2642
+ return self._get_connections_core(
2643
+ niswitch.Session, relay_names, sites, INSTRUMENT_TYPE_NI_RELAY_DRIVER
2644
+ )
2645
+
2646
+ def initialize_niswitch_multiplexer_session(
2647
+ self,
2648
+ topology: str | None = None,
2649
+ simulate: bool | None = None,
2650
+ reset_device: bool = False,
2651
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2652
+ multiplexer_type_id: str | None = None,
2653
+ ) -> ContextManager[TypedMultiplexerSessionInformation[niswitch.Session]]:
2654
+ """Initialize a single NI-SWITCH multiplexer session.
2655
+
2656
+ Args:
2657
+ topology: Specifies the switch topology. If this argument is not
2658
+ specified, the default value is "Configured Topology", which you
2659
+ may override by setting ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_TOPOLOGY`` in
2660
+ the configuration file (``.env``).
2661
+
2662
+ simulate: Enables or disables simulation of the switch module. If
2663
+ this argument is not specified, the default value is ``False``,
2664
+ which you may override by setting
2665
+ ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_SIMULATE`` in the configuration file
2666
+ (``.env``).
2667
+
2668
+ reset_device: Specifies whether to reset the switch module during
2669
+ the initialization procedure.
2670
+
2671
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2672
+ will initialize a new session or attach to an existing session.
2673
+
2674
+ multiplexer_type_id: User-defined identifier for the multiplexer
2675
+ type in the pin map editor. If not specified, the multiplexer
2676
+ type id is ignored when matching multiplexer sessions.
2677
+
2678
+ Returns:
2679
+ A context manager that yields a session information object. The
2680
+ multiplexer session object is available via the ``session`` field.
2681
+
2682
+ Raises:
2683
+ TypeError: If the argument types are incorrect.
2684
+
2685
+ ValueError: If no multiplexer sessions are available or
2686
+ too many multiplexer sessions are available.
2687
+
2688
+ See Also:
2689
+ For more details, see :py:class:`niswitch.Session`.
2690
+ """
2691
+ return self._multiplexer_session_container.initialize_niswitch_multiplexer_session(
2692
+ topology, simulate, reset_device, initialization_behavior, multiplexer_type_id
2693
+ )
2694
+
2695
+ def initialize_niswitch_multiplexer_sessions(
2696
+ self,
2697
+ topology: str | None = None,
2698
+ simulate: bool | None = None,
2699
+ reset_device: bool = False,
2700
+ initialization_behavior: SessionInitializationBehavior = SessionInitializationBehavior.AUTO,
2701
+ multiplexer_type_id: str | None = None,
2702
+ ) -> ContextManager[Sequence[TypedMultiplexerSessionInformation[niswitch.Session]]]:
2703
+ """Initialize multiple NI-SWITCH multiplexer sessions.
2704
+
2705
+ Args:
2706
+ topology: Specifies the switch topology. If this argument is not
2707
+ specified, the default value is "Configured Topology", which you
2708
+ may override by setting ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_TOPOLOGY`` in
2709
+ the configuration file (``.env``).
2710
+
2711
+ simulate: Enables or disables simulation of the switch module. If
2712
+ this argument is not specified, the default value is ``False``,
2713
+ which you may override by setting
2714
+ ``MEASUREMENT_PLUGIN_NISWITCH_MULTIPLEXER_SIMULATE`` in the configuration file
2715
+ (``.env``).
2716
+
2717
+ reset_device: Specifies whether to reset the switch module during
2718
+ the initialization procedure.
2719
+
2720
+ initialization_behavior: Specifies whether the NI gRPC Device Server
2721
+ will initialize a new session or attach to an existing session.
2722
+
2723
+ multiplexer_type_id: User-defined identifier for the multiplexer
2724
+ type in the pin map editor. If not specified, the multiplexer
2725
+ type id is ignored when matching multiplexer sessions.
2726
+
2727
+ Returns:
2728
+ A context manager that yields a sequence of multiplexer session
2729
+ information objects. The session objects are available via
2730
+ the ``session`` field.
2731
+
2732
+ Raises:
2733
+ TypeError: If the argument types are incorrect.
2734
+
2735
+ ValueError: If no multiplexer sessions are available.
2736
+
2737
+ See Also:
2738
+ For more details, see :py:class:`niswitch.Session`.
2739
+ """
2740
+ return self._multiplexer_session_container.initialize_niswitch_multiplexer_sessions(
2741
+ topology, simulate, reset_device, initialization_behavior, multiplexer_type_id
2742
+ )
2743
+
2744
+
2745
+ class SingleSessionReservation(BaseReservation):
2746
+ """Manages reservation for a single session."""
2747
+
2748
+ @property
2749
+ def session_info(self) -> SessionInformation:
2750
+ """Single session information object."""
2751
+ assert len(self._session_info) == 1
2752
+ info = self._session_info[0]
2753
+ return info._with_session(self._session_cache.get(info.session_name))
2754
+
2755
+
2756
+ class MultiSessionReservation(BaseReservation):
2757
+ """Manages reservation for multiple sessions."""
2758
+
2759
+ @property
2760
+ def session_info(self) -> list[SessionInformation]:
2761
+ """Multiple session information objects."""
2762
+ # If the session cache is empty, return the existing list without copying.
2763
+ if not self._session_cache:
2764
+ return self._session_info
2765
+
2766
+ return [
2767
+ info._with_session(self._session_cache.get(info.session_name))
2768
+ for info in self._session_info
2769
+ ]