visa-instrument-drivers 0.1.4__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.
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ .venv/
5
+ build/
6
+ dist/
7
+ *.egg-info/
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
@@ -0,0 +1,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Black">
4
+ <option name="sdkName" value="Python 3.12 (visa_instrument_drivers)" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
7
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/visa_instrument_drivers.iml" filepath="$PROJECT_DIR$/.idea/visa_instrument_drivers.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.venv" />
6
+ </content>
7
+ <orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
8
+ <orderEntry type="sourceFolder" forTests="false" />
9
+ </component>
10
+ </module>
@@ -0,0 +1,87 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AutoImportSettings">
4
+ <option name="autoReloadType" value="SELECTIVE" />
5
+ </component>
6
+ <component name="ChangeListManager">
7
+ <list default="true" id="1b9d8306-46eb-4f49-a77c-72d8b07063ff" name="Changes" comment="">
8
+ <change afterPath="$PROJECT_DIR$/src/visa_instrument_drivers/keysight_e36150.py" afterDir="false" />
9
+ </list>
10
+ <option name="SHOW_DIALOG" value="false" />
11
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
12
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
13
+ <option name="LAST_RESOLUTION" value="IGNORE" />
14
+ </component>
15
+ <component name="FileTemplateManagerImpl">
16
+ <option name="RECENT_TEMPLATES">
17
+ <list>
18
+ <option value="Python Script" />
19
+ </list>
20
+ </option>
21
+ </component>
22
+ <component name="Git.Settings">
23
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
24
+ </component>
25
+ <component name="ProjectColorInfo">{
26
+ &quot;associatedIndex&quot;: 7
27
+ }</component>
28
+ <component name="ProjectId" id="321jFeavc3IaGNnvrXfw0ry68ba" />
29
+ <component name="ProjectViewState">
30
+ <option name="hideEmptyMiddlePackages" value="true" />
31
+ <option name="showLibraryContents" value="true" />
32
+ </component>
33
+ <component name="PropertiesComponent">{
34
+ &quot;keyToString&quot;: {
35
+ &quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
36
+ &quot;Python.main.executor&quot;: &quot;Run&quot;,
37
+ &quot;Python.rigol_dp800.executor&quot;: &quot;Run&quot;,
38
+ &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
39
+ &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
40
+ &quot;git-widget-placeholder&quot;: &quot;main&quot;,
41
+ &quot;last_opened_file_path&quot;: &quot;/Users/mborgh/github.com/mikeborgh/visa-instrument-drivers&quot;,
42
+ &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
43
+ &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
44
+ &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
45
+ &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
46
+ &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
47
+ &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
48
+ }
49
+ }</component>
50
+ <component name="RecentsManager">
51
+ <key name="MoveFile.RECENT_KEYS">
52
+ <recent name="$PROJECT_DIR$/src/visa_instrument_drivers" />
53
+ </key>
54
+ </component>
55
+ <component name="SharedIndexes">
56
+ <attachedChunks>
57
+ <set>
58
+ <option value="bundled-js-predefined-d6986cc7102b-f27c65a3e318-JavaScript-PY-251.23774.444" />
59
+ <option value="bundled-python-sdk-890ed5b35930-d9c5bdb153f4-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-251.23774.444" />
60
+ </set>
61
+ </attachedChunks>
62
+ </component>
63
+ <component name="TaskManager">
64
+ <task active="true" id="Default" summary="Default task">
65
+ <changelist id="1b9d8306-46eb-4f49-a77c-72d8b07063ff" name="Changes" comment="" />
66
+ <created>1756594869221</created>
67
+ <option name="number" value="Default" />
68
+ <option name="presentableId" value="Default" />
69
+ <updated>1756594869221</updated>
70
+ <workItem from="1756594870240" duration="11799000" />
71
+ <workItem from="1756657832343" duration="1059000" />
72
+ <workItem from="1756854196801" duration="4745000" />
73
+ <workItem from="1758366158951" duration="24000" />
74
+ <workItem from="1767736572715" duration="16495000" />
75
+ <workItem from="1768163729441" duration="91000" />
76
+ <workItem from="1768164174885" duration="1672000" />
77
+ </task>
78
+ <servers />
79
+ </component>
80
+ <component name="TypeScriptGeneratedFilesManager">
81
+ <option name="version" value="3" />
82
+ </component>
83
+ <component name="com.intellij.coverage.CoverageDataManagerImpl">
84
+ <SUITE FILE_PATH="coverage/visa_instrument_drivers$main.coverage" NAME="main Coverage Results" MODIFIED="1756656650668" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
85
+ <SUITE FILE_PATH="coverage/visa_instrument_drivers$rigol_dp800.coverage" NAME="rigol_dp800 Coverage Results" MODIFIED="1756598317827" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/src/visa_instrument_drivers" />
86
+ </component>
87
+ </project>
@@ -0,0 +1 @@
1
+ 3.12
File without changes
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: visa-instrument-drivers
3
+ Version: 0.1.4
4
+ Summary: Add your description here
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: pyvisa>=1.16.0
8
+ Description-Content-Type: text/markdown
9
+
10
+ # visa-instrument-drivers
11
+
12
+ Tiny, pragmatic VISA instrument drivers built to use PyVISA.
13
+
14
+ ```python
15
+ import pyvisa
16
+ from visa_instrument_drivers import RigolDP800
17
+
18
+ rm = pyvisa.ResourceManager()
19
+ instr = rm.open_resource("TCPIP::192.168.0.107::INSTR")
20
+ dp832a = RigolDP800(instr)
21
+ dp832a.write_source_voltage(13.5) # CH1
22
+ print(dp832a.read_source_voltage()) # 13.5 (setpoint)
23
+ instr.close()
24
+ rm.close()
25
+ ```
26
+
27
+ Build and publish
28
+
29
+ ```shell
30
+ python -m pip install --upgrade pip build twine
31
+ # python -m build
32
+ # python -m twine upload --repository pypi dist/*
33
+ uv version --bump patch
34
+ uv build
35
+ # uv tool install uv-publish
36
+ uv-publish # looks for .pypirc file with PyPI credentials
37
+ ```
@@ -0,0 +1,28 @@
1
+ # visa-instrument-drivers
2
+
3
+ Tiny, pragmatic VISA instrument drivers built to use PyVISA.
4
+
5
+ ```python
6
+ import pyvisa
7
+ from visa_instrument_drivers import RigolDP800
8
+
9
+ rm = pyvisa.ResourceManager()
10
+ instr = rm.open_resource("TCPIP::192.168.0.107::INSTR")
11
+ dp832a = RigolDP800(instr)
12
+ dp832a.write_source_voltage(13.5) # CH1
13
+ print(dp832a.read_source_voltage()) # 13.5 (setpoint)
14
+ instr.close()
15
+ rm.close()
16
+ ```
17
+
18
+ Build and publish
19
+
20
+ ```shell
21
+ python -m pip install --upgrade pip build twine
22
+ # python -m build
23
+ # python -m twine upload --repository pypi dist/*
24
+ uv version --bump patch
25
+ uv build
26
+ # uv tool install uv-publish
27
+ uv-publish # looks for .pypirc file with PyPI credentials
28
+ ```
@@ -0,0 +1,29 @@
1
+ import pyvisa
2
+ from src.visa_instrument_drivers.rigol_dp800 import RigolDP800
3
+
4
+ def main():
5
+ rm = pyvisa.ResourceManager() #'/Users/mborgh/Downloads/nodevisa-v0.0.3-osx-arm64/liblibrary.dylib')
6
+ instr = rm.open_resource('Rigol DP832A SLC')
7
+
8
+ rigol_dp832a = RigolDP800(instr)
9
+
10
+ initial_current_limit = rigol_dp832a.query_source_current_level_immediate_amplitude(1)
11
+ initial_voltage_level = rigol_dp832a.query_source_voltage_level_immediate_amplitude(1)
12
+ initial_output_state = rigol_dp832a.query_output_state(1)
13
+
14
+ rigol_dp832a.write_source_current_level_immediate_amplitude(1, 3.0)
15
+ rigol_dp832a.write_source_voltage_level_immediate_amplitude(1, 5.0)
16
+ rigol_dp832a.write_output_state(1, 1)
17
+
18
+ final_current_limit = rigol_dp832a.query_source_current_level_immediate_amplitude(1)
19
+ final_voltage_level = rigol_dp832a.query_source_voltage_level_immediate_amplitude(1)
20
+ final_output_state = rigol_dp832a.query_output_state(1)
21
+
22
+ instr.close()
23
+ rm.close()
24
+
25
+ return
26
+
27
+
28
+ if __name__ == '__main__':
29
+ main()
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "visa-instrument-drivers" # 👇 The PyPI name
7
+ version = "0.1.1" # 👇 Bump each release
8
+ description = "Tiny, pragmatic VISA instrument drivers on top of PyVISA."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Michael", email = "michael@example.com" } # 👇
14
+ ]
15
+ keywords = ["VISA", "SCPI", "PyVISA", "instruments", "automation", "rigol"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Topic :: Scientific/Engineering",
21
+ "Intended Audience :: Developers",
22
+ ]
23
+
24
+ # Core runtime deps
25
+ dependencies = [
26
+ "pyvisa>=1.13",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ # For users who want a pure-Python backend (no NI-VISA)
31
+ backends = ["pyvisa-py>=0.7"]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/fusaware/visa-instrument-drivers" # 👇
35
+ Issues = "https://github.com/fusaware/visa-instrument-drivers/issues"
36
+
37
+ [tool.hatch.build.targets.sdist]
38
+ include = ["src", "README.md", "LICENSE", "pyproject.toml"]
39
+
40
+ [tool.hatch.build.targets.wheel]
41
+ packages = ["src/visa_instrument_drivers"]
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "visa-instrument-drivers"
7
+ version = "0.1.4"
8
+ description = "Add your description here"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "pyvisa>=1.16.0",
13
+ ]
14
+
15
+ [tool.hatch.build.targets.wheel]
16
+ packages = ["src/visa_instrument_drivers"]
@@ -0,0 +1,4 @@
1
+ from .rigol_dp800 import RigolDP800
2
+ from .rigol_mso5000 import RigolMSO5000
3
+
4
+ __all__ = ['RigolDP800', 'RigolMSO5000']
@@ -0,0 +1,28 @@
1
+ import pyvisa
2
+
3
+ class KeysightE36150:
4
+ class Channel:
5
+ class Number:
6
+ CH1 = 1
7
+
8
+ def __init__(self, instr: pyvisa.Resource):
9
+ self.instr = instr
10
+ return
11
+
12
+ def query_output_state(self, channel: int) -> int:
13
+ if channel not in KeysightE36150.Channel.Number:
14
+ raise ValueError(f"Channel {channel} is not supported")
15
+
16
+ msg = f":OUTP? (@{channel})"
17
+ resp = self.instr.query(msg)
18
+ state = int(resp.strip())
19
+ return state
20
+
21
+ def write_output_state(self, channel: int, state: int):
22
+ if channel not in KeysightE36150.Channel.Number:
23
+ raise ValueError(f"Channel {channel} is not supported")
24
+
25
+ msg = f":OUTP {state},(@{channel})"
26
+ self.instr.write(msg)
27
+ return
28
+
@@ -0,0 +1,75 @@
1
+ from enum import Enum
2
+ import pyvisa
3
+
4
+ class RigolDP800:
5
+ class Channel:
6
+ class Number(int, Enum):
7
+ CH1 = 1
8
+ CH2 = 2
9
+ CH3 = 3
10
+
11
+ class Output:
12
+ class State(int, Enum):
13
+ OFF = 0
14
+ ON = 1
15
+
16
+ def __init__(self, instr: pyvisa.Resource):
17
+ self.instr = instr
18
+ return
19
+
20
+ def query_source_current_level_immediate_amplitude(self, channel: int) -> float:
21
+ if channel not in RigolDP800.Channel.Number:
22
+ raise ValueError("Invalid channel number")
23
+
24
+ msg = f":SOUR{channel}:CURR?"
25
+ resp = self.instr.query(msg)
26
+ level = float(resp.strip())
27
+ return level
28
+
29
+ def write_source_current_level_immediate_amplitude(self, channel: int, amplitude: float):
30
+ if channel not in RigolDP800.Channel.Number:
31
+ raise ValueError("Invalid channel number")
32
+
33
+ msg = f":SOUR{channel}:CURR {amplitude}"
34
+ self.instr.write(msg)
35
+ return
36
+
37
+ def query_source_voltage_level_immediate_amplitude(self, channel: int) -> float:
38
+ if channel not in RigolDP800.Channel.Number:
39
+ raise ValueError("Invalid channel number")
40
+
41
+ msg = f":SOUR{channel}:VOLT?"
42
+ resp = self.instr.query(msg)
43
+ level = float(resp.strip())
44
+ return level
45
+
46
+ def write_source_voltage_level_immediate_amplitude(self, channel: int, amplitude: float):
47
+ if channel not in RigolDP800.Channel.Number:
48
+ raise ValueError("Invalid channel number")
49
+
50
+ msg = f":SOUR{channel}:VOLT {amplitude}"
51
+ self.instr.write(msg)
52
+ return
53
+
54
+ def query_output_state(self, channel: int) -> int:
55
+ if channel not in RigolDP800.Channel.Number:
56
+ raise ValueError("Invalid channel number")
57
+
58
+ msg = f":OUTP:STAT? CH{channel}"
59
+ resp = self.instr.query(msg)
60
+ state = int(resp.strip())
61
+
62
+ if state not in RigolDP800.Output.State:
63
+ raise ValueError("Invalid output state")
64
+ return state
65
+
66
+ def write_output_state(self, channel: int, state: int):
67
+ if channel not in RigolDP800.Channel.Number:
68
+ raise ValueError("Invalid channel number")
69
+
70
+ if state not in RigolDP800.Output.State:
71
+ raise ValueError("Invalid output state")
72
+
73
+ msg = f":OUTP:STAT CH{channel},{state}"
74
+ self.instr.write(msg)
75
+ return
@@ -0,0 +1,158 @@
1
+ from enum import Enum
2
+ import math
3
+
4
+ import pyvisa
5
+
6
+ class RigolMSO5000:
7
+
8
+ class Attenuation:
9
+
10
+ class Ratio(Enum):
11
+ AR100u = 0.0001
12
+ AR200u = 0.0002
13
+ AR500u = 0.0005
14
+ AR1m = 0.001
15
+ AR2m = 0.002
16
+ AR5m = 0.005
17
+ AR10m = 0.01
18
+ AR20m = 0.02
19
+ AR50m = 0.05
20
+ AR100m = 0.1
21
+ AR200m = 0.2
22
+ AR500m = 0.5
23
+ AR1 = 1
24
+ AR2 = 2
25
+ AR5 = 5
26
+ AR10 = 10
27
+ AR20 = 20
28
+ AR50 = 50
29
+ AR100 = 100
30
+ AR200 = 200
31
+ AR500 = 500
32
+ AR1000 = 1000
33
+ AR2000 = 2000
34
+ AR5000 = 5000
35
+ AR10000 = 10000
36
+ AR20000 = 20000
37
+ AR50000 = 50000
38
+
39
+ class Channel:
40
+
41
+ class Number(Enum):
42
+ CH1 = 1
43
+ CH2 = 2
44
+ CH3 = 3
45
+ CH4 = 4
46
+
47
+ class Display:
48
+
49
+ class State(Enum):
50
+ OFF = 0
51
+ ON = 1
52
+
53
+ class Units(Enum):
54
+ AMP = 'AMP'
55
+ UNKN = 'UNKN'
56
+ VOLT = 'VOLT'
57
+ WATT = 'WATT'
58
+
59
+ def __init__(self, instr: pyvisa.Resource):
60
+ self.instr = instr
61
+ return
62
+
63
+ def query_channel_offset(self, channel: int) -> float:
64
+ if channel not in RigolMSO5000.Channel.Number:
65
+ raise ValueError("Invalid channel number")
66
+
67
+ msg = f":CHAN{channel}:OFFS?"
68
+ resp = self.instr.query(msg)
69
+ level = float(resp.strip())
70
+ return level
71
+
72
+ def write_channel_offset(self, channel: int, offset: float):
73
+ if channel not in RigolMSO5000.Channel.Number:
74
+ raise ValueError("Invalid channel number")
75
+
76
+ msg = f":CHAN{channel}:OFFS {offset}"
77
+ self.instr.write(msg)
78
+ return
79
+
80
+ def query_channel_scale(self, channel: int) -> float:
81
+ if channel not in RigolMSO5000.Channel.Number:
82
+ raise ValueError("Invalid channel number")
83
+
84
+ msg = f":CHAN{channel}:SCAL?"
85
+ resp = self.instr.query(msg)
86
+ level = float(resp.strip())
87
+ return level
88
+
89
+ def write_channel_scale(self, channel: int, scale: float):
90
+ if channel not in RigolMSO5000.Channel.Number:
91
+ raise ValueError("Invalid channel number")
92
+ msg = f":CHAN{channel}:SCAL {scale}"
93
+ self.instr.write(msg)
94
+ return
95
+
96
+ def query_channel_probe(self, channel: int) -> float:
97
+ if channel not in RigolMSO5000.Channel.Number:
98
+ raise ValueError("Invalid channel number")
99
+
100
+ msg = f":CHAN{channel}:PROB?"
101
+ resp = self.instr.query(msg)
102
+ level = float(resp.strip())
103
+ return float(level)
104
+
105
+ def write_channel_probe(self, channel: int, attenuation: float):
106
+ if channel not in RigolMSO5000.Channel.Number:
107
+ raise ValueError("Invalid channel number")
108
+
109
+ attenuation_value = None
110
+ for option in RigolMSO5000.Attenuation.Ratio:
111
+ if math.isclose(option.value, attenuation):
112
+ attenuation_value = option.value
113
+ if attenuation_value is None:
114
+ raise ValueError("Invalid attenuation")
115
+
116
+ msg = f":CHAN{channel}:PROB {attenuation_value}"
117
+ self.instr.write(msg)
118
+ return
119
+
120
+ def query_channel_display(self, channel: int) -> int:
121
+ if channel not in RigolMSO5000.Channel.Number:
122
+ raise ValueError("Invalid channel number")
123
+
124
+ msg = f":CHAN{channel}:DISP?"
125
+ resp = self.instr.query(msg)
126
+ state = resp.strip()
127
+ if state not in RigolMSO5000.Display.State:
128
+ raise ValueError("Invalid display state")
129
+ return state
130
+
131
+ def write_channel_display(self, channel: int, state: int):
132
+ if channel not in RigolMSO5000.Channel.Number:
133
+ raise ValueError("Invalid channel number")
134
+
135
+ msg = f":CHAN{channel}:DISP {state}?"
136
+ self.instr.write(msg)
137
+ return
138
+
139
+ def query_channel_units(self, channel: int) -> str:
140
+ if channel not in RigolMSO5000.Channel.Number:
141
+ raise ValueError("Invalid channel number")
142
+
143
+ msg = f":CHAN{channel}:UNIT?"
144
+ resp = self.instr.query(msg)
145
+ units = resp.strip()
146
+
147
+ if units not in RigolMSO5000.Units:
148
+ raise ValueError("Invalid units")
149
+
150
+ return units
151
+
152
+ def write_channel_units(self, channel: int, units: str):
153
+ if channel not in RigolMSO5000.Channel.Number:
154
+ raise ValueError("Invalid channel number")
155
+
156
+ msg = f":CHAN{channel}:UNIT {units}?"
157
+ self.instr.write(msg)
158
+ return
@@ -0,0 +1,35 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.12"
4
+
5
+ [[package]]
6
+ name = "pyvisa"
7
+ version = "1.16.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ dependencies = [
10
+ { name = "typing-extensions" },
11
+ ]
12
+ sdist = { url = "https://files.pythonhosted.org/packages/53/a1/c39c71aa453a0f68db672ab94f47cb06fb51265b2e66231987919e7d4b41/pyvisa-1.16.0.tar.gz", hash = "sha256:6daeb845fde2f9c095d02039ffd01dd27507c09376b1859dacb6b4f9a3aa3db0", size = 238604, upload-time = "2025-12-18T16:57:19.786Z" }
13
+ wheels = [
14
+ { url = "https://files.pythonhosted.org/packages/96/81/cca605eebc44f30d8d6b7a7cdb4b69f8ae4f255811f7328d60df4e0aafc5/pyvisa-1.16.0-py3-none-any.whl", hash = "sha256:10b49ab9b04c5c6f3ea3b9e69398ab49133f46dbe827f0cea13ea934e092d3d0", size = 181351, upload-time = "2025-12-18T16:57:18.208Z" },
15
+ ]
16
+
17
+ [[package]]
18
+ name = "typing-extensions"
19
+ version = "4.15.0"
20
+ source = { registry = "https://pypi.org/simple" }
21
+ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
22
+ wheels = [
23
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
24
+ ]
25
+
26
+ [[package]]
27
+ name = "visa-instrument-drivers"
28
+ version = "0.1.4"
29
+ source = { editable = "." }
30
+ dependencies = [
31
+ { name = "pyvisa" },
32
+ ]
33
+
34
+ [package.metadata]
35
+ requires-dist = [{ name = "pyvisa", specifier = ">=1.16.0" }]