benchloom 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. benchloom-0.1.3/.github/ISSUE_TEMPLATE/bug_report.yml +41 -0
  2. benchloom-0.1.3/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. benchloom-0.1.3/.github/ISSUE_TEMPLATE/instrument_request.yml +35 -0
  4. benchloom-0.1.3/.github/pull_request_template.md +16 -0
  5. benchloom-0.1.3/.github/workflows/release.yml +83 -0
  6. benchloom-0.1.3/.github/workflows/tests.yml +42 -0
  7. benchloom-0.1.3/.gitignore +9 -0
  8. benchloom-0.1.3/CHANGELOG.md +68 -0
  9. benchloom-0.1.3/CLA.md +38 -0
  10. benchloom-0.1.3/CONTRIBUTING.md +85 -0
  11. benchloom-0.1.3/LICENSE +661 -0
  12. benchloom-0.1.3/PKG-INFO +422 -0
  13. benchloom-0.1.3/README.md +375 -0
  14. benchloom-0.1.3/SECURITY.md +27 -0
  15. benchloom-0.1.3/THIRD_PARTY_NOTICES.md +67 -0
  16. benchloom-0.1.3/docs/INSTRUMENTS.md +438 -0
  17. benchloom-0.1.3/docs/PLAN.md +90 -0
  18. benchloom-0.1.3/docs/images/app.png +0 -0
  19. benchloom-0.1.3/docs/images/panel.png +0 -0
  20. benchloom-0.1.3/docs/images/visual.png +0 -0
  21. benchloom-0.1.3/docs/images/waveforms.png +0 -0
  22. benchloom-0.1.3/packaging/README-Windows.txt +43 -0
  23. benchloom-0.1.3/packaging/app.py +9 -0
  24. benchloom-0.1.3/packaging/benchloom.ico +0 -0
  25. benchloom-0.1.3/packaging/benchloom.spec +58 -0
  26. benchloom-0.1.3/packaging/build_windows.py +108 -0
  27. benchloom-0.1.3/packaging/cli.py +9 -0
  28. benchloom-0.1.3/packaging/entry.py +100 -0
  29. benchloom-0.1.3/packaging/release_notes.py +58 -0
  30. benchloom-0.1.3/pyproject.toml +87 -0
  31. benchloom-0.1.3/src/benchloom/__init__.py +43 -0
  32. benchloom-0.1.3/src/benchloom/__main__.py +5 -0
  33. benchloom-0.1.3/src/benchloom/cli.py +210 -0
  34. benchloom-0.1.3/src/benchloom/config.py +88 -0
  35. benchloom-0.1.3/src/benchloom/datalog.py +205 -0
  36. benchloom-0.1.3/src/benchloom/engine.py +554 -0
  37. benchloom-0.1.3/src/benchloom/graph.py +427 -0
  38. benchloom-0.1.3/src/benchloom/gui/__init__.py +29 -0
  39. benchloom-0.1.3/src/benchloom/gui/devices.py +529 -0
  40. benchloom-0.1.3/src/benchloom/gui/editor.py +197 -0
  41. benchloom-0.1.3/src/benchloom/gui/graph_editor.py +843 -0
  42. benchloom-0.1.3/src/benchloom/gui/main_window.py +688 -0
  43. benchloom-0.1.3/src/benchloom/gui/panel_view.py +448 -0
  44. benchloom-0.1.3/src/benchloom/gui/plot.py +265 -0
  45. benchloom-0.1.3/src/benchloom/gui/plugins.py +417 -0
  46. benchloom-0.1.3/src/benchloom/gui/runner.py +132 -0
  47. benchloom-0.1.3/src/benchloom/gui/settings.py +245 -0
  48. benchloom-0.1.3/src/benchloom/gui/theme.py +75 -0
  49. benchloom-0.1.3/src/benchloom/gui/waveforms.py +83 -0
  50. benchloom-0.1.3/src/benchloom/modbus.py +33 -0
  51. benchloom-0.1.3/src/benchloom/panel.py +198 -0
  52. benchloom-0.1.3/src/benchloom/plugin.py +462 -0
  53. benchloom-0.1.3/src/benchloom/plugin_install.py +144 -0
  54. benchloom-0.1.3/src/benchloom/plugins/chroma/chroma6404.py +243 -0
  55. benchloom-0.1.3/src/benchloom/plugins/chroma/plugin.toml +31 -0
  56. benchloom-0.1.3/src/benchloom/plugins/demo/driver.py +27 -0
  57. benchloom-0.1.3/src/benchloom/plugins/demo/plugin.toml +13 -0
  58. benchloom-0.1.3/src/benchloom/plugins/demo/simulator.py +50 -0
  59. benchloom-0.1.3/src/benchloom/plugins/feeltech/fy6900.py +661 -0
  60. benchloom-0.1.3/src/benchloom/plugins/feeltech/plugin.toml +33 -0
  61. benchloom-0.1.3/src/benchloom/plugins/generic/driver.py +39 -0
  62. benchloom-0.1.3/src/benchloom/plugins/generic/plugin.toml +21 -0
  63. benchloom-0.1.3/src/benchloom/plugins/generic/simulator.py +19 -0
  64. benchloom-0.1.3/src/benchloom/plugins/hantek/dso5000p.py +617 -0
  65. benchloom-0.1.3/src/benchloom/plugins/hantek/plugin.toml +18 -0
  66. benchloom-0.1.3/src/benchloom/plugins/hantek/protocol.inf +125 -0
  67. benchloom-0.1.3/src/benchloom/plugins/hp/hp3478a.py +260 -0
  68. benchloom-0.1.3/src/benchloom/plugins/hp/hp53131a.py +294 -0
  69. benchloom-0.1.3/src/benchloom/plugins/hp/hp6655a.py +155 -0
  70. benchloom-0.1.3/src/benchloom/plugins/hp/plugin.toml +71 -0
  71. benchloom-0.1.3/src/benchloom/plugins/kunkin/driver.py +197 -0
  72. benchloom-0.1.3/src/benchloom/plugins/kunkin/plugin.toml +39 -0
  73. benchloom-0.1.3/src/benchloom/plugins/kunkin/simulator.py +81 -0
  74. benchloom-0.1.3/src/benchloom/project.py +246 -0
  75. benchloom-0.1.3/src/benchloom/report.py +159 -0
  76. benchloom-0.1.3/src/benchloom/scpi.py +155 -0
  77. benchloom-0.1.3/src/benchloom/simbench.py +38 -0
  78. benchloom-0.1.3/src/benchloom/svgplot.py +230 -0
  79. benchloom-0.1.3/src/benchloom/svgpng.py +47 -0
  80. benchloom-0.1.3/src/benchloom/templates/LICENSE.txt +21 -0
  81. benchloom-0.1.3/src/benchloom/templates/bode/benchloom.toml +24 -0
  82. benchloom-0.1.3/src/benchloom/templates/bode/main.lua +99 -0
  83. benchloom-0.1.3/src/benchloom/templates/bode/panel.json +243 -0
  84. benchloom-0.1.3/src/benchloom/templates/bode/template.toml +6 -0
  85. benchloom-0.1.3/src/benchloom/transports.py +788 -0
  86. benchloom-0.1.3/src/benchloom/worker.py +68 -0
  87. benchloom-0.1.3/tests/conftest.py +34 -0
  88. benchloom-0.1.3/tests/test_bode.py +141 -0
  89. benchloom-0.1.3/tests/test_counter_scope_usb.py +196 -0
  90. benchloom-0.1.3/tests/test_engine.py +125 -0
  91. benchloom-0.1.3/tests/test_feeltech.py +218 -0
  92. benchloom-0.1.3/tests/test_graph.py +137 -0
  93. benchloom-0.1.3/tests/test_graph_editor.py +256 -0
  94. benchloom-0.1.3/tests/test_gui.py +384 -0
  95. benchloom-0.1.3/tests/test_instruments.py +427 -0
  96. benchloom-0.1.3/tests/test_panel.py +226 -0
  97. benchloom-0.1.3/tests/test_plugin_manager.py +177 -0
  98. benchloom-0.1.3/tests/test_rename.py +33 -0
  99. benchloom-0.1.3/tests/test_report.py +191 -0
  100. benchloom-0.1.3/tests/test_safety.py +253 -0
  101. benchloom-0.1.3/tests/test_sandbox.py +78 -0
  102. benchloom-0.1.3/tests/test_theme_plot.py +116 -0
@@ -0,0 +1,41 @@
1
+ name: Bug report
2
+ description: Something does not work as it should.
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: what
7
+ attributes:
8
+ label: What happened?
9
+ description: What you did, what you expected, and what happened instead.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: steps
14
+ attributes:
15
+ label: How to make it happen again
16
+ description: Steps, or a small project (zip the project folder without its runs/).
17
+ - type: textarea
18
+ id: log
19
+ attributes:
20
+ label: Console output
21
+ description: From the Console, or the run folder's console.log. Error messages are most helpful.
22
+ render: text
23
+ - type: input
24
+ id: version
25
+ attributes:
26
+ label: Benchloom version
27
+ description: "`pip show benchloom`, or the version at the top of a run's report.html"
28
+ validations:
29
+ required: true
30
+ - type: input
31
+ id: system
32
+ attributes:
33
+ label: Operating system and Python version
34
+ placeholder: Windows 11, Python 3.12
35
+ validations:
36
+ required: true
37
+ - type: input
38
+ id: instruments
39
+ attributes:
40
+ label: Instruments involved
41
+ description: Model, and how it is connected (serial, USB, GPIB adapter, LAN).
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Security problem
4
+ url: https://github.com/criscrafter/benchloom/security/advisories/new
5
+ about: Please report security problems privately, not as a public issue.
@@ -0,0 +1,35 @@
1
+ name: Instrument request
2
+ description: Ask for support of an instrument Benchloom does not have a driver for.
3
+ labels: [instrument]
4
+ body:
5
+ - type: input
6
+ id: model
7
+ attributes:
8
+ label: Instrument
9
+ placeholder: Maker and model, for example Rigol DP832
10
+ validations:
11
+ required: true
12
+ - type: dropdown
13
+ id: connection
14
+ attributes:
15
+ label: How it connects
16
+ multiple: true
17
+ options: [USB (serial / virtual COM port), USB (other), RS-232 / RS-485, GPIB, LAN, Other]
18
+ validations:
19
+ required: true
20
+ - type: input
21
+ id: manual
22
+ attributes:
23
+ label: Programming manual
24
+ description: A link to the command reference, if you have one.
25
+ - type: textarea
26
+ id: use
27
+ attributes:
28
+ label: What do you want to do with it?
29
+ description: The commands that matter most to you, for example set voltage, measure current.
30
+ - type: checkboxes
31
+ id: help
32
+ attributes:
33
+ label: Can you help test?
34
+ options:
35
+ - label: I own this instrument and can try a driver on it.
@@ -0,0 +1,16 @@
1
+ ## What this changes
2
+
3
+ <!-- What and why, in a few sentences. Link the issue if there is one. -->
4
+
5
+ ## How it was tested
6
+
7
+ <!-- Tests added or run; for a driver: which instrument, firmware and connection,
8
+ or "simulator only". -->
9
+
10
+ ## Checklist
11
+
12
+ - [ ] `pytest` passes.
13
+ - [ ] New instrument drivers come with a simulator and tests, and notes in
14
+ `docs/INSTRUMENTS.md` on what was tried on real hardware.
15
+ - [ ] I have read and agree to the [Benchloom Contributor License Agreement](../CLA.md).
16
+ <!-- Not needed for typo or wording fixes. -->
@@ -0,0 +1,83 @@
1
+ name: Release
2
+
3
+ # Builds Benchloom-<version>-windows-x64.zip, runs its self-test and publishes it.
4
+ # For a pushed version tag (v1.2.3) it creates the release itself, with notes from
5
+ # the version's section in CHANGELOG.md, so nothing needs editing by hand, and then
6
+ # uploads the Python package to PyPI. Run by hand (Actions -> Release ->
7
+ # Run workflow), it only re-attaches the zip to an existing release.
8
+ on:
9
+ push:
10
+ tags: ["v*"]
11
+ workflow_dispatch:
12
+ inputs:
13
+ tag:
14
+ description: "Release tag to attach the download to, for example v0.1.0"
15
+ required: true
16
+
17
+ permissions:
18
+ contents: write # to upload the zip to the release
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: windows-latest
23
+ env:
24
+ TAG: ${{ github.event.inputs.tag || github.ref_name }}
25
+ steps:
26
+ - uses: actions/checkout@v5
27
+ with:
28
+ ref: ${{ env.TAG }}
29
+
30
+ - uses: actions/setup-python@v6
31
+ with:
32
+ python-version: "3.12"
33
+
34
+ - name: Install
35
+ run: |
36
+ python -m pip install --upgrade pip
37
+ pip install -e ".[gui,usb]" "pyinstaller>=6.10"
38
+
39
+ - name: Build and self-test
40
+ run: python packaging/build_windows.py
41
+
42
+ - name: Publish the release
43
+ shell: bash
44
+ env:
45
+ GH_TOKEN: ${{ github.token }}
46
+ run: |
47
+ if gh release view "$TAG" > /dev/null 2>&1; then
48
+ gh release upload "$TAG" build/Benchloom-*-windows-x64.zip --clobber
49
+ else
50
+ python packaging/release_notes.py "$TAG" > notes.md
51
+ gh release create "$TAG" build/Benchloom-*-windows-x64.zip \
52
+ --title "Benchloom ${TAG#v}" --notes-file notes.md --verify-tag --latest
53
+ fi
54
+
55
+ pypi:
56
+ # PyPI trusts this workflow ("trusted publishing"), so no password or token is
57
+ # stored anywhere. Only after the Windows build passed its self-test.
58
+ needs: build
59
+ if: github.event_name == 'push'
60
+ runs-on: ubuntu-latest
61
+ environment:
62
+ name: pypi
63
+ url: https://pypi.org/project/benchloom/
64
+ permissions:
65
+ id-token: write # proves to PyPI that this is criscrafter/benchloom's workflow
66
+ steps:
67
+ - uses: actions/checkout@v5
68
+ with:
69
+ ref: ${{ github.ref_name }}
70
+
71
+ - uses: actions/setup-python@v6
72
+ with:
73
+ python-version: "3.12"
74
+
75
+ - name: Build the package
76
+ run: |
77
+ python -m pip install --upgrade build twine
78
+ python -m build
79
+ python -m twine check --strict dist/*
80
+ test "$(ls dist/*.whl)" = "dist/benchloom-${GITHUB_REF_NAME#v}-py3-none-any.whl"
81
+
82
+ - name: Upload to PyPI
83
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,42 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: ${{ matrix.os }} · Python ${{ matrix.python }}
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [windows-latest, ubuntu-latest]
19
+ python: ["3.11", "3.13"]
20
+ env:
21
+ QT_QPA_PLATFORM: offscreen
22
+ steps:
23
+ - uses: actions/checkout@v5
24
+
25
+ - uses: actions/setup-python@v6
26
+ with:
27
+ python-version: ${{ matrix.python }}
28
+
29
+ - name: Qt's system libraries (Linux)
30
+ if: runner.os == 'Linux'
31
+ run: |
32
+ sudo apt-get update
33
+ sudo apt-get install -y libegl1 libgl1 libxkbcommon0 libdbus-1-3 \
34
+ libfontconfig1 libglib2.0-0 fonts-dejavu-core
35
+
36
+ - name: Install
37
+ run: |
38
+ python -m pip install --upgrade pip
39
+ pip install -e ".[gui,usb,dev]"
40
+
41
+ - name: Test
42
+ run: pytest -q
@@ -0,0 +1,9 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .pytest_cache/
8
+ runs/
9
+ packaging/version_info.txt
@@ -0,0 +1,68 @@
1
+ # Changelog
2
+
3
+ ## 0.1.3 – Safer stops, plugin consent and PyPI
4
+
5
+ - **Plugins in a project need your consent:** a project's own `plugins/` folder
6
+ is Python code, and it used to be loaded as soon as the project was opened.
7
+ Now the app asks first, per project, and `benchloom run` needs
8
+ `--trust-plugins` once. Until then such a plugin does not replace a built-in
9
+ one either.
10
+ - **Stopping switches outputs off more reliably:** when a script does not stop
11
+ within 3 s (a loop that never checks, a slow command), the run now shuts its
12
+ devices down without the script instead of being killed with the outputs on.
13
+ Shutting down is no longer cut short after 3 s, and closing the window
14
+ while a test runs waits for it too.
15
+ - The app no longer shows the commands of another project's plugin after
16
+ switching between projects that carry a plugin with the same id.
17
+ - **On PyPI:** `pip install "benchloom[gui,usb]"` installs Benchloom; every
18
+ release is uploaded there automatically.
19
+
20
+ ## 0.1.2 – Lua sandbox
21
+
22
+ - **Lua sandbox:** scripts no longer reach files, other programs or other code
23
+ on the computer (`io`, `os.execute` and the rest of `os` except `time`,
24
+ `clock`, `date` and `difftime`, `require`, `dofile`, `loadfile`, `package`,
25
+ `debug`, `collectgarbage`, `string.dump`; `load` takes text only), and use at
26
+ most 1 GB of memory. Scripts that read or wrote files themselves need
27
+ changing.
28
+ - CONTRIBUTING: the build command for the Windows download was garbled.
29
+
30
+ ## 0.1.1 – Windows download
31
+
32
+ - **Windows download:** `Benchloom-0.1.1-windows-x64.zip` on the releases page.
33
+ Unzip and start `Benchloom.exe`; no Python needed. `benchloom-cli.exe` is the
34
+ command line.
35
+ - The app has an About dialog and `benchloom --version` with the licence and
36
+ warranty notices.
37
+ - Waveform PNGs also work in the packaged app, and show text when Qt runs
38
+ offscreen on Windows.
39
+ - CI runs on Windows and Linux; the Linux test run no longer fails after the
40
+ tests have passed (a PySide6 shutdown fault).
41
+
42
+ ## 0.1.0 – first public release
43
+
44
+ Benchloom was developed as "Patchbay" until this release. Projects with a
45
+ `patchbay.toml`, the `~/.patchbay` folder and the desktop app's settings from
46
+ that time keep working.
47
+
48
+ - **Tests** as Lua scripts or as visual graphs (nodes and wires, compiled to
49
+ Lua), run in a separate process that can always be stopped.
50
+ - **Desktop app:** project wizard with templates, device manager with serial
51
+ port list and connection test, Lua editor, node editor (undo/redo,
52
+ copy/paste), live plot (right-hand scale, log X, column choice), front panel
53
+ with controls and indicators, waveform viewer, plugin manager, settings,
54
+ light and dark theme.
55
+ - **Run folders** with `data.csv`, console log, `run.json`, a copy of the
56
+ script, pass/fail checks (`check`), saved waveforms (`save_waveform`, as CSV,
57
+ SVG and PNG) and `report.html` with the verdict, data chart and waveforms.
58
+ - **Instruments:** Kunkin KP184 electronic load (RS-232 and RS-485), Chroma 6404
59
+ AC source, Hantek DSO5102P oscilloscope (USB, including gain/phase
60
+ measurement), Feeltech FY6900 function generator (signal, modulation, sweep,
61
+ counter), HP 6655A, HP 3478A and HP 53131A (GPIB, from their manuals), a
62
+ generic SCPI driver and an Arduino line protocol. Each has a simulator.
63
+ - **Connections:** serial, TCP, Prologix and AR488 GPIB adapters, VISA, USB
64
+ bulk and USBTMC (including the xyphro UsbGpib adapter) without a vendor VISA.
65
+ - **Templates:** a power supply example and a Bode plot (FY6900 and DSO5102P)
66
+ that finds the -3 dB points and can check them against limits.
67
+ - **Plugins:** installable from a folder or a .zip, can be switched off,
68
+ `benchloom plugins` on the command line.
benchloom-0.1.3/CLA.md ADDED
@@ -0,0 +1,38 @@
1
+ # Benchloom Contributor License Agreement
2
+
3
+ Version 1.0
4
+
5
+ This agreement is between you (the contributor) and the maintainer of
6
+ Benchloom, Friedrich-Christer Rosenthal (the maintainer). It covers everything
7
+ you submit to the Benchloom project, such as code, documentation and drivers
8
+ (your contributions).
9
+
10
+ 1. **You keep your copyright.** You do not transfer ownership of your
11
+ contributions.
12
+
13
+ 2. **Licence to the maintainer.** You grant the maintainer, and anyone the
14
+ maintainer licenses Benchloom to, a perpetual, worldwide, non-exclusive,
15
+ royalty-free, irrevocable licence to use, copy, modify, publish, distribute
16
+ and sublicense your contributions, under the GNU Affero General Public
17
+ License or **any other licence, including commercial licences**.
18
+
19
+ 3. **Patents.** You grant the same parties a perpetual, worldwide,
20
+ non-exclusive, royalty-free, irrevocable licence under any patents you hold
21
+ that your contributions would otherwise infringe, to make, use, sell and
22
+ distribute them as part of Benchloom.
23
+
24
+ 4. **Open source stays open.** The maintainer will keep making your
25
+ contributions available under the GNU Affero General Public License 3.0 or a
26
+ later version, as part of Benchloom.
27
+
28
+ 5. **You may agree to this.** Your contributions are your own work, or you have
29
+ the right to submit them under these terms. If your employer has rights in
30
+ your work, you have its permission or it has waived those rights. You say
31
+ so when parts of a contribution come from someone else, along with their
32
+ licence.
33
+
34
+ 6. **No warranty.** Your contributions are provided "as is", without warranty
35
+ of any kind, and you are not expected to support them.
36
+
37
+ You agree to this by ticking the box in the pull request template, or by
38
+ writing "I agree to the Benchloom CLA" in the pull request.
@@ -0,0 +1,85 @@
1
+ # Contributing to Benchloom
2
+
3
+ Thank you for helping. Bug reports, instrument drivers, fixes and documentation
4
+ are all welcome.
5
+
6
+ ## Reporting a bug or asking for an instrument
7
+
8
+ Open an issue and pick a template. For a bug, say what you did, what you
9
+ expected and what happened, and attach the run folder's `console.log` (and
10
+ `run.json`) if a test run went wrong. For an instrument, name the model, how it
11
+ connects (serial, USB, GPIB, LAN) and link its programming manual if you have
12
+ it.
13
+
14
+ ## Setting up
15
+
16
+ ```
17
+ git clone https://github.com/criscrafter/benchloom
18
+ cd benchloom
19
+ python -m venv .venv
20
+ .venv\Scripts\pip install -e ".[gui,dev]" # Linux/Mac: .venv/bin/pip
21
+ .venv\Scripts\pytest
22
+ ```
23
+
24
+ Python 3.11 or newer. The tests use the instruments' simulators, so no hardware
25
+ is needed; the desktop app is tested offscreen.
26
+
27
+ ## Building the Windows download
28
+
29
+ ```
30
+ .venv\Scripts\pip install -e ".[gui,usb]" pyinstaller
31
+ .venv\Scripts\python packaging\build_windows.py
32
+ ```
33
+
34
+ This makes `build/Benchloom-<version>-windows-x64.zip` and runs a self-test of
35
+ the packaged app first.
36
+
37
+ To release a version: add its section to CHANGELOG.md (`## 1.2.3 – title`),
38
+ set `__version__` in `src/benchloom/__init__.py`, and push the tag `v1.2.3`.
39
+ GitHub then builds and self-tests the download and publishes the release with
40
+ that changelog section as its notes, then uploads the package to PyPI;
41
+ nothing needs editing by hand. PyPI accepts it through trusted publishing
42
+ (the `pypi` environment of this repository), so no token is stored anywhere.
43
+
44
+ ## Writing an instrument plugin
45
+
46
+ A plugin is a folder with a `plugin.toml` and a Python driver. The README
47
+ section "A plugin" shows the format, and `src/benchloom/plugins/demo` is the
48
+ reference example. For a driver to be merged it needs:
49
+
50
+ - **A simulator** that answers like the real instrument (`simulator = ...` in
51
+ `plugin.toml`), so the driver is tested without hardware, and tests in
52
+ `tests/` that use it.
53
+ - **Output safety:** sources and loads switch their output off in `close()`
54
+ unless the device entry says `leave_output_on = true`.
55
+ - **Honest notes** in `docs/INSTRUMENTS.md`: what was tried on real hardware
56
+ (model, firmware, connection) and what was only written from the manual.
57
+ - **Checked settings:** when an instrument silently clamps or ignores a value,
58
+ read it back and raise a `CommandError` that says what happened.
59
+
60
+ ## Code style
61
+
62
+ - Readable over clever; comments say why, not what.
63
+ - Error messages tell the user what to do ("is the channel on and the scope
64
+ running?"), in plain words.
65
+ - New files start with the licence header:
66
+ ```
67
+ # SPDX-License-Identifier: AGPL-3.0-or-later
68
+ # Copyright (C) 2026 <your name>
69
+ ```
70
+ - Run `pytest` before you open a pull request. CI runs it on Windows and Linux.
71
+
72
+ ## The contributor agreement
73
+
74
+ Benchloom is open source under the AGPL-3.0, and the maintainer also offers
75
+ commercial licences to companies that cannot use the AGPL. That only works if
76
+ the maintainer may license every part of Benchloom, including contributions,
77
+ on both terms.
78
+
79
+ So every pull request needs agreement to the **[Contributor License
80
+ Agreement](CLA.md)**: you keep the copyright of your contribution and grant a
81
+ licence to use it, including under other licences. Tick the box in the pull
82
+ request template to agree. Your contribution stays available under the AGPL in
83
+ any case.
84
+
85
+ Small fixes of typos or wording need no agreement.