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

Use logging module instead of prints #345

Merged
merged 12 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ tm_devices.yaml
tm_devices.yml
*.log
*.dat
**/logs/**

# Poetry lock file
poetry.lock
Expand Down Expand Up @@ -58,6 +59,7 @@ coverage.xml
.pytest_cache/
.results*/
tests/samples/generated_stubs/*
tests/generated_**/*
tests/verify_devices.yaml
prof/

Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ Things to be included in the next release go here.
- Added the `get_errors()` method to the `Device` class to enable easy access to the current error code and messages on any device.
- Added more details to the Architectural Overview page of the documentation as well as highlighting to the device driver diagram on the page.
- Added regex matching to the `verify_values()` helper function to allow for more flexible value verification.
- A main logfile is now created by default (can be disabled if desired) that contains all the logging output of the entire tm_devices package during execution.
- Use the `configure_logging()` function to set the logging levels for stdout and file logging.
- The default settings will log all messages to the log file and maintain the current printout functionality on stdout.
- A logfile is now created that contains each command sent to a VISA device.
- This file is located next to the main log file and will start with the same name, but have the unique address of the device appended.
- This file will only be created if file logging is enabled for the package (which is the default behavior).

### Changed

Expand All @@ -46,17 +52,23 @@ 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 config file and environment variable can also be used to control the logging functionality.
- The debug logging from the `pyvisa` package is also included in the log file by default.

### Removed

- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed previously deprecated `TekScopeSW` alias to the `TekScopePC` class
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed previously deprecated `TekScopeSW` alias to the `TekScopePC` class.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed previously deprecated `write_buffers()` from the `TSPControl` class.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed Internal AFG methods from the `TekScopePC` driver, since they wouldn't have worked due to its lack of an IAFG.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed previously deprecated `DEVICE_DRIVER_MODEL_MAPPING` constant.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed the `DEVICE_TYPE_CLASSES` constant and the `device_type_classes.py` module.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed many hacky implementations of `total_channels` and `all_channel_names_list` properties from drivers that don't need them anymore.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed the `verify_values()`, `raise_failure()`, and `raise_error()` methods from all device drivers.
- These methods have been converted to helper functions and can be imported from the `tm_devices.helpers` subpackage now.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed the `print_with_timestamp()` function since this functionality is now handled by the `logging` module.
- _**<span style="color:red">BREAKING CHANGE</span>**_: Removed the `get_timestamp_string()` function since this functionality is now handled by the `logging` module.

---

Expand Down
20 changes: 10 additions & 10 deletions README.md

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion docs/basic_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This will print the available VISA devices to the console when run from a shell
```console
$ list-visa-resources
[
"TCPIP0::192.168.0.100::inst0::INSTR",
"TCPIP0::192.168.0.1::inst0::INSTR",
"ASRL4::INSTR"
]
```
Expand Down Expand Up @@ -59,6 +59,23 @@ outside the Python code for ease of automation
--8<-- "examples/miscellaneous/adding_devices_with_env_var.py"
```

## Customize logging and console output

The amount of console output and logging saved to the log file can be customized as needed. This
configuration can be done in the Python code itself as demonstrated here, or by using the
[config file](configuration.md#config-options) or
[environment variable](configuration.md#environment-variable).

!!! important
If any configuration is performed in the Python code prior to instantiating the
[`DeviceManager`][tm_devices.DeviceManager], all other logging configuration methods
(config file, env var) will be ignored.

```python
# fmt: off
--8<-- "examples/miscellaneous/customize_logging.py"
```

## Disable command checking

This removes an extra query that verifies the property was set to the expected
Expand Down
47 changes: 44 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,7 @@ devices:

### Config Options

These options are flags that enable/disable runtime behaviors of the Device
Manager.
These options are used to configure runtime behaviors of `tm_devices`.

#### Yaml Options Syntax

Expand All @@ -230,6 +229,12 @@ options:
retry_visa_connection: false
default_visa_timeout: 5000
check_for_updates: false
log_console_level: INFO
log_file_level: DEBUG
log_file_directory: ./logs
log_file_name: tm_devices_<timestamp>.log
log_colored_output: false
log_pyvisa_messages: false
```

These are all `false` by default if not defined, set to `true` to modify the
Expand Down Expand Up @@ -259,6 +264,30 @@ runtime behavior configuration.
- `check_for_updates`
- This config option will enable a check for any available updates on pypi.org for the
package when the `DeviceManager` is instantiated.
- `log_console_level`
- This config option is used to set the log level for the console output.
The default value of this config option is "INFO". See the
[`configure_logging()`][tm_devices.helpers.logging.configure_logging] function for more information.
- `log_file_level`
- This config option is used to set the log level for the file output.
The default value of this config option is "DEBUG". See the
[`configure_logging()`][tm_devices.helpers.logging.configure_logging] function for more information.
- `log_file_directory`
- This config option is used to set the directory where the log files will be saved.
The default value of this config option is "./logs". See the
[`configure_logging()`][tm_devices.helpers.logging.configure_logging] function for more information.
- `log_file_name`
- This config option is used to set the name of the log file.
The default value of this config option is a timestamped filename with the .log extension. See the
[`configure_logging()`][tm_devices.helpers.logging.configure_logging] function for more information.
- `log_colored_output`
- This config option is used to enable or disable colored output in the console.
The default value of this config option is false. See the
[`configure_logging()`][tm_devices.helpers.logging.configure_logging] function for more information.
- `log_pyvisa_messages`
- This config option is used to enable or disable logging of PyVISA messages within the
configured log file. The default value of this config option is false. See the
[`configure_logging()`][tm_devices.helpers.logging.configure_logging] function for more information.

### Sample Config File

Expand Down Expand Up @@ -320,6 +349,12 @@ options:
retry_visa_connection: false
default_visa_timeout: 10000 # 10 second default VISA timeout
check_for_updates: false
log_console_level: NONE # completely disable console output
log_file_level: DEBUG
log_file_directory: ./logs
log_file_name: custom_logfile.log # customize the log file name
log_colored_output: false
log_pyvisa_messages: true # log PyVISA messages in the log file
```

#### TOML
Expand Down Expand Up @@ -393,8 +428,14 @@ standalone = false
verbose_mode = false
verbose_visa = false
retry_visa_connection = false
default_visa_timeout = 10000 # 10 second default VISA timeout
default_visa_timeout = 10000 # 10 second default VISA timeout
check_for_updates = false
log_console_level = "NONE" # completely disable console output
log_file_level = "DEBUG"
log_file_directory = "./logs"
log_file_name = "custom_logfile.log" # customize the log file name
log_colored_output = false
log_pyvisa_messages = true # log PyVISA messages in the log file
```

---
Expand Down
1 change: 1 addition & 0 deletions docs/key_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ complex examples.
IntelliSense.
- Organize connections to an entire "Test Bench" of devices with one package!
- Full support for all VISA connection types (some require external drivers).
- Customizable logging to both the console and a log file.
3 changes: 3 additions & 0 deletions docs/known_words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ ci
classdiagram
codebase
codecov
colored
config
conftest
cookiecutter
cov
csv
customizable
deps
dev
disable_command_verification
Expand All @@ -33,6 +35,7 @@ docstring
docstrings
en
enum
env
executables
filepath
generate_function
Expand Down
4 changes: 2 additions & 2 deletions docs/macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ def define_env(env: MacrosPlugin) -> None:
used to perform a transformation
"""
# Read in the current package version number to use in templates and files
with open(
pathlib.Path(f"{pathlib.Path(__file__).parents[1]}") / "pyproject.toml", "rb"
with (pathlib.Path(f"{pathlib.Path(__file__).parents[1]}") / "pyproject.toml").open(
"rb"
) as file_handle:
pyproject_data = tomli.load(file_handle)
package_version = "v" + pyproject_data["tool"]["poetry"]["version"]
Expand Down
21 changes: 21 additions & 0 deletions examples/miscellaneous/customize_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""The console output and level of logging outputs in the log file can be configured as needed."""

from tm_devices import configure_logging, DeviceManager, LoggingLevels
from tm_devices.drivers import MSO6B

# NOTE: This configuration will prevent any logging config options from a config file or
# environment variable from being used.
configure_logging(
log_console_level=LoggingLevels.NONE, # completely disable console logging
log_file_level=LoggingLevels.DEBUG, # log everything to the file
log_file_directory="./log_files", # save the log file in the "./log_files" directory
log_file_name="custom_log_filename.log", # customize the filename
log_pyvisa_messages=True, # include all the pyvisa debug messages in the same log file
)

with DeviceManager(verbose=False) as dm:
scope: MSO6B = dm.add_scope("192.168.0.1")
scope.curve_query(1)
scope.check_port_connection(4000)
scope.check_network_connection()
scope.check_visa_connection()
2 changes: 1 addition & 1 deletion examples/miscellaneous/register_dm_atexit.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
atexit.register(dm.close)

# Add a device
scope: MSO6B = dm.add_scope("192.168.1.102")
scope: MSO6B = dm.add_scope("192.168.0.1")

# Use the device
print(scope)
Expand Down
6 changes: 4 additions & 2 deletions examples/scopes/tekscope/basic_curve_query.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""An example showing a basic curve query."""

from pathlib import Path

from tm_devices import DeviceManager
from tm_devices.drivers import AFG3KC, MSO5

EXAMPLE_CSV_FILE = "example_curve_query.csv"
EXAMPLE_CSV_FILE = Path("example_curve_query.csv")

with DeviceManager(verbose=True) as dm:
scope: MSO5 = dm.add_scope("MSO56-100083")
Expand All @@ -16,7 +18,7 @@
curve_returned = scope.curve_query(1, output_csv_file=EXAMPLE_CSV_FILE)

# Read in the curve query from file
with open(EXAMPLE_CSV_FILE, encoding="utf-8") as csv_content:
with EXAMPLE_CSV_FILE.open(encoding="utf-8") as csv_content:
curve_saved = [int(i) for i in csv_content.read().split(",")]

# Verify query saved to csv is the same as the one returned from curve_query function call
Expand Down
2 changes: 1 addition & 1 deletion examples/scopes/tekscope/basic_save_recall.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

with DeviceManager(verbose=True) as dm:
# Get a scope
scope: MSO6B = dm.add_scope("192.168.1.177")
scope: MSO6B = dm.add_scope("192.168.0.1")

# Send some commands
scope.add_new_math("MATH1", "CH1") # add MATH1 to CH1
Expand Down
2 changes: 1 addition & 1 deletion examples/scopes/tekscope/generate_internal_afg_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

with DeviceManager(verbose=True) as dm:
# Create a connection to the scope and indicate that it is a MSO5 scope for type hinting
scope: MSO5 = dm.add_scope("192.168.1.102")
scope: MSO5 = dm.add_scope("192.168.0.1")

# Generate the signal using individual PI commands.
scope.commands.afg.frequency.write(10e6) # set frequency
Expand Down
2 changes: 1 addition & 1 deletion examples/scopes/tekscope/save_screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

with DeviceManager(verbose=True) as dm:
# Add a scope
scope: MSO6B = dm.add_scope("192.168.1.5")
scope: MSO6B = dm.add_scope("192.168.0.1")

# Send some commands
scope.add_new_math("MATH1", "CH1") # add MATH1 to CH1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from tm_devices.drivers import SMU2450

with DeviceManager(verbose=False) as device_manager:
inst: SMU2450 = device_manager.add_smu("192.168.1.4", alias="my2450")
inst: SMU2450 = device_manager.add_smu("192.168.0.1", alias="my2450")

# Reset the instrument, which also clears the buffer.
inst.commands.reset()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
with DeviceManager() as device_manager:
print(device_manager.get_available_devices())

inst: SMU2450 = device_manager.add_smu("192.168.4.74", alias="my2450")
inst: SMU2450 = device_manager.add_smu("192.168.0.1", alias="my2450")

# Configure the Simple Loop trigger model template to make 100 readings.
inst.commands.trigger.model.load_simple_loop(100)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
with DeviceManager() as device_manager:
print(device_manager.get_available_devices())

inst: SMU2450 = device_manager.add_smu("192.168.4.74", alias="my2450")
inst: SMU2450 = device_manager.add_smu("192.168.0.1", alias="my2450")

# Clear the buffer.
inst.commands.buffer_var["defbuffer1"].clear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
with DeviceManager() as device_manager:
print(device_manager.get_available_devices())

inst: SMU2450 = device_manager.add_smu("192.168.4.74", alias="my2450")
inst: SMU2450 = device_manager.add_smu("192.168.0.1", alias="my2450")

# Define the number of points in the sweep.
POINTS = 56
Expand Down
Loading
Loading