Skip to content

Commit

Permalink
feat: Added the pyvisa log to the file.
Browse files Browse the repository at this point in the history
Also updated the tests to work properly with the new logging
  • Loading branch information
nfelt14 committed Nov 9, 2024
1 parent 5925bc8 commit 6267588
Show file tree
Hide file tree
Showing 24 changed files with 201 additions and 130 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ However, please read through all changes to be aware of what may potentially imp
- _**<span style="color:red">BREAKING CHANGE</span>**_: Changed the behavior of the `expect_esr()` method to expect an integer error code input and an optional tuple of error messages to compare against the actual error code and messages returned by the `_get_errors()` private method.
- _**<span style="color:orange">minor breaking change</span>**_: Converted the `device_type` property into an abstract, cached property to force all children of the `Device` class to specify what type of device they are.
- Updated the auto-generated command mixin classes to no longer use an `__init__()` method to enable the driver API documentation to render in a more usable way.
- Switched from using standard `print()` calls to using the `logging` module for all logging in the `tm_devices` package.
- A configuration function provides the ability to set different logging levels for stdout and file logging.
- The debug logging from the `pyvisa` package is also included in the log file by default.

### Removed

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ filterwarnings = [
]
junit_family = "xunit2"
junit_logging = "all"
log_format = "[%(asctime)s] [%(levelname)8s] %(message)s"
markers = [
'docs',
'order',
Expand Down
14 changes: 7 additions & 7 deletions src/tm_devices/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from tm_devices.helpers import (
AliasDict,
check_for_update,
configure_logging,
ConnectionTypes,
create_visa_connection,
detect_visa_resource_expression,
Expand Down Expand Up @@ -135,11 +136,7 @@ def __init__(
(updates the current configuration options).
external_device_drivers: An optional dict for passing in additional device drivers.
"""
# pylint: disable=import-outside-toplevel
if not logging.getLogger(PACKAGE_NAME).hasHandlers():
from tm_devices.helpers.logging import configure_logging

configure_logging()
configure_logging()
self._suppress_protection = False
# Set up the DeviceManager
self.__is_open = False
Expand Down Expand Up @@ -260,8 +257,11 @@ def verbose_visa(self, value: bool) -> None:
visa.log_to_screen()
else:
for handler in visa.logger.handlers.copy():
if "DEBUG" in str(handler):
visa.logger.removeHandler(handler)
if "DEBUG" in str(handler) and (
isinstance(handler, logging.StreamHandler)
and not isinstance(handler, logging.FileHandler)
):
visa.logger.removeHandler(handler) # pyright: ignore[reportUnknownArgumentType]
self.__config.options.verbose_visa = value
self.__verbose_visa = value

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
"""
self._is_open = False
self._verbose = verbose
Expand Down
12 changes: 6 additions & 6 deletions src/tm_devices/driver_mixins/device_control/pi_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ def __init__(
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
visa_resource: The VISA resource object.
default_visa_timeout: The default VISA timeout value in milliseconds.
"""
Expand Down Expand Up @@ -124,7 +126,7 @@ def visa_timeout(self, timeout_ms: float) -> None:
timeout_ms: The new VISA timeout, in milliseconds.
"""
self._visa_resource.timeout = timeout_ms
_logger.debug("%s VISA timeout set to: %fms", self._name_and_alias, timeout_ms)
_logger.debug("%s VISA timeout set to: %.3fms", self._name_and_alias, timeout_ms)

@property
def visa_resource(self) -> visa.resources.MessageBasedResource:
Expand Down Expand Up @@ -771,7 +773,6 @@ def wait_for_visa_connection(
wait_time: float,
sleep_seconds: int = 5,
accept_immediate_connection: bool = False,
verbose: bool = True,
) -> bool:
"""Wait for a VISA connection to be made to the device.
Expand All @@ -780,7 +781,6 @@ def wait_for_visa_connection(
sleep_seconds: The number of seconds to sleep in between connection attempts.
accept_immediate_connection: A boolean indicating if a connection on the
first attempt is a valid connection.
verbose: Set this to False in order to disable printouts.
Returns:
A boolean indicating if a VISA connection was made within the given time limit.
Expand All @@ -791,7 +791,7 @@ def wait_for_visa_connection(
attempt_num = 0
visa_connection = False
_logger.log(
logging.INFO if verbose else logging.DEBUG,
logging.INFO if self._verbose else logging.DEBUG,
"Attempting to establish a VISA connection with %s",
self._resource_expression,
)
Expand All @@ -815,7 +815,7 @@ def wait_for_visa_connection(

if visa_connection:
_logger.log(
logging.INFO if verbose else logging.DEBUG,
logging.INFO if self._verbose else logging.DEBUG,
"Successfully established a VISA connection with %s after %.2f seconds",
self._resource_expression,
total_time,
Expand Down
27 changes: 6 additions & 21 deletions src/tm_devices/driver_mixins/device_control/rest_api_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
"""
super().__init__(config_entry, verbose)

Expand Down Expand Up @@ -78,7 +80,6 @@ def delete( # noqa: PLR0913
allow_errors: bool = False,
verify_ssl: bool = True,
allow_redirects: bool = False,
verbose: bool = True,
) -> Tuple[bool, Union[Dict[str, Any], bytes], int, Optional[requests.RequestException]]:
"""Perform a DELETE request with the given url and headers.
Expand All @@ -92,7 +93,6 @@ def delete( # noqa: PLR0913
verify_ssl: A bool that indicates if the SSL certificate should be verified.
allow_redirects: A bool that indicates if URL redirects should be allowed.
allow_errors: A boolean indicating if errors are allowed.
verbose: Set this to False in order to disable printouts.
Returns:
A tuple containing a success boolean, the response data, status code, and any errors
Expand All @@ -107,7 +107,6 @@ def delete( # noqa: PLR0913
allow_errors=allow_errors,
verify_ssl=verify_ssl,
allow_redirects=allow_redirects,
verbose=verbose,
)

# pylint: disable=too-many-arguments
Expand All @@ -121,7 +120,6 @@ def get( # noqa: PLR0913
allow_errors: bool = False,
verify_ssl: bool = True,
allow_redirects: bool = False,
verbose: bool = True,
) -> Tuple[bool, Union[Dict[str, Any], bytes], int, Optional[requests.RequestException]]:
"""Perform a GET request with the given url and headers.
Expand All @@ -135,7 +133,6 @@ def get( # noqa: PLR0913
verify_ssl: A bool that indicates if the SSL certificate should be verified.
allow_redirects: A bool that indicates if URL redirects should be allowed.
allow_errors: A boolean indicating if errors are allowed.
verbose: Set this to False in order to disable printouts.
Returns:
A tuple containing a success boolean, the response data, status code, and any errors
Expand All @@ -150,7 +147,6 @@ def get( # noqa: PLR0913
allow_errors=allow_errors,
verify_ssl=verify_ssl,
allow_redirects=allow_redirects,
verbose=verbose,
)

# pylint: disable=too-many-arguments
Expand All @@ -166,7 +162,6 @@ def patch( # noqa: PLR0913
allow_errors: bool = False,
verify_ssl: bool = True,
allow_redirects: bool = False,
verbose: bool = True,
) -> Tuple[bool, Union[Dict[str, Any], bytes], int, Optional[requests.RequestException]]:
"""Perform a PATCH request with the given url and headers.
Expand All @@ -185,7 +180,6 @@ def patch( # noqa: PLR0913
verify_ssl: A bool that indicates if the SSL certificate should be verified.
allow_redirects: A bool that indicates if URL redirects should be allowed.
allow_errors: A boolean indicating if errors are allowed.
verbose: Set this to False in order to disable printouts.
Returns:
A tuple containing a success boolean, the response data, status code, and any errors
Expand All @@ -202,7 +196,6 @@ def patch( # noqa: PLR0913
allow_errors=allow_errors,
verify_ssl=verify_ssl,
allow_redirects=allow_redirects,
verbose=verbose,
)

# pylint: disable=too-many-arguments
Expand All @@ -218,7 +211,6 @@ def post( # noqa: PLR0913
allow_errors: bool = False,
verify_ssl: bool = True,
allow_redirects: bool = False,
verbose: bool = True,
) -> Tuple[bool, Union[Dict[str, Any], bytes], int, Optional[requests.RequestException]]:
"""Perform a POST request with the given url and headers.
Expand All @@ -237,7 +229,6 @@ def post( # noqa: PLR0913
verify_ssl: A bool that indicates if the SSL certificate should be verified.
allow_redirects: A bool that indicates if URL redirects should be allowed.
allow_errors: A boolean indicating if errors are allowed.
verbose: Set this to False in order to disable printouts.
Returns:
A tuple containing a success boolean, the response data, status code, and any errors
Expand All @@ -254,7 +245,6 @@ def post( # noqa: PLR0913
allow_errors=allow_errors,
verify_ssl=verify_ssl,
allow_redirects=allow_redirects,
verbose=verbose,
)

# pylint: disable=too-many-arguments
Expand All @@ -270,7 +260,6 @@ def put( # noqa: PLR0913
allow_errors: bool = False,
verify_ssl: bool = True,
allow_redirects: bool = False,
verbose: bool = True,
) -> Tuple[bool, Union[Dict[str, Any], bytes], int, Optional[requests.RequestException]]:
"""Perform a PUT request with the given url and headers.
Expand All @@ -289,7 +278,6 @@ def put( # noqa: PLR0913
verify_ssl: A bool that indicates if the SSL certificate should be verified.
allow_redirects: A bool that indicates if URL redirects should be allowed.
allow_errors: A boolean indicating if errors are allowed.
verbose: Set this to False in order to disable printouts.
Returns:
A tuple containing a success boolean, the response data, status code, and any errors
Expand All @@ -306,7 +294,6 @@ def put( # noqa: PLR0913
allow_errors=allow_errors,
verify_ssl=verify_ssl,
allow_redirects=allow_redirects,
verbose=verbose,
)

def set_api_version(self, api_version: int) -> None:
Expand Down Expand Up @@ -411,7 +398,6 @@ def _send_request( # noqa: PLR0913,PLR0912,C901
allow_errors: bool = False,
verify_ssl: bool = True,
allow_redirects: bool = False,
verbose: bool = True,
) -> Tuple[bool, Union[Dict[str, Any], bytes], int, Optional[requests.RequestException]]:
"""Perform a request with the given url and headers.
Expand All @@ -431,7 +417,6 @@ def _send_request( # noqa: PLR0913,PLR0912,C901
verify_ssl: A bool that indicates if the SSL certificate should be verified.
allow_redirects: A bool that indicates if URL redirects should be allowed.
allow_errors: A boolean indicating if errors are allowed.
verbose: Set this to False in order to disable printouts.
Returns:
A tuple containing a success boolean, the response data, status code, and any errors
Expand All @@ -450,10 +435,10 @@ def _send_request( # noqa: PLR0913,PLR0912,C901
response = cast(requests.Response, None)
retval: Union[Dict[str, Any], bytes] = {}
_logger.log(
logging.INFO if verbose else logging.DEBUG,
logging.INFO if self._verbose else logging.DEBUG,
"(%s) %s >> %s%s%s",
self._name_and_alias,
request_type.value,
getattr(request_type, "value", request_type),
url,
f", {headers=}" if headers else "",
f", {json_body=}" if json_body else "",
Expand Down Expand Up @@ -515,7 +500,7 @@ def _send_request( # noqa: PLR0913,PLR0912,C901
raise ValueError(msg)

_logger.log(
logging.INFO if verbose else logging.DEBUG,
logging.INFO if self._verbose else logging.DEBUG,
"Response from %s >>\n%s",
request_type.value,
json.dumps(response.json(), indent=2) if not return_bytes else response.text,
Expand Down
17 changes: 12 additions & 5 deletions src/tm_devices/driver_mixins/device_control/tsp_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,18 @@ def print_buffers(self, *args: str) -> None:
def fix_width(key: str, value: Any) -> str: # Function to add spaces if needed
return str(value) + " " * (column_widths[key] - len(str(value)))

print(*[fix_width(x, x) for x in buffer_data]) # noqa: T201
for index in range(column_length):
print( # noqa: T201
*[fix_width(k, v[index] if index < len(v) else "") for k, v in buffer_data.items()]
)
buffer_headers = [fix_width(x, x) for x in buffer_data]
buffer_rows: List[List[Any]] = [
[fix_width(k, v[index] if index < len(v) else "") for k, v in buffer_data.items()]
for index in range(column_length)
]
_logger.info(
"(%s) Printing Buffers %s >>\n%s\n%s",
self._name_and_alias,
buffer_headers,
" ".join(buffer_headers),
"\n".join(" ".join(row) for row in buffer_rows),
)

def run_script(self, script_name: str) -> None:
"""Run a TSP script on the instrument.
Expand Down
4 changes: 3 additions & 1 deletion src/tm_devices/drivers/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
"""
super().__init__(config_entry, verbose)
self._is_open = True
Expand Down
4 changes: 3 additions & 1 deletion src/tm_devices/drivers/margin_testers/margin_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
"""
super().__init__(config_entry, verbose)

Expand Down
20 changes: 12 additions & 8 deletions src/tm_devices/drivers/margin_testers/tmt4.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
Notes:
The default port is 5000, but device could be configured for any specific port.
Expand Down Expand Up @@ -110,11 +112,12 @@ def request_about_info(self, verbose: bool = True) -> Dict[str, Any]:
A Dictionary with information about the Margin device.
"""
# Make get request to about and version endpoints
_, res_json, _, _ = self.get("/device/about", verbose=verbose)
res_json = cast(Dict[str, Any], res_json)
_, res_json2, _, _ = self.get("/device/version", verbose=verbose)
res_json2 = cast(Dict[str, Any], res_json2)
res_json.update(res_json2)
with self.temporary_verbose(verbose):
_, res_json, _, _ = self.get("/device/about")
res_json = cast(Dict[str, Any], res_json)
_, res_json2, _, _ = self.get("/device/version")
res_json2 = cast(Dict[str, Any], res_json2)
res_json.update(res_json2)
return res_json

def wait_till_unlocked(self, timeout: int = 120) -> None:
Expand Down Expand Up @@ -144,8 +147,9 @@ def _check_api_connection(self) -> bool:
Returns:
A boolean indicating if the call was successful.
"""
# allow_errors is set to True since this is just checking if the API is reachable
return self.get("/device/about", allow_errors=True, verbose=False)[0]
with self.temporary_verbose(False):
# allow_errors is set to True since this is just checking if the API is reachable
return self.get("/device/about", allow_errors=True)[0]

def _cleanup(self) -> None:
"""Perform the cleanup defined for the device."""
4 changes: 3 additions & 1 deletion src/tm_devices/drivers/scopes/tekscope/mso2.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ def __init__(
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
visa_resource: The VISA resource object.
default_visa_timeout: The default VISA timeout value in milliseconds.
"""
Expand Down
4 changes: 3 additions & 1 deletion src/tm_devices/drivers/scopes/tekscope/tekscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ def __init__(
Args:
config_entry: A config entry object parsed by the DMConfigParser.
verbose: A boolean indicating if verbose output should be printed.
verbose: A boolean indicating if verbose output should be printed. If True,
communication printouts will be logged with a level of INFO. If False,
communication printouts will be logged with a level of DEBUG.
visa_resource: The VISA resource object.
default_visa_timeout: The default VISA timeout value in milliseconds.
"""
Expand Down
Loading

0 comments on commit 6267588

Please sign in to comment.