Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

service: Update reserve_session(s) to accept a single pin and explicitly specify default timeout #389

Merged
merged 11 commits into from
Sep 21, 2023
153 changes: 88 additions & 65 deletions ni_measurementlink_service/session_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Optional,
Sequence,
Type,
Union,
)

import grpc
Expand Down Expand Up @@ -120,9 +121,19 @@ class SessionInformation(NamedTuple):
"""

session_exists: bool
"""Indicates whether the session exists in the Session Manager.
"""Indicates whether the session has been registered with the session management service.

This indicates whether the session has been created."""
When calling measurements from TestStand, the test sequence's ``ProcessSetup`` callback
creates instrument sessions and registers them with the session management service so that
they can be shared between multiple measurement steps. In this case, the `session_exists`
attribute is ``True``, indicating that the instrument sessions were already created and any
one-time setup (such as creating NI-DAQmx channels or loading NI-Digital files) has been
performed.

When calling measurements outside of TestStand, the `session_exists` attribute is ``False``,
indicating that the measurement is responsible for creating the instrument sessions and
performing any one-time setup.
"""

channel_mappings: Iterable[ChannelMapping]
"""List of site and pin/relay mappings that correspond to each channel in the channel_list.
Expand Down Expand Up @@ -305,40 +316,44 @@ def _get_stub(self) -> session_management_service_pb2_grpc.SessionManagementServ
def reserve_session(
self,
context: PinMapContext,
pin_or_relay_names: Optional[Iterable[str]] = None,
pin_or_relay_names: Union[str, Iterable[str], None] = None,
instrument_type_id: Optional[str] = None,
timeout: Optional[float] = None,
timeout: Optional[float] = 0.0,
) -> SingleSessionReservation:
"""Reserve a single session.

Reserve the session matching the given pins, sites, and instrument type ID and return the
information needed to create or access the session.

Args:
context (PinMapContext): Includes the pin map ID for the pin map in the Pin Map Service,
context: Includes the pin map ID for the pin map in the Pin Map Service,
as well as the list of sites for the measurement.

pin_or_relay_names (Iterable[str]): List of pins, pin groups, relays, or relay groups to
use for the measurement. If unspecified, reserve sessions for all pins and relays in
the registered pin map resource.
pin_or_relay_names: One or multiple pins, pin groups, relays, or relay groups to use
for the measurement.

instrument_type_id (str): Instrument type ID for the measurement. If unspecified,
reserve sessions for all instrument types connected in the registered pin map
If unspecified, reserve sessions for all pins and relays in the registered pin map
resource.

instrument_type_id: Instrument type ID for the measurement.

If unspecified, this method reserve sessions for all instrument types connected
in the registered pin map resource.

For NI instruments, use instrument type id constants, such as
:py:const:`INSTRUMENT_TYPE_NI_DCPOWER` or :py:const:`INSTRUMENT_TYPE_NI_DMM`.

For custom instruments, use the instrument type id defined in the pin map file.

timeout (float): Timeout in seconds. Allowed values,
0 (non-blocking, fails immediately if resources cannot be reserved),
-1 or negative (infinite timeout), or
any positive numeric value (wait for that number of second).
timeout: Timeout in seconds.
bkeryan marked this conversation as resolved.
Show resolved Hide resolved

Allowed values: 0 (non-blocking, fails immediately if resources cannot be
reserved), -1 (infinite timeout), or any other positive numeric value (wait for
that number of seconds)

Returns:
SingleSessionReservation: Context manager that can be used with a with-statement to
unreserve the session.
A reservation object with which you can query information about the session and
unreserve it.
"""
session_info = self._reserve_sessions(
context, pin_or_relay_names, instrument_type_id, timeout
Expand All @@ -356,40 +371,44 @@ def reserve_session(
def reserve_sessions(
self,
context: PinMapContext,
pin_or_relay_names: Optional[Iterable[str]] = None,
pin_or_relay_names: Union[str, Iterable[str], None] = None,
instrument_type_id: Optional[str] = None,
timeout: Optional[float] = None,
timeout: Optional[float] = 0.0,
) -> MultiSessionReservation:
"""Reserve multiple sessions.

Reserve sessions matching the given pins, sites, and instrument type ID and return the
information needed to create or access the sessions.

Args:
context (PinMapContext): Includes the pin map ID for the pin map in the Pin Map Service,
context: Includes the pin map ID for the pin map in the Pin Map Service,
as well as the list of sites for the measurement.

pin_or_relay_names (Iterable[str]): List of pins, pin groups, relays, or relay groups to
use for the measurement. If unspecified, reserve sessions for all pins and relays in
the registered pin map resource.
pin_or_relay_names: One or multiple pins, pin groups, relays, or relay groups to use
for the measurement.

instrument_type_id (str): Instrument type ID for the measurement. If unspecified,
reserve sessions for all instrument types connected in the registered pin map
If unspecified, reserve sessions for all pins and relays in the registered pin map
resource.

instrument_type_id: Instrument type ID for the measurement.

If unspecified, this method reserves sessions for all instrument types connected
in the registered pin map resource.

For NI instruments, use instrument type id constants, such as
:py:const:`INSTRUMENT_TYPE_NI_DCPOWER` or :py:const:`INSTRUMENT_TYPE_NI_DMM`.

For custom instruments, use the instrument type id defined in the pin map file.

timeout (float): Timeout in seconds. Allowed values,
0 (non-blocking, fails immediately if resources cannot be reserved),
-1 or negative (infinite timeout), or
any positive numeric value (wait for that number of second).
timeout: Timeout in seconds.
bkeryan marked this conversation as resolved.
Show resolved Hide resolved

Allowed values: 0 (non-blocking, fails immediately if resources cannot be
reserved), -1 (infinite timeout), or any other positive numeric value (wait for
that number of seconds)

Returns:
MultiSessionReservation: Context manager that can be used with a with-statement to
unreserve the sessions.
A reservation object with which you can query information about the sessions and
unreserve them.
"""
session_info = self._reserve_sessions(
context, pin_or_relay_names, instrument_type_id, timeout
Expand All @@ -399,26 +418,24 @@ def reserve_sessions(
def _reserve_sessions(
self,
context: PinMapContext,
pin_or_relay_names: Optional[Iterable[str]] = None,
pin_or_relay_names: Union[str, Iterable[str], None] = None,
instrument_type_id: Optional[str] = None,
timeout: Optional[float] = None,
timeout: Optional[float] = 0.0,
) -> Sequence[session_management_service_pb2.SessionInformation]:
pin_map_context = pin_map_context_pb2.PinMapContext(
pin_map_id=context.pin_map_id, sites=context.sites
)

request = session_management_service_pb2.ReserveSessionsRequest(
pin_map_context=pin_map_context
pin_map_context=pin_map_context,
timeout_in_milliseconds=_timeout_to_milliseconds(timeout),
)
if instrument_type_id is not None:
request.instrument_type_id = instrument_type_id
if pin_or_relay_names is not None:
if isinstance(pin_or_relay_names, str):
request.pin_or_relay_names.append(pin_or_relay_names)
elif pin_or_relay_names is not None:
request.pin_or_relay_names.extend(pin_or_relay_names)
if timeout is not None:
timeout_in_ms = round(timeout * 1000)
if timeout_in_ms < 0:
timeout_in_ms = -1
request.timeout_in_milliseconds = timeout_in_ms

response = self._get_stub().ReserveSessions(request)
return response.sessions
Expand All @@ -431,16 +448,12 @@ def _unreserve_sessions(
self._get_stub().UnreserveSessions(request)

def register_sessions(self, session_info: Iterable[SessionInformation]) -> None:
"""Register the sessions with the Session Manager.
"""Register sessions with the session management service.

Indicates that the sessions are open and will need to be closed later.

Args:
session_info (Iterable[SessionInformation]): Sessions to register with the session
management service to track as the sessions are open.

Raises:
Exception: If a session by the same name is already registered.
session_info: Sessions to register.
"""
request = session_management_service_pb2.RegisterSessionsRequest(
sessions=(
Expand All @@ -465,14 +478,13 @@ def register_sessions(self, session_info: Iterable[SessionInformation]) -> None:
self._get_stub().RegisterSessions(request)

def unregister_sessions(self, session_info: Iterable[SessionInformation]) -> None:
"""Unregisters the sessions from the Session Manager.
"""Unregisters sessions from the session management service.

Indicates that the sessions have been closed and will need to be reopened before they can be
used again.

Args:
session_info (Iterable[SessionInformation]): Sessions to be registered.

session_info: Sessions to unregister.
"""
request = session_management_service_pb2.UnregisterSessionsRequest(
sessions=(
Expand All @@ -497,41 +509,52 @@ def unregister_sessions(self, session_info: Iterable[SessionInformation]) -> Non
self._get_stub().UnregisterSessions(request)

def reserve_all_registered_sessions(
self, instrument_type_id: Optional[str] = None, timeout: Optional[float] = None
self, instrument_type_id: Optional[str] = None, timeout: Optional[float] = 0.0
) -> MultiSessionReservation:
"""Reserves and gets all sessions currently registered in the Session Manager.
"""Reserve all sessions currently registered with the session management service.

Args:
instrument_type_id (str): Instrument type ID for the measurement. If unspecified,
reserve sessions for all instrument types connected in the registered pin map
resource.
instrument_type_id: Instrument type ID for the measurement.

If unspecified, reserve sessions for all instrument types connected in the
registered pin map resource.

For NI instruments, use instrument type id constants, such as
:py:const:`INSTRUMENT_TYPE_NI_DCPOWER` or :py:const:`INSTRUMENT_TYPE_NI_DMM`.

For custom instruments, use the instrument type id defined in the pin map file.

timeout (float): Timeout in seconds. Allowed values,
0 (non-blocking, fails immediately if resources cannot be reserved),
-1 or negative (infinite timeout), or
any positive numeric value (wait for that number of second).
timeout: Timeout in seconds.
bkeryan marked this conversation as resolved.
Show resolved Hide resolved

Allowed values: 0 (non-blocking, fails immediately if resources cannot be
reserved), -1 (infinite timeout), or any other positive numeric value (wait for
that number of seconds)

Returns:
MultiSessionReservation: Context manager that can be used with a with-statement to
unreserve the sessions.
A reservation object with which you can query information about the sessions and
unreserve them.
"""
request = session_management_service_pb2.ReserveAllRegisteredSessionsRequest()
request = session_management_service_pb2.ReserveAllRegisteredSessionsRequest(
timeout_in_milliseconds=_timeout_to_milliseconds(timeout)
)
if instrument_type_id is not None:
request.instrument_type_id = instrument_type_id
if timeout is not None:
timeout_in_ms = round(timeout * 1000)
if timeout_in_ms < 0:
timeout_in_ms = -1
request.timeout_in_milliseconds = timeout_in_ms

response = self._get_stub().ReserveAllRegisteredSessions(request)
return MultiSessionReservation(session_manager=self, session_info=response.sessions)


Client = SessionManagementClient
"""Alias for compatibility with code that uses session_management.Client."""


def _timeout_to_milliseconds(timeout: Optional[float]) -> int:
if timeout is None:
return 0
elif timeout == -1:
return -1
elif timeout < 0:
warnings.warn("Specify -1 for an infinite timeout.", RuntimeWarning)
return -1
else:
return round(timeout * 1000)
Loading
Loading