From a83fb4f7d5bbad72c485106785633eb9836c8e46 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Wed, 2 Aug 2023 17:24:35 -0700 Subject: [PATCH 01/18] ci: Update workflows to not push package yet. --- .github/workflows/package-build.yml | 89 +++++++++---------- pyproject.toml | 9 ++ src/tm_devices/drivers/api/__init__.py | 1 - .../drivers/api/rest_api/__init__.py | 1 - src/tm_devices/drivers/pi/__init__.py | 1 - 5 files changed, 53 insertions(+), 48 deletions(-) diff --git a/.github/workflows/package-build.yml b/.github/workflows/package-build.yml index 23d6d9f7..79ec66b5 100644 --- a/.github/workflows/package-build.yml +++ b/.github/workflows/package-build.yml @@ -25,48 +25,47 @@ jobs: with: fetch-depth: 0 - uses: hynek/build-and-inspect-python-package@v1.5 - - # Upload to Test PyPI on every push to main - test-pypi: - name: Publish package to test.pypi.org - environment: - name: test-pypi - url: https://test.pypi.org/p/tm_devices - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - needs: build-package - steps: - - name: Download built package - uses: actions/download-artifact@v3 - with: - name: Package - path: dist - - name: Upload package to Test PyPI - uses: pypa/gh-action-pypi-publish@v1.8.8 - with: - repository-url: https://test.pypi.org/legacy/ - - # Upload to PyPI and create a tag in the repo after a GitHub Release is published - pypi: - name: Publish released package to pypi.org and create new tag in repo - environment: - name: pypi - url: https://pypi.org/p/tm_devices - if: github.event.action == 'published' - runs-on: ubuntu-latest - needs: build-package - permissions: - contents: write - steps: - - uses: actions/checkout@v3 - - name: Download built package - uses: actions/download-artifact@v3 - with: - name: Package - path: dist - - name: Upload package to PyPI - uses: pypa/gh-action-pypi-publish@v1.8.8 - - name: Create and push tag - run: |- - git tag --annotate v${{ github.event.release.tag_name }} --message="${{ github.event.release.name }}" - git push --tags +# # Upload to Test PyPI on every push to main +# test-pypi: +# name: Publish package to test.pypi.org +# environment: +# name: test-pypi +# url: https://test.pypi.org/p/tm_devices +# if: github.event_name == 'push' && github.ref == 'refs/heads/main' +# runs-on: ubuntu-latest +# needs: build-package +# steps: +# - name: Download built package +# uses: actions/download-artifact@v3 +# with: +# name: Package +# path: dist +# - name: Upload package to Test PyPI +# uses: pypa/gh-action-pypi-publish@v1.8.8 +# with: +# repository-url: https://test.pypi.org/legacy/ +# +# # Upload to PyPI and create a tag in the repo after a GitHub Release is published +# pypi: +# name: Publish released package to pypi.org and create new tag in repo +# environment: +# name: pypi +# url: https://pypi.org/p/tm_devices +# if: github.event.action == 'published' +# runs-on: ubuntu-latest +# needs: build-package +# permissions: +# contents: write +# steps: +# - uses: actions/checkout@v3 +# - name: Download built package +# uses: actions/download-artifact@v3 +# with: +# name: Package +# path: dist +# - name: Upload package to PyPI +# uses: pypa/gh-action-pypi-publish@v1.8.8 +# - name: Create and push tag +# run: |- +# git tag --annotate v${{ github.event.release.tag_name }} --message="${{ github.event.release.name }}" +# git push --tags diff --git a/pyproject.toml b/pyproject.toml index 3b43b10a..b7d04c13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -324,6 +324,15 @@ order-by-type = false "S105", # Possible hardcoded password "TID252" # Relative imports from parent modules are banned ] +"src/tm_devices/drivers/api/__init__.py" = [ + "D104" # Missing docstring in public package +] +"src/tm_devices/drivers/api/rest_api/__init__.py" = [ + "D104" # Missing docstring in public package +] +"src/tm_devices/drivers/pi/__init__.py" = [ + "D104" # Missing docstring in public package +] "tests/**" = [ "PLC1901", # compare-to-empty-string "PLR2004", # Magic value used in comparison diff --git a/src/tm_devices/drivers/api/__init__.py b/src/tm_devices/drivers/api/__init__.py index 8dbaf7ef..e69de29b 100644 --- a/src/tm_devices/drivers/api/__init__.py +++ b/src/tm_devices/drivers/api/__init__.py @@ -1 +0,0 @@ -# ruff: noqa: D104 diff --git a/src/tm_devices/drivers/api/rest_api/__init__.py b/src/tm_devices/drivers/api/rest_api/__init__.py index 8dbaf7ef..e69de29b 100644 --- a/src/tm_devices/drivers/api/rest_api/__init__.py +++ b/src/tm_devices/drivers/api/rest_api/__init__.py @@ -1 +0,0 @@ -# ruff: noqa: D104 diff --git a/src/tm_devices/drivers/pi/__init__.py b/src/tm_devices/drivers/pi/__init__.py index 8dbaf7ef..e69de29b 100644 --- a/src/tm_devices/drivers/pi/__init__.py +++ b/src/tm_devices/drivers/pi/__init__.py @@ -1 +0,0 @@ -# ruff: noqa: D104 From b2bbb74f24bf90accf2a2f1dbab88e29a2e4ae1c Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Wed, 2 Aug 2023 17:46:14 -0700 Subject: [PATCH 02/18] ci: Specify the coverage file for codecov. --- .github/workflows/test-code.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index cf2775ef..161fb06a 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -25,6 +25,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + check-latest: true - name: Install dependencies run: | python -m pip install --upgrade pip @@ -35,6 +36,7 @@ jobs: test-fast: runs-on: ${{ matrix.os_name }}-latest strategy: + fail-fast: false matrix: os_name: [ubuntu, macos, windows] steps: @@ -42,6 +44,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: x # any version + check-latest: true - name: Install tox run: | python -m pip install --upgrade pip @@ -49,7 +52,8 @@ jobs: - name: Test run: tox -ve tests - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: + files: ./.coverage.tests name: codecov-${{ matrix.os_name }} fail_ci_if_error: true From c0b08ea32d05350951b552e45d4d79828ff1b98f Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Wed, 2 Aug 2023 17:53:28 -0700 Subject: [PATCH 03/18] ci: Make sure to check out the code when running tests. --- .github/workflows/test-code.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index 161fb06a..1fa6d287 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -40,6 +40,7 @@ jobs: matrix: os_name: [ubuntu, macos, windows] steps: + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: From 378508dce63522e2a20dac81b0efe0f2879e0b42 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Wed, 2 Aug 2023 18:09:45 -0700 Subject: [PATCH 04/18] docs: Update badges to indicate build status of GitHub actions. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38486b65..d6732072 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@

-Code testing status -Docs testing status -Package build status +Code testing status +Docs testing status +Package build status Coverage status -CodeQL status +CodeQL status pre-commit enabled pre-commit status Documentation status From 6e88ac9f8337f218ea93977bdc5bf1162c9e3fb1 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 08:26:43 -0700 Subject: [PATCH 05/18] ci: Add new checks that make it simpler to gate code changes. --- .github/workflows/tek-repo-lint.yml | 16 ++++++++++++++++ .github/workflows/test-code.yml | 11 +++++++++++ .github/workflows/test-docs.yml | 11 +++++++++++ 3 files changed, 38 insertions(+) diff --git a/.github/workflows/tek-repo-lint.yml b/.github/workflows/tek-repo-lint.yml index 1db77839..b934d8e3 100644 --- a/.github/workflows/tek-repo-lint.yml +++ b/.github/workflows/tek-repo-lint.yml @@ -7,6 +7,7 @@ on: branches: [main] release: workflow_dispatch: +# IMPORTANT: Any new jobs need to be added to the check-repo-lint-passed job to ensure they correctly gate code changes jobs: check-for-codeowners-file: runs-on: ubuntu-latest @@ -98,3 +99,18 @@ jobs: - name: codeql-analysis file does not exist if: steps.codeql-analysis_file.outputs.file_exists == 'false' run: echo codeql-analysis file does not exist! + # Check that all jobs passed + check-repo-lint-passed: + if: always() + needs: + - check-for-codeowners-file + - check-for-readme-file + - check-for-license + - check-for-dependabot-file + - check-for-codeql-file + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index 1fa6d287..a0e326e8 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -10,6 +10,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# IMPORTANT: Any new jobs need to be added to the check-tests-passed job to ensure they correctly gate code changes jobs: # Basic testing & linting test-general: @@ -58,3 +59,13 @@ jobs: files: ./.coverage.tests name: codecov-${{ matrix.os_name }} fail_ci_if_error: true + # Check that all jobs passed + check-tests-passed: + if: always() + needs: [test-general, test-fast] + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 7fcca8b3..4f3f985a 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -10,6 +10,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# IMPORTANT: Any new jobs need to be added to the check-docs-passed job to ensure they correctly gate code changes jobs: # Test building the docs (html, linkcheck, doctest, coverage) test-docs: @@ -35,3 +36,13 @@ jobs: python -m pip install --upgrade tox - name: Test run: tox -ve ${{ matrix.tox_env }} + # Check that all jobs passed + check-docs-passed: + if: always() + needs: [test-docs] + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} From e323f2ba99309ee8e6f1c24be02223965dea6f30 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 08:41:09 -0700 Subject: [PATCH 06/18] ci: Comment out codecov for now. --- .github/workflows/test-code.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index a0e326e8..74fba40f 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -53,12 +53,12 @@ jobs: python -m pip install --upgrade tox - name: Test run: tox -ve tests - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - files: ./.coverage.tests - name: codecov-${{ matrix.os_name }} - fail_ci_if_error: true +# - name: Upload coverage to Codecov +# uses: codecov/codecov-action@v3 +# with: +# files: ./.coverage.tests +# name: codecov-${{ matrix.os_name }} +# fail_ci_if_error: true # Check that all jobs passed check-tests-passed: if: always() From e4e54b3c98e7c9e4c64a97c98d05eddd1e3f4e54 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 09:00:04 -0700 Subject: [PATCH 07/18] ci: Save artifacts after running tests. --- .github/workflows/test-code.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index 74fba40f..012aaee2 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -24,6 +24,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 + id: set_up_python with: python-version: ${{ matrix.python-version }} check-latest: true @@ -33,6 +34,11 @@ jobs: python -m pip install --upgrade tox tox-gh-actions - name: Run tox run: tox -v + - uses: actions/upload-artifact@v3 + if: '!cancelled()' + with: + name: artifact_${{ set_up_python.python-version }}_tests_and_linting + path: .results_*/** # Quick testing with coverage (no linting) test-fast: runs-on: ${{ matrix.os_name }}-latest @@ -44,6 +50,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 + id: set_up_python with: python-version: x # any version check-latest: true @@ -53,6 +60,12 @@ jobs: python -m pip install --upgrade tox - name: Test run: tox -ve tests + - uses: actions/upload-artifact@v3 + if: '!cancelled()' + with: + name: artifact_${{ set_up_python.python-version }}_tests + path: .results_*/** + # TODO: look into using https://github.com/mikepenz/action-junit-report for a junit report # - name: Upload coverage to Codecov # uses: codecov/codecov-action@v3 # with: From 21985a212d14656d837e26cecc6241a0f2fc8cd4 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 09:18:55 -0700 Subject: [PATCH 08/18] fix: Enable macOS support for the ping command. --- .github/workflows/test-docs.yml | 5 +++++ src/tm_devices/helpers/functions.py | 6 +++--- tests/test_helpers.py | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 4f3f985a..0844327a 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -36,6 +36,11 @@ jobs: python -m pip install --upgrade tox - name: Test run: tox -ve ${{ matrix.tox_env }} + - uses: actions/upload-artifact@v3 + if: '!cancelled()' + with: + name: artifact_${{ matrix.tox_env }} + path: .results_${{ matrix.tox_env }}/** # Check that all jobs passed check-docs-passed: if: always() diff --git a/src/tm_devices/helpers/functions.py b/src/tm_devices/helpers/functions.py index c06ed7a8..ccc6b35a 100644 --- a/src/tm_devices/helpers/functions.py +++ b/src/tm_devices/helpers/functions.py @@ -534,14 +534,14 @@ def _create_ping_command(address: str, timeout: int = 2) -> str: """ validate_address(address) # Create the ping command - if platform.system().lower() == "windows": + if (platform_system := platform.system().lower()) == "windows": count_arg = "-n" timeout_arg = "-w" timeout_val = timeout * 1000 # Windows uses milliseconds else: count_arg = "-c" - timeout_arg = "-w" - timeout_val = timeout # Linux uses seconds + timeout_arg = "-W" if platform_system == "darwin" else "-w" + timeout_val = timeout # Linux/MacOS uses seconds return f"ping {address} {count_arg} 1 {timeout_arg} {timeout_val}" diff --git a/tests/test_helpers.py b/tests/test_helpers.py index e493f7f9..4014508e 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -50,6 +50,8 @@ def test_create_ping_command() -> None: assert _create_ping_command("127.0.0.1") == "ping 127.0.0.1 -n 1 -w 2000" with mock.patch("platform.system", mock.MagicMock(return_value="Linux")): assert _create_ping_command("localhost") == "ping localhost -c 1 -w 2" + with mock.patch("platform.system", mock.MagicMock(return_value="Darwin")): + assert _create_ping_command("localhost") == "ping localhost -c 1 -W 2" # Invalid addresses with pytest.raises( From cf8b2804a6bc94d004584f50ad9e6e503e46688f Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 09:25:24 -0700 Subject: [PATCH 09/18] ci: Update artifact directory. --- .github/workflows/test-code.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index 012aaee2..f211c1ee 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -24,7 +24,6 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 - id: set_up_python with: python-version: ${{ matrix.python-version }} check-latest: true @@ -37,7 +36,7 @@ jobs: - uses: actions/upload-artifact@v3 if: '!cancelled()' with: - name: artifact_${{ set_up_python.python-version }}_tests_and_linting + name: artifact_${{ matrix.os_name }}_${{ matrix.python-version }}_tests_and_linting path: .results_*/** # Quick testing with coverage (no linting) test-fast: @@ -50,7 +49,6 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 - id: set_up_python with: python-version: x # any version check-latest: true @@ -63,7 +61,7 @@ jobs: - uses: actions/upload-artifact@v3 if: '!cancelled()' with: - name: artifact_${{ set_up_python.python-version }}_tests + name: artifact_${{ matrix.os_name }}_tests path: .results_*/** # TODO: look into using https://github.com/mikepenz/action-junit-report for a junit report # - name: Upload coverage to Codecov From ce256537aa510f329edf8b2c2e68e20f63b68a7e Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 09:54:29 -0700 Subject: [PATCH 10/18] test: Change IP address to try to get tests to pass on macOS. --- .github/workflows/test-code.yml | 2 +- tests/sim_devices/devices.yaml | 2 +- tests/test_all_device_drivers.py | 2 +- tests/test_scopes.py | 5 ++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index f211c1ee..03b30f48 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -36,7 +36,7 @@ jobs: - uses: actions/upload-artifact@v3 if: '!cancelled()' with: - name: artifact_${{ matrix.os_name }}_${{ matrix.python-version }}_tests_and_linting + name: artifact_${{ matrix.platform }}_${{ matrix.python-version }}_tests_and_linting path: .results_*/** # Quick testing with coverage (no linting) test-fast: diff --git a/tests/sim_devices/devices.yaml b/tests/sim_devices/devices.yaml index 09aa0d9e..f9b4aae5 100644 --- a/tests/sim_devices/devices.yaml +++ b/tests/sim_devices/devices.yaml @@ -239,7 +239,7 @@ resources: device: dpo7kc filename: scope/dpo7kc.yaml # mso70k - TCPIP::127.0.0.2::INSTR: + TCPIP::127.0.0.1::INSTR: device: mso70k filename: scope/mso70k.yaml TCPIP::MSO70KC-HOSTNAME::INSTR: diff --git a/tests/test_all_device_drivers.py b/tests/test_all_device_drivers.py index d0395f09..40ddf044 100644 --- a/tests/test_all_device_drivers.py +++ b/tests/test_all_device_drivers.py @@ -57,7 +57,7 @@ def test_all_device_drivers( ("SCOPE", "DPO4K-HOSTNAME", None, None, None), ("SCOPE", "DPO4KB-HOSTNAME", None, None, None), ("SCOPE", "192.168.0.101", None, None, None), - ("SCOPE", "127.0.0.2", None, None, None), + ("SCOPE", "127.0.0.1", None, None, None), ("SCOPE", "MSO70KDX-HOSTNAME", None, None, None), ("SMU", "SMU-HOSTNAME", None, None, None), # smu2612b ("SMU", "SMU2450-HOSTNAME", None, None, None), diff --git a/tests/test_scopes.py b/tests/test_scopes.py index 6674db6b..d98fb4a3 100644 --- a/tests/test_scopes.py +++ b/tests/test_scopes.py @@ -262,9 +262,8 @@ def test_tekscope70k(device_manager: DeviceManager, capsys: pytest.CaptureFixtur device_manager: The DeviceManager object. capsys: The captured stdout and stderr. """ - # Assert 7 series device was added and aliased properly - scope = device_manager.add_scope("127.0.0.2") - assert scope.ip_address == "127.0.0.2" + scope = device_manager.add_scope("127.0.0.1") + assert scope.ip_address == "127.0.0.1" assert scope.hostname == "" # Test some generic device functionality assert scope.wait_for_network_connection( From 5b72282a43c70fc6352b54a74eb2d1f25470378e Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 10:53:21 -0700 Subject: [PATCH 11/18] docs: Update link for license badge. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6732072..2907c26c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ pre-commit enabled pre-commit status Documentation status -License: Apache 2.0 +License: Apache 2.0 PyPI: Package status PyPI: Latest release version PyPI: Supported Python versions From 4a31912e85d644f87beb4ca18844b43a9ae18346 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 10:56:30 -0700 Subject: [PATCH 12/18] docs: Update link for license badge. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2907c26c..8e4103c4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ pre-commit enabled pre-commit status Documentation status -License: Apache 2.0 +License: Apache 2.0 PyPI: Package status PyPI: Latest release version PyPI: Supported Python versions From d581074403b8c1e68626f31ce6d5be60b0b48119 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 11:30:42 -0700 Subject: [PATCH 13/18] docs: Add new links for package. --- pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index b7d04c13..6a907ab7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ classifiers = [ "Topic :: System :: Hardware :: Hardware Drivers" ] description = "Manage connections and interactions with Test & Measurement devices." +documentation = "https://tm_devices.readthedocs.io/en/stable/" homepage = "https://pypi.org/project/tm_devices/" keywords = [ "REST API", @@ -72,6 +73,7 @@ maintainers = [ ] name = "tm_devices" readme = "README.md" +repository = "https://github.com/tektronix/tm_devices" version = "0.1.7" [tool.poetry.dependencies] @@ -139,6 +141,10 @@ types-requests = ">=2.28.8" urllib3 = ">=1.26.14" wheel = ">=0.37.1" +[tool.poetry.urls] +"Bug Tracker" = "https://github.com/tektronix/tm_devices/issues" +"Changelog" = "https://tm_devices.readthedocs.io/en/stable/CHANGELOG.html" + [tool.pylint.basic] good-names = ["_"] From 06edfe90b5fbbe75ff0417f099456eaa80a3e4ed Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 13:10:44 -0700 Subject: [PATCH 14/18] test: Update some tests. --- tests/test_docs.py | 1 + tests/test_helpers.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_docs.py b/tests/test_docs.py index 4a64b3d6..47931d9f 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -35,6 +35,7 @@ def _use_docs_directory() -> Generator[None, None, None]: # pyright: ignore [re class TestDocs: # pylint: disable=no-self-use """A collection of documentation tests.""" + @pytest.mark.xfail(reason="tm_devices GitHub links don't work currently") @pytest.mark.order(1) def test_docs_linkcheck(self) -> None: """Run the linkcheck test for the documentation.""" diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 4014508e..27faa6ad 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -43,7 +43,7 @@ def test_create_ping_command() -> None: """Test the creation of the ping command.""" - # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,import-private-name,useless-suppression from tm_devices.helpers.functions import _create_ping_command with mock.patch("platform.system", mock.MagicMock(return_value="Windows")): From 03ba02d1f2368c4bd5e79b38c693f92887f6b18e Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 13:30:14 -0700 Subject: [PATCH 15/18] ci: Update runner used for doc tests. --- .github/workflows/test-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 0844327a..df36a6d5 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -14,7 +14,7 @@ concurrency: jobs: # Test building the docs (html, linkcheck, doctest, coverage) test-docs: - runs-on: ubuntu-latest + runs-on: ubuntu-latest-16-cores strategy: fail-fast: false matrix: From 5158b8b11dd29f4ccf08862872ece68e538d0f49 Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 3 Aug 2023 13:33:02 -0700 Subject: [PATCH 16/18] ci: revert runner --- .github/workflows/test-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index df36a6d5..0844327a 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -14,7 +14,7 @@ concurrency: jobs: # Test building the docs (html, linkcheck, doctest, coverage) test-docs: - runs-on: ubuntu-latest-16-cores + runs-on: ubuntu-latest strategy: fail-fast: false matrix: From 61e308dadae00e3d52c915d8e7882366f0b65b8d Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Wed, 9 Aug 2023 16:31:21 -0700 Subject: [PATCH 17/18] refactor: Added new driver. Added docs on unit tests. --- .pre-commit-config.yaml | 6 +- CONTRIBUTING.md | 4 +- docs/conf.py | 5 +- docs/contributing/add_driver_methods.md | 17 ++--- docs/contributing/add_new_driver.md | 6 +- docs/contributing/index.md | 1 + docs/contributing/unit_tests.md | 62 +++++++++++++++++++ docs/index.md | 2 +- pyproject.toml | 2 +- .../commands/_helpers/generic_commands.py | 2 +- src/tm_devices/device_manager.py | 13 ++-- src/tm_devices/drivers/__init__.py | 3 + .../drivers/pi/scopes/tekscope/tekscope.py | 7 +++ .../pi/signal_sources/awgs/__init__.py | 2 + .../drivers/pi/signal_sources/awgs/awg5kb.py | 6 ++ .../drivers/pi/signal_sources/awgs/awg5kc.py | 4 +- src/tm_devices/helpers/alias_dict.py | 4 ++ src/tm_devices/helpers/enums.py | 4 ++ tests/sim_devices/awg/awg5kb.yaml | 46 ++++++++++++++ tests/sim_devices/devices.yaml | 3 + tests/sim_devices/scope/lpd6.yaml | 8 +++ tests/sim_devices/scope/mso2.yaml | 7 +++ tests/sim_devices/scope/mso4.yaml | 8 +++ tests/sim_devices/scope/mso5.yaml | 7 +++ tests/sim_devices/scope/mso5b.yaml | 8 +++ tests/sim_devices/scope/mso5lp.yaml | 8 +++ tests/sim_devices/scope/mso6.yaml | 8 +++ tests/sim_devices/scope/mso6b.yaml | 8 +++ tests/test_all_device_drivers.py | 1 + tests/test_helpers.py | 1 + 30 files changed, 236 insertions(+), 27 deletions(-) create mode 100644 docs/contributing/unit_tests.md create mode 100644 src/tm_devices/drivers/pi/signal_sources/awgs/awg5kb.py create mode 100644 tests/sim_devices/awg/awg5kb.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6dfb11fe..6b248053 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,12 +22,12 @@ repos: - id: pretty-format-json args: [--autofix, --indent=4] - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.1 + rev: v1.5.3 hooks: - id: remove-tabs - id: forbid-tabs - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.23.3 + rev: 0.24.0 hooks: - id: check-readthedocs - id: check-dependabot @@ -112,7 +112,7 @@ repos: always_run: true args: [., --min=10] - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.282 + rev: v0.0.283 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79c55b3f..1219d703 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,13 +118,13 @@ recommended IDE for package development is ```` - To run full static code analysis, tests, and documentation validation - (running this prior to opening a pull request is highly recommended, but it is very slow): + (running this prior to opening a pull request is highly recommended, but it is **very slow**): ```console tox -p ``` - - To run just the tests and static code analysis (much quicker): + - To run just the tests and static code analysis (**much quicker**): ```console tox -p -m basic diff --git a/docs/conf.py b/docs/conf.py index b98d396a..454cba79 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -69,7 +69,7 @@ extlinks_detect_hardcoded_links = True extlinks = { "repo_url": ( - ("https://github.com/tektronix/tm_devices/blob/main/%s"), + "https://github.com/tektronix/tm_devices/blob/main/%s", "%s", ) } @@ -170,6 +170,9 @@ def prep_jinja_env(jinja_env: JinjaEnvironment) -> None: "https://pyvisa.readthedocs.io/projects/pyvisa-py/en/latest/", "https://pyvisa.readthedocs.io/en/latest/", "https://python-semantic-release.readthedocs.io/en/latest/", + "https://docs.pytest.org/en/latest/", + "https://pytest-cov.readthedocs.io/en/latest/", + "https://pyvisa.readthedocs.io/projects/pyvisa-sim/en/latest/", ] tippy_anchor_parent_selector = "div.document" diff --git a/docs/contributing/add_driver_methods.md b/docs/contributing/add_driver_methods.md index 65d71e20..e62142d0 100644 --- a/docs/contributing/add_driver_methods.md +++ b/docs/contributing/add_driver_methods.md @@ -8,21 +8,24 @@ device drivers. Because of the inheritance structure of the device drivers (see the [architecture diagrams](../advanced/architecture.md#main-device-types)), new methods should be added to the highest applicable class in the tree. All methods -for each type of device (Scope, AFG, SMU, etc.) need to be defined in that -device type's abstract class, or higher up the tree, to enable accurate type -hinting for each different device type tree. Unless the implementation is the -same for all subclasses of that device type, the abstract class's implementation -should simply `raise NotImplementedError`. +for each family of device (TekScope, SMU2600, PSU2200, etc.) need to be defined in that +device family's abstract class, or higher up the tree, to enable accurate type +hinting for each different device family tree. Unless the implementation is the +same for all subclasses of that device family, the abstract class's implementation +should be decorated as an `@abstractmethod`. ## New method addition example ```python +from abc import abstractmethod + + # scope.py # Abstract class class Scope(...): + @abstractmethod def new_method(self): - # Abstract class raises an error. - raise NotImplementedError + """Abstract class raises an error.""" # tekscope.py diff --git a/docs/contributing/add_new_driver.md b/docs/contributing/add_new_driver.md index d3842032..b4ecd80b 100644 --- a/docs/contributing/add_new_driver.md +++ b/docs/contributing/add_new_driver.md @@ -10,8 +10,8 @@ This guide will walk through the steps needed to add a new device driver. [add a new device type](./add_new_device_type.md) subpackage 02. Create the new device driver python file and class that inherits the appropriate device type/series base class - 1. If the new device(s) are part of a series, add a new series subpackage - for theme (e.g. `power_supplies/psu2200/`) + 1. If the new device(s) are part of a series (also referred to as a family), + add a new series subpackage for them (e.g. `power_supplies/psu2200/`) 2. Create the device driver python file, create a class that inherits from the abstracted device type (or series) base class, see [example](#example-of-adding-a-new-device-series-parent-driver-class). @@ -63,7 +63,7 @@ from tm_devices.drivers.pi.power_supplies.power_supply import PowerSupplyUnit from tm_devices.drivers.device import family_base_class -@family_base_class +@family_base_class # Mark the base class for the new family of devices class BaseFancyPSU(PowerSupplyUnit, ABC): """Base Fancy PSU device driver.""" diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 77972753..874d927b 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -20,4 +20,5 @@ maxdepth: 1 add_driver_methods.md add_new_driver.md add_new_device_type.md +unit_tests.md ``` diff --git a/docs/contributing/unit_tests.md b/docs/contributing/unit_tests.md new file mode 100644 index 00000000..98de4e6a --- /dev/null +++ b/docs/contributing/unit_tests.md @@ -0,0 +1,62 @@ +# Creating & Updating Unit Tests + +This guide will walk through details needed when updating existing unit tests or creating new ones. + +The tests for `tm_devices` are located in the {repo_url}`tests` folder. + +## Test Style & Standards + +The `tm_devices` package uses the [pytest](https://docs.pytest.org/en/latest/) package +for testing and enforces 100% code coverage through the +[pytest-cov](https://pytest-cov.readthedocs.io/en/latest/readme.html) plugin. + +All tests must conform to the same coding standards as the rest of the `tm_devices` +package, and are subject to the same static code analysis requirements. + +## Testing First Steps + +When adding or modifying source code: + +1. Search through the codebase to find usages of the code being worked on. +2. Determine if the existing tests should be modified or if new tests should be created. + +## Testing Details + +### `DeviceManager` fixture + +There is a session-scoped +[pytest fixture](https://docs.pytest.org/en/latest/explanation/fixtures.html), +`device_manager`, that provides access to simulated VISA devices throughout the entire test run. +This fixture is defined in the {repo_url}`tests/conftest.py` file and returns a +{py:obj}`DeviceManager ` instance which can be used by any test that +needs to test device driver behavior. + +### Simulated VISA devices + +The unit tests make use of simulated devices to fully test each device driver. +These simulated devices are created using the +[pyvisa-sim](https://pyvisa.readthedocs.io/projects/pyvisa-sim/en/latest/) +package which has a schema for defining simulated devices. + +The simulated devices primarily consist of error handling definitions and +defined commands and optional responses. In addition to these basic building blocks, +the simulated devices can also contain settable properties, see the +[pyvisa-sim docs](https://pyvisa.readthedocs.io/projects/pyvisa-sim/en/latest/definitions.html) +and the existing simulated devices for more details and examples. + +The simulated devices used during testing are located in the +{repo_url}`tests/sim_devices` folder, organized in sub-folders by device type. +The devices that are available for VISA connections during test runs are +defined in the {repo_url}`tests/sim_devices/devices.yaml` file, under +the `resources` key. + +- In either of the following two scenarios, reference the + [pyvisa-sim simulated instrument definition docs](https://pyvisa.readthedocs.io/projects/pyvisa-sim/en/latest/definitions.html) + for details on how the simulated instruments are defined. + 1. If a new feature or driver update introduces any new commands to existing + drivers: + - The simulation definition files for the affected devices will need to be updated. + 2. If a new device driver is added to `tm_devices`: + - A new simulation definition file for the new device will need to be added and the + master `resources` list will need the new driver added, see the walkthrough for + [adding a new device driver](./add_new_driver.md). diff --git a/docs/index.md b/docs/index.md index d7c636d0..a5a0e25a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,10 +11,10 @@ basic_usage.md configuration.md CHANGELOG.md advanced/index.md -contributing/index.md troubleshooting/index.md glossary.md CODE_OF_CONDUCT.md +contributing/index.md LICENSE.md _autoapi/index ``` diff --git a/pyproject.toml b/pyproject.toml index 6a907ab7..277bb0fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ maintainers = [ name = "tm_devices" readme = "README.md" repository = "https://github.com/tektronix/tm_devices" -version = "0.1.7" +version = "0.1.8" [tool.poetry.dependencies] check4updates = ">=0.0.2" diff --git a/src/tm_devices/commands/_helpers/generic_commands.py b/src/tm_devices/commands/_helpers/generic_commands.py index c99a0367..01819187 100644 --- a/src/tm_devices/commands/_helpers/generic_commands.py +++ b/src/tm_devices/commands/_helpers/generic_commands.py @@ -80,7 +80,7 @@ def __init__(self, device: Optional["Device"], cmd_syntax: str) -> None: self._cmd_syntax = cmd_syntax self._device = device - def __eq__(self, other: Any) -> bool: + def __eq__(self, other: object) -> bool: """Compare equality by comparing the syntax of two commands.""" if not isinstance(other, BaseCmd): return NotImplemented diff --git a/src/tm_devices/device_manager.py b/src/tm_devices/device_manager.py index 7a061c7d..d11fe994 100644 --- a/src/tm_devices/device_manager.py +++ b/src/tm_devices/device_manager.py @@ -19,6 +19,7 @@ AFG3KC, AFG31K, AWG5K, + AWG5KB, AWG5KC, AWG7K, AWG7KC, @@ -139,16 +140,16 @@ if TYPE_CHECKING: from pyvisa.resources import MessageBasedResource - from typing_extensions import TypeAlias + from typing_extensions import Self, TypeAlias from tm_devices.drivers.device import Device #################################################################################################### # Type Aliases #################################################################################################### -# TODO: this is temporary until python3.12 which will support typvar with defaults +# TODO: this is temporary until python3.12 which will support TypeVar with defaults AFGAlias: TypeAlias = Union[AFG3K, AFG3KB, AFG3KC, AFG31K] -AWGAlias: TypeAlias = Union[AWG5K, AWG5KC, AWG7K, AWG7KC, AWG5200, AWG70KA, AWG70KB] +AWGAlias: TypeAlias = Union[AWG5K, AWG5KB, AWG5KC, AWG7K, AWG7KC, AWG5200, AWG70KA, AWG70KB] DataAcquisitionSystemAlias: TypeAlias = Union[DAQ6510] # pyright: ignore DigitalMultimeterAlias: TypeAlias = Union[DMM6500, DMM7510, DMM7512] ScopeAlias: TypeAlias = Union[ @@ -296,7 +297,7 @@ def __del__(self) -> None: if self.__is_open: self.close() - def __enter__(self) -> DeviceManager: + def __enter__(self) -> Self: """Provide access to the DeviceManager class instance. This and the __exit__ method allow this class to be used as a Context Manager. @@ -307,8 +308,8 @@ def __enter__(self) -> DeviceManager: def __exit__( self, - exc_type: Optional[Type[Exception]], - exc_val: Optional[Exception], + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: """Handle exiting the context by closing down the DeviceManager. diff --git a/src/tm_devices/drivers/__init__.py b/src/tm_devices/drivers/__init__.py index 11925888..e4b3acc7 100644 --- a/src/tm_devices/drivers/__init__.py +++ b/src/tm_devices/drivers/__init__.py @@ -61,6 +61,7 @@ from tm_devices.drivers.pi.signal_sources.afgs.afg3kc import AFG3KC from tm_devices.drivers.pi.signal_sources.afgs.afg31k import AFG31K from tm_devices.drivers.pi.signal_sources.awgs.awg5k import AWG5K +from tm_devices.drivers.pi.signal_sources.awgs.awg5kb import AWG5KB from tm_devices.drivers.pi.signal_sources.awgs.awg5kc import AWG5KC from tm_devices.drivers.pi.signal_sources.awgs.awg7k import AWG7K from tm_devices.drivers.pi.signal_sources.awgs.awg7kc import AWG7KC @@ -112,6 +113,7 @@ # AWGs SupportedModels.AWG5200.value: AWG5200, SupportedModels.AWG5K.value: AWG5K, + SupportedModels.AWG5KB.value: AWG5KB, SupportedModels.AWG5KC.value: AWG5KC, SupportedModels.AWG7K.value: AWG7K, SupportedModels.AWG7KC.value: AWG7KC, @@ -227,6 +229,7 @@ "AFG31K", "AWG5200", "AWG5K", + "AWG5KB", "AWG5KC", "AWG7K", "AWG7KC", diff --git a/src/tm_devices/drivers/pi/scopes/tekscope/tekscope.py b/src/tm_devices/drivers/pi/scopes/tekscope/tekscope.py index 0dd1e9c2..d80489f5 100644 --- a/src/tm_devices/drivers/pi/scopes/tekscope/tekscope.py +++ b/src/tm_devices/drivers/pi/scopes/tekscope/tekscope.py @@ -130,6 +130,10 @@ def channel(self) -> "MappingProxyType[str, TekScopeChannel]": with self.temporary_verbose(False) and self.temporary_visa_timeout( 500 if not bool(os.environ.get("TM_DEVICES_UNIT_TESTS_RUNNING")) else UNIT_TEST_TIMEOUT ): + # Set scope PI to be verbose + old_pi_verbosity = self.query(":VERBose?") + self.set_and_check(":VERBose", 1) + # CH1, CH2, ..., CH[, DCH] for channel in self.all_channel_names_list: try: @@ -161,6 +165,9 @@ def channel(self) -> "MappingProxyType[str, TekScopeChannel]": raise AssertionError(msg) # create the probe dataclass channel_map[channel] = TekScopeChannel(name=channel, probe=probe) + + # Set scope PI verbosity back to previous value + self.set_and_check(":VERBose", old_pi_verbosity) return MappingProxyType(channel_map) @property diff --git a/src/tm_devices/drivers/pi/signal_sources/awgs/__init__.py b/src/tm_devices/drivers/pi/signal_sources/awgs/__init__.py index 860dd59d..7a8655a5 100644 --- a/src/tm_devices/drivers/pi/signal_sources/awgs/__init__.py +++ b/src/tm_devices/drivers/pi/signal_sources/awgs/__init__.py @@ -1,6 +1,7 @@ """AWG package init file.""" from tm_devices.drivers.pi.signal_sources.awgs.awg import AWG from tm_devices.drivers.pi.signal_sources.awgs.awg5k import AWG5K +from tm_devices.drivers.pi.signal_sources.awgs.awg5kb import AWG5KB from tm_devices.drivers.pi.signal_sources.awgs.awg5kc import AWG5KC from tm_devices.drivers.pi.signal_sources.awgs.awg7k import AWG7K from tm_devices.drivers.pi.signal_sources.awgs.awg7kc import AWG7KC @@ -12,6 +13,7 @@ "AWG", "AWG5200", "AWG5K", + "AWG5KB", "AWG5KC", "AWG7K", "AWG7KC", diff --git a/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kb.py b/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kb.py new file mode 100644 index 00000000..cbbc5dcd --- /dev/null +++ b/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kb.py @@ -0,0 +1,6 @@ +"""AWG5KB device driver module.""" +from tm_devices.drivers.pi.signal_sources.awgs.awg5k import AWG5K + + +class AWG5KB(AWG5K): + """AWG5KB device driver.""" diff --git a/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kc.py b/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kc.py index 300e156d..528fd60e 100644 --- a/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kc.py +++ b/src/tm_devices/drivers/pi/signal_sources/awgs/awg5kc.py @@ -1,7 +1,7 @@ """AWG5KC device driver module.""" from tm_devices.commands import AWG5KCMixin -from tm_devices.drivers.pi.signal_sources.awgs.awg5k import AWG5K +from tm_devices.drivers.pi.signal_sources.awgs.awg5kb import AWG5KB -class AWG5KC(AWG5KCMixin, AWG5K): +class AWG5KC(AWG5KCMixin, AWG5KB): """AWG5KC device driver.""" diff --git a/src/tm_devices/helpers/alias_dict.py b/src/tm_devices/helpers/alias_dict.py index 7c4ea1dd..a69c23e3 100644 --- a/src/tm_devices/helpers/alias_dict.py +++ b/src/tm_devices/helpers/alias_dict.py @@ -99,3 +99,7 @@ def __setitem__(self, key: Any, value: Any) -> None: break # this skips over the else clause else: super().__setitem__(key, value) + + def __len__(self) -> int: # pylint: disable=useless-parent-delegation + """Return the length of the dictionary.""" + return super().__len__() diff --git a/src/tm_devices/helpers/enums.py b/src/tm_devices/helpers/enums.py index 5c9afad5..b0eb4cd8 100644 --- a/src/tm_devices/helpers/enums.py +++ b/src/tm_devices/helpers/enums.py @@ -97,6 +97,7 @@ class SupportedModels(CustomStrEnum): # AWGs AWG5200 = "AWG5200" AWG5K = "AWG5K" + AWG5KB = "AWG5KB" AWG5KC = "AWG5KC" AWG7K = "AWG7K" AWG7KC = "AWG7KC" @@ -216,6 +217,7 @@ class SignalSourceFunctionsAWG(SignalSourceFunctionBase): SIN = "Sine" SQUARE = "Square" RAMP = "Ramp" + TRIANGLE = "Triangle" CLOCK = "Clock" DC = "DC" @@ -235,6 +237,7 @@ class SignalSourceFunctionsAFG(SignalSourceFunctionBase): ERISE = "ERIS" EDECAY = "EDEC" HAVERSINE = "HAV" + ARBITRARY = "ARB" class SignalSourceFunctionsIAFG(SignalSourceFunctionBase): @@ -252,4 +255,5 @@ class SignalSourceFunctionsIAFG(SignalSourceFunctionBase): EDECAY = "EDECAY" HAVERSINE = "HAVERSINE" CARDIAC = "CARDIAC" + NOISE = "NOISE" ARBITRARY = "ARBITRARY" diff --git a/tests/sim_devices/awg/awg5kb.yaml b/tests/sim_devices/awg/awg5kb.yaml new file mode 100644 index 00000000..7e1a4bc6 --- /dev/null +++ b/tests/sim_devices/awg/awg5kb.yaml @@ -0,0 +1,46 @@ +--- +spec: '1.1' +devices: + awg5012b: + eom: + USB INSTR: + q: "\n" + r: "\n" + TCPIP INSTR: + q: "\n" + r: "\n" + TCPIP SOCKET: + q: "\n" + r: "\n" + dialogues: + - q: '*IDN?' + r: TEKTRONIX,AWG5012B,SERIAL1,FV:6.3.0080.0 + - q: '*OPC' + - q: '*OPC?' + r: '1' + - q: '*RST' + - q: '*CLS' + - q: AWGControl:CONFigure:CNUMber? + r: '2' + - q: 'MMEMory:IMPort ' + error: + status_register: + - q: '*ESR?' + command_error: 32 + query_error: 4 + error_queue: + - q: SYSTEM:ERROR? + default: 0,"No error" + command_error: 1, "Command error" + properties: + sre: + default: 0 + getter: + q: '*SRE?' + r: '{:d}' + setter: + q: '*SRE {:d}' + specs: + min: 0 + max: 255 + type: int diff --git a/tests/sim_devices/devices.yaml b/tests/sim_devices/devices.yaml index f9b4aae5..119b156f 100644 --- a/tests/sim_devices/devices.yaml +++ b/tests/sim_devices/devices.yaml @@ -95,6 +95,9 @@ resources: TCPIP::AWG5K-HOSTNAME::INSTR: device: awg5012 filename: awg/awg5k.yaml + TCPIP::AWG5KB-HOSTNAME::INSTR: + device: awg5012b + filename: awg/awg5kb.yaml TCPIP::AWG5KC-HOSTNAME::INSTR: device: awg5012c filename: awg/awg5kc.yaml diff --git a/tests/sim_devices/scope/lpd6.yaml b/tests/sim_devices/scope/lpd6.yaml index a9030aac..91788eaf 100644 --- a/tests/sim_devices/scope/lpd6.yaml +++ b/tests/sim_devices/scope/lpd6.yaml @@ -42,3 +42,11 @@ devices: - q: :ALLev? default: 0,"No events to report - queue empty" command_error: 113,"Undefined header; Command not found; EXAMPLE_COMMAND" + properties: + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} diff --git a/tests/sim_devices/scope/mso2.yaml b/tests/sim_devices/scope/mso2.yaml index 963f4b16..56297a44 100644 --- a/tests/sim_devices/scope/mso2.yaml +++ b/tests/sim_devices/scope/mso2.yaml @@ -63,6 +63,13 @@ devices: min: 0 max: 255 type: int + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} chan_1_state: default: '1' getter: diff --git a/tests/sim_devices/scope/mso4.yaml b/tests/sim_devices/scope/mso4.yaml index 9069863c..51da6020 100644 --- a/tests/sim_devices/scope/mso4.yaml +++ b/tests/sim_devices/scope/mso4.yaml @@ -42,3 +42,11 @@ devices: - q: :ALLev? default: 0,"No events to report - queue empty" command_error: 113,"Undefined header; Command not found; EXAMPLE_COMMAND" + properties: + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} diff --git a/tests/sim_devices/scope/mso5.yaml b/tests/sim_devices/scope/mso5.yaml index f8588676..f6d436fd 100644 --- a/tests/sim_devices/scope/mso5.yaml +++ b/tests/sim_devices/scope/mso5.yaml @@ -90,6 +90,13 @@ devices: min: 0 max: 255 type: int + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} afg_burst_cnt: default: '1' getter: diff --git a/tests/sim_devices/scope/mso5b.yaml b/tests/sim_devices/scope/mso5b.yaml index 09e4dfd3..08992178 100644 --- a/tests/sim_devices/scope/mso5b.yaml +++ b/tests/sim_devices/scope/mso5b.yaml @@ -42,3 +42,11 @@ devices: - q: :ALLev? default: 0,"No events to report - queue empty" command_error: 113,"Undefined header; Command not found; EXAMPLE_COMMAND" + properties: + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} diff --git a/tests/sim_devices/scope/mso5lp.yaml b/tests/sim_devices/scope/mso5lp.yaml index 78806fca..73a230b5 100644 --- a/tests/sim_devices/scope/mso5lp.yaml +++ b/tests/sim_devices/scope/mso5lp.yaml @@ -42,3 +42,11 @@ devices: - q: :ALLev? default: 0,"No events to report - queue empty" command_error: 113,"Undefined header; Command not found; EXAMPLE_COMMAND" + properties: + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} diff --git a/tests/sim_devices/scope/mso6.yaml b/tests/sim_devices/scope/mso6.yaml index c73e780a..e6d102a8 100644 --- a/tests/sim_devices/scope/mso6.yaml +++ b/tests/sim_devices/scope/mso6.yaml @@ -42,3 +42,11 @@ devices: - q: :ALLev? default: 0,"No events to report - queue empty" command_error: 113,"Undefined header; Command not found; EXAMPLE_COMMAND" + properties: + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} diff --git a/tests/sim_devices/scope/mso6b.yaml b/tests/sim_devices/scope/mso6b.yaml index aff92ee3..fa2f2495 100644 --- a/tests/sim_devices/scope/mso6b.yaml +++ b/tests/sim_devices/scope/mso6b.yaml @@ -42,3 +42,11 @@ devices: - q: :ALLev? default: 0,"No events to report - queue empty" command_error: 113,"Undefined header; Command not found; EXAMPLE_COMMAND" + properties: + verbosity: + default: 0 + getter: + q: :VERBose? + r: '{:s}' + setter: + q: :VERBose {:s} diff --git a/tests/test_all_device_drivers.py b/tests/test_all_device_drivers.py index 40ddf044..b1db374b 100644 --- a/tests/test_all_device_drivers.py +++ b/tests/test_all_device_drivers.py @@ -29,6 +29,7 @@ def test_all_device_drivers( ("AWG", "AWG7K-HOSTNAME", None, None, None), ("AWG", "AWG7KC-HOSTNAME", None, None, None), ("AWG", "AWG5KC-HOSTNAME", None, None, None), + ("AWG", "AWG5KB-HOSTNAME", None, None, None), ("AWG", "AWG70KB-HOSTNAME", None, None, None), ("AWG", "AWG70KA-HOSTNAME", None, None, None), ("SCOPE", "MSO22-HOSTNAME", None, None, None), diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 27faa6ad..61742f0f 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -74,6 +74,7 @@ def test_create_ping_command() -> None: ("MSO70604", "MSO70K"), ("AWG5204", "AWG5200"), ("AWG5012C", "AWG5KC"), + ("AWG5012B", "AWG5KB"), ("AWG5012", "AWG5K"), ("AWG70002B", "AWG70KB"), ("AFG3252", "AFG3K"), From 84ad165e5f4da6924a1eb89f8c4b86f43186dd1e Mon Sep 17 00:00:00 2001 From: Nicholas Felt Date: Thu, 17 Aug 2023 17:24:07 -0700 Subject: [PATCH 18/18] refactor: Added to troubleshooting guide. Update linting noqa comments. --- .pre-commit-config.yaml | 8 +- docs/troubleshooting/contributions.md | 98 +++++++++++++++++++ src/tm_devices/drivers/device.py | 2 +- .../data_acquisition_system.py | 2 +- .../digital_multimeters/digital_multimeter.py | 2 +- src/tm_devices/drivers/pi/pi_device.py | 6 +- .../pi/power_supplies/psu2200/psu2200.py | 2 +- src/tm_devices/drivers/pi/scopes/scope.py | 4 +- .../pi/scopes/tekscope_2k/tekscope_2k.py | 2 +- .../tekscope_5k_7k_70k/tekscope_5k_7k_70k.py | 2 +- src/tm_devices/drivers/pi/scopes/tso/tsovu.py | 2 +- .../drivers/pi/signal_sources/awgs/awg.py | 2 +- .../smu2400/smu2400_interactive.py | 2 +- .../smu2400/smu2400_standard.py | 2 +- .../source_measure_units/smu2600/smu2600.py | 2 +- .../source_measure_units/smu6000/smu6000.py | 2 +- .../drivers/pi/systems_switches/ss3706a.py | 2 +- 17 files changed, 120 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6b248053..4e52c449 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,12 +22,12 @@ repos: - id: pretty-format-json args: [--autofix, --indent=4] - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.3 + rev: v1.5.4 hooks: - id: remove-tabs - id: forbid-tabs - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.24.0 + rev: 0.24.1 hooks: - id: check-readthedocs - id: check-dependabot @@ -39,7 +39,7 @@ repos: - id: commitizen stages: [commit-msg] - repo: https://github.com/asottile/blacken-docs - rev: 1.15.0 + rev: 1.16.0 hooks: - id: blacken-docs - repo: https://github.com/lyz-code/yamlfix/ @@ -112,7 +112,7 @@ repos: always_run: true args: [., --min=10] - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.283 + rev: v0.0.285 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/docs/troubleshooting/contributions.md b/docs/troubleshooting/contributions.md index 32a3184b..6db7b00e 100644 --- a/docs/troubleshooting/contributions.md +++ b/docs/troubleshooting/contributions.md @@ -125,3 +125,101 @@ proper development dependencies installed. See the [contributing guide](../CONTRIBUTING.md) for details on how to properly set up and test changes using a virtual environment. + +______________________________________________________________________ + +## Executable not found during `pre-commit` + +Pre-commit is failing with "Executable not found" errors. + +### Problem: + +When running pre-commit, in either an Integrated Development Environment (IDE) or through +the command line, the virtual environment must be used so that all necessary +executables can be found. + +`tm_devices` uses a few [local pre-commit hooks](https://pre-commit.com/#repository-local-hooks), +so if the environment is not correctly enabled, those hooks will fail. + +```console +pre-commit run --all +check yaml...............................................................Passed +check toml...............................................................Passed +check json...............................................................Passed +fix requirements.txt.....................................................Passed +trim trailing whitespace.................................................Passed +fix end of files.........................................................Passed +check for case conflicts.................................................Passed +check for merge conflicts................................................Passed +check for added large files..............................................Passed +forbid new submodules................................(no files to check)Skipped +pretty format json.......................................................Passed +Tabs remover.............................................................Passed +No-tabs checker..........................................................Passed +Validate ReadTheDocs Config..............................................Passed +Validate Dependabot Config (v2)..........................................Passed +Validate GitHub Actions..............................(no files to check)Skipped +Validate GitHub Workflows................................................Passed +blacken-docs.............................................................Passed +yamlfix..................................................................Passed +mdformat.................................................................Passed +Poetry check.............................................................Failed +- hook id: check-poetry +- exit code: 1 + +Executable `poetry` not found + +toml-sort................................................................Failed +- hook id: toml-sort +- exit code: 1 + +Executable `toml-sort` not found + +pylint...................................................................Failed +- hook id: pylint +- exit code: 1 + +Executable `pylint` not found + +pyright..................................................................Failed +- hook id: pyright +- exit code: 1 + +Executable `pyright` not found + +pyright-verifytypes......................................................Failed +- hook id: pyright-verifytypes +- exit code: 1 + +Executable `pyright` not found + +pyroma...................................................................Failed +- hook id: pyroma +- exit code: 1 + +Executable `pyroma` not found + +ruff.....................................................................Passed +black....................................................................Passed +docformatter.............................................................Passed +``` + +### Solution: + +In order to fix this issue, first activate the virtual environment +(or set your IDE to use the correct Python interpreter for pre-commit hooks), +then update the installed dependencies, +then retry the command. + +```console +# Linux +source .env/bin/activate + +# Windows +.env\Scripts\activate.bat + +# Update installed dependencies +python -m poetry update + +# Re-run original, failing command +``` diff --git a/src/tm_devices/drivers/device.py b/src/tm_devices/drivers/device.py index 838424e0..9b19a6ca 100644 --- a/src/tm_devices/drivers/device.py +++ b/src/tm_devices/drivers/device.py @@ -153,7 +153,7 @@ def _open(self) -> bool: @abstractmethod def _reboot(self) -> None: """Perform the actual rebooting code.""" - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``._reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py b/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py index 79793adb..9ad0eb0d 100644 --- a/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py +++ b/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py @@ -24,7 +24,7 @@ def _reboot(self) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py b/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py index f54ab08b..18c56247 100644 --- a/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py +++ b/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py @@ -30,7 +30,7 @@ def _reboot(self) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/pi_device.py b/src/tm_devices/drivers/pi/pi_device.py index ef8bc93f..ccbe8282 100644 --- a/src/tm_devices/drivers/pi/pi_device.py +++ b/src/tm_devices/drivers/pi/pi_device.py @@ -121,7 +121,7 @@ def turn_channel_off(self, channel_str: str) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement for all driver subclasses then remove this blanket NotImplementedError - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -136,7 +136,7 @@ def turn_channel_on(self, channel_str: str) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement for all driver subclasses then remove this blanket NotImplementedError - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -862,7 +862,7 @@ def _open(self) -> bool: # If it does, it most certainly did not reboot. opened = False break - except ConnectionError: # noqa: PERF203 + except ConnectionError: # raised by the create_visa_connection() function pass diff --git a/src/tm_devices/drivers/pi/power_supplies/psu2200/psu2200.py b/src/tm_devices/drivers/pi/power_supplies/psu2200/psu2200.py index ffd0c5a2..4c60dd19 100644 --- a/src/tm_devices/drivers/pi/power_supplies/psu2200/psu2200.py +++ b/src/tm_devices/drivers/pi/power_supplies/psu2200/psu2200.py @@ -49,6 +49,6 @@ def fpga_version(self) -> Version: def _reboot(self) -> None: """Perform the actual rebooting code.""" # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/scopes/scope.py b/src/tm_devices/drivers/pi/scopes/scope.py index 60e04076..10120943 100644 --- a/src/tm_devices/drivers/pi/scopes/scope.py +++ b/src/tm_devices/drivers/pi/scopes/scope.py @@ -23,7 +23,7 @@ def single_sequence(self) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement for all driver subclasses then convert to abstractmethod - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -55,7 +55,7 @@ def curve_query( Raises: NotImplementedError: Indicates the current driver has not implemented this method. """ - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/scopes/tekscope_2k/tekscope_2k.py b/src/tm_devices/drivers/pi/scopes/tekscope_2k/tekscope_2k.py index 4310d4e5..37690fb0 100644 --- a/src/tm_devices/drivers/pi/scopes/tekscope_2k/tekscope_2k.py +++ b/src/tm_devices/drivers/pi/scopes/tekscope_2k/tekscope_2k.py @@ -27,6 +27,6 @@ class TekScope2k(Scope, ABC): def _reboot(self) -> None: """Perform the actual rebooting code.""" # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/scopes/tekscope_5k_7k_70k/tekscope_5k_7k_70k.py b/src/tm_devices/drivers/pi/scopes/tekscope_5k_7k_70k/tekscope_5k_7k_70k.py index 05dfb204..95c72120 100644 --- a/src/tm_devices/drivers/pi/scopes/tekscope_5k_7k_70k/tekscope_5k_7k_70k.py +++ b/src/tm_devices/drivers/pi/scopes/tekscope_5k_7k_70k/tekscope_5k_7k_70k.py @@ -27,6 +27,6 @@ class TekScope5k7k70k(Scope, ABC): def _reboot(self) -> None: """Perform the actual rebooting code.""" # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/scopes/tso/tsovu.py b/src/tm_devices/drivers/pi/scopes/tso/tsovu.py index 183cc9b5..563648d7 100644 --- a/src/tm_devices/drivers/pi/scopes/tso/tsovu.py +++ b/src/tm_devices/drivers/pi/scopes/tso/tsovu.py @@ -41,7 +41,7 @@ def _reboot(self) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py b/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py index fb4de002..58e62164 100644 --- a/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py +++ b/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py @@ -93,7 +93,7 @@ def generate_waveform( # noqa: PLR0913 # pyright: ignore[reportIncompatibleMet NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py index 3dda530e..9ee6c913 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py @@ -75,6 +75,6 @@ def get_eventlog_status(self) -> Tuple[bool, str]: def _reboot(self) -> None: """Perform the actual rebooting code.""" # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py index 8b08931f..5eadb1d2 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py @@ -132,6 +132,6 @@ def load_script( def _reboot(self) -> None: """Perform the actual rebooting code.""" # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu2600/smu2600.py b/src/tm_devices/drivers/pi/source_measure_units/smu2600/smu2600.py index 46948a94..de012b8a 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu2600/smu2600.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu2600/smu2600.py @@ -94,6 +94,6 @@ def get_eventlog_status(self) -> Tuple[bool, str]: def _reboot(self) -> None: """Perform the actual rebooting code.""" # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.reboot()`` is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py b/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py index 035fb88e..24477eb9 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py @@ -138,7 +138,7 @@ def _reboot(self) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/systems_switches/ss3706a.py b/src/tm_devices/drivers/pi/systems_switches/ss3706a.py index eaaa4958..5b4f7329 100644 --- a/src/tm_devices/drivers/pi/systems_switches/ss3706a.py +++ b/src/tm_devices/drivers/pi/systems_switches/ss3706a.py @@ -77,7 +77,7 @@ def _reboot(self) -> None: NotImplementedError: Indicates the current driver has not implemented this method. """ # TODO: implement - raise NotImplementedError( # noqa: TRY003 + raise NotImplementedError( f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore f" is not yet implemented for the {self.__class__.__name__} driver" )