Public Access
add type hints to Experiment.py and dac.py, set up pyrefly as dev dependency
This commit is contained in:
1 parent
f9d8de7697
commit
efb01250c8
4 files changed
+85
-44
No files matched your search
@@ -39,6 +39,9 @@ maintainers = [
|
||||
[project.scripts]
|
||||
DAMARIS3 = "damaris.__main__:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = ["pyrefly"]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
@@ -50,6 +53,15 @@ version = {attr = "damaris.__version__"}
|
||||
|
||||
[tool.setuptools.data-files]
|
||||
"share/python3-damaris/images" = ["src/damaris/gui/DAMARIS3.png", "src/damaris/gui/DAMARIS3.ico"]
|
||||
|
||||
[tool.pyrefly]
|
||||
project-includes = [
|
||||
"src/damaris/experiments/Experiment.py",
|
||||
"src/damaris/experiments/dac.py",
|
||||
]
|
||||
search-path = ["src"]
|
||||
python-version = "3.11"
|
||||
python-platform = "linux"
|
||||
#"share/python3-damaris/doc" = ["doc/index.html"]
|
||||
#"share/python3-damaris/doc/reference-html" = ["doc/reference-html/*"]
|
||||
#"share/python3-damaris/doc/tutorial-html" = ["doc/tutorial-html/*"]
|
||||
|
||||
@@ -3,20 +3,20 @@ import types
|
||||
import numpy
|
||||
|
||||
class StateBase(object):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
def to_xml(self, indent = ""):
|
||||
def to_xml(self, indent: str = "") -> str:
|
||||
return indent + "<!-- " + repr(self) + " -->"
|
||||
|
||||
class StateSimple(StateBase):
|
||||
def __init__(self, time, content=None):
|
||||
def __init__(self, time: float, content: object | None = None) -> None:
|
||||
super(StateSimple, self).__init__()
|
||||
if time < 0:
|
||||
raise AssertionError("time for state is negative!")
|
||||
self.time = time
|
||||
self.content = content
|
||||
|
||||
def to_xml(self, indent = ""):
|
||||
def to_xml(self, indent: str = "") -> str:
|
||||
s = indent + '<state time="%s"' % repr(self.time)
|
||||
if self.content is None:
|
||||
return s + '/>\n'
|
||||
@@ -24,14 +24,14 @@ class StateSimple(StateBase):
|
||||
s += indent + ' ' + str(self.content) + '\n'
|
||||
s += indent + '</state>\n'
|
||||
return s
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return 'StateSimple(%s, %s)' % (self.time, repr(self.content))
|
||||
|
||||
class StateList(StateBase):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super(StateList, self).__init__()
|
||||
self.list = []
|
||||
def to_xml(self, indent = " "):
|
||||
self.list: list[object] = []
|
||||
def to_xml(self, indent: str = " ") -> str:
|
||||
s = ""
|
||||
for k in self.list:
|
||||
if hasattr(k, "to_xml"):
|
||||
@@ -39,21 +39,21 @@ class StateList(StateBase):
|
||||
else:
|
||||
s += indent + str(k)
|
||||
return s
|
||||
def append(self, val):
|
||||
def append(self, val: object) -> None:
|
||||
self.list.append(val)
|
||||
|
||||
|
||||
class StateLoop(StateList):
|
||||
"""Represents a loop in the state tree"""
|
||||
def __init__(self, repeat):
|
||||
def __init__(self, repeat: int) -> None:
|
||||
super(StateLoop, self).__init__()
|
||||
self.repeat = repeat
|
||||
def to_xml(self, indent = ""):
|
||||
def to_xml(self, indent: str = "") -> str:
|
||||
s = indent + ('<sequent repeat="%d">\n' % self.repeat)
|
||||
s += super(StateLoop, self).to_xml(indent + " ")
|
||||
s += indent + '</sequent>\n'
|
||||
return s
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return 'StateLoop(repeat=%d, %s)' \
|
||||
% (self.repeat, repr(self.list))
|
||||
|
||||
@@ -78,32 +78,32 @@ class Experiment:
|
||||
:param list rf_gates: list of rf gates ttl channels len(rf_gates) == len(rf_sources)
|
||||
|
||||
"""
|
||||
job_id = 0
|
||||
job_id: int = 0
|
||||
|
||||
def __init__(self, gating=None, rf_sources=[], rf_gates=[]):
|
||||
self.job_id = Experiment.job_id
|
||||
def __init__(self, gating: float | None = None, rf_sources: list[int] = [], rf_gates: list[int] = []) -> None:
|
||||
self.job_id: int = Experiment.job_id
|
||||
Experiment.job_id += 1
|
||||
|
||||
self.state_list = StateList()
|
||||
self.list_stack = []
|
||||
self.description = { }
|
||||
self.gating = gating
|
||||
self.state_list: StateList = StateList()
|
||||
self.list_stack: list[StateList] = []
|
||||
self.description: dict[str, object] = { }
|
||||
self.gating: float | None = gating
|
||||
assert type(rf_sources) == type(list()), "rf_sources needs to be a list with the channels"
|
||||
assert type(rf_gates) == type(list()), "rf_gates needs to be a list with the channels"
|
||||
assert len(rf_gates) == len(rf_sources), "rf_sources and rf_gates must have equal number of entries"
|
||||
self.rf_sources = rf_sources
|
||||
self.rf_gates = rf_gates
|
||||
self.rf_sources: list[int] = rf_sources
|
||||
self.rf_gates: list[int] = rf_gates
|
||||
|
||||
#for tracking the experiment length:
|
||||
#because loops are possible we need to track the length for each loop level
|
||||
self.total_time=[0.0]
|
||||
self.total_time: list[float] = [0.0]
|
||||
|
||||
#and we need to know the number of iterations of the loops to multiply the state.
|
||||
self.loop_iterations=[1]
|
||||
self.loop_iterations: list[int] = [1]
|
||||
|
||||
# Commands -------------------------------------------------------------------------------------
|
||||
|
||||
def ttl_pulse(self, length, channel = None, value = None):
|
||||
def ttl_pulse(self, length: float, channel: int | None = None, value: int | None = None) -> None:
|
||||
"""
|
||||
Creates a state with length **length** and switches requested bits of the pulse programmer to HIGH.
|
||||
|
||||
@@ -151,7 +151,7 @@ class Experiment:
|
||||
self.total_time[-1] += length
|
||||
|
||||
## Same as ttl_pulse, but no *channel* keyword
|
||||
def ttls(self, length = None, value = None):
|
||||
def ttls(self, length: float | None = None, value: int | None = None) -> None:
|
||||
"""
|
||||
Same as ttl_pulse, but no *channel* keyword
|
||||
|
||||
@@ -159,6 +159,7 @@ class Experiment:
|
||||
:param int value: lines to set (integer)
|
||||
:return:
|
||||
"""
|
||||
assert value is not None, "ttls needs an integer value"
|
||||
the_value=int(value)
|
||||
s_content = '<ttlout value="0x%06x"/>' % the_value
|
||||
if length is not None:
|
||||
@@ -168,7 +169,7 @@ class Experiment:
|
||||
self.state_list.append(s_content)
|
||||
|
||||
|
||||
def rf_pulse(self, length=None, phase=0, source=0):
|
||||
def rf_pulse(self, length: float | None = None, phase: float = 0, source: int = 0) -> None:
|
||||
"""
|
||||
Make an rf pulse, including gating and phase switching. Only possible if Experiment is configured.
|
||||
|
||||
@@ -183,7 +184,7 @@ class Experiment:
|
||||
self.ttls(length=length, value=self.rf_gates[source]+self.rf_sources[source])
|
||||
|
||||
## Beginning of a new state
|
||||
def state_start(self, time):
|
||||
def state_start(self, time: float) -> None:
|
||||
"""
|
||||
Starts a state in the pulse programs with duration *time*.
|
||||
This must be closed with :func:`state_end`.
|
||||
@@ -194,13 +195,13 @@ class Experiment:
|
||||
self.total_time[-1] += time
|
||||
|
||||
## End of *state_start*
|
||||
def state_end(self):
|
||||
def state_end(self) -> None:
|
||||
"""
|
||||
Closes a previous :func:`state_start`
|
||||
"""
|
||||
self.state_list.append('</state>\n')
|
||||
|
||||
def wait(self, time, ttls=None, gating=False):
|
||||
def wait(self, time: float, ttls: int | None = None, gating: bool = False) -> None:
|
||||
"""
|
||||
Waits for a specified amount of time without performing any actions.
|
||||
|
||||
@@ -241,6 +242,7 @@ class Experiment:
|
||||
|
||||
"""
|
||||
if gating:
|
||||
assert self.gating is not None, "gating time must be set for gating=True"
|
||||
time -= self.gating
|
||||
if ttls is not None:
|
||||
s_content = '<ttlout value="0x%06x"/>' % ttls
|
||||
@@ -251,7 +253,7 @@ class Experiment:
|
||||
self.total_time[-1] += time
|
||||
|
||||
|
||||
def record(self, samples, frequency, timelength=None, sensitivity = None, ttls=None, channels = 3, offset = None, impedance = None):
|
||||
def record(self, samples: int, frequency: float, timelength: float | None = None, sensitivity: float | list[float] | None = None, ttls: int | None = None, channels: int = 3, offset: int | list[int] | None = None, impedance: float | list[float] | None = None) -> None:
|
||||
"""
|
||||
Records data with a given number of samples, sampling frequency, and sensitivity.
|
||||
This command starts data acquisition from the ADC (Analog-to-Digital Converter).
|
||||
@@ -365,7 +367,7 @@ class Experiment:
|
||||
|
||||
## Create a loop on the pulse programmer. Loop contents can not change inside the loop.
|
||||
# @params iterations Number of loop iterations
|
||||
def loop_start(self, iterations):
|
||||
def loop_start(self, iterations: int) -> None:
|
||||
"""
|
||||
creates a loop of given number of iterations and has to be closed by loop_end().
|
||||
Commands inside the loop can not change, i.e., the parameters are the same for each loop run.
|
||||
@@ -384,7 +386,7 @@ class Experiment:
|
||||
self.loop_iterations.append(iterations)
|
||||
|
||||
## End loop state
|
||||
def loop_end(self):
|
||||
def loop_end(self) -> None:
|
||||
"""
|
||||
Closes a l:func:`loop_start` statement.
|
||||
"""
|
||||
@@ -396,7 +398,7 @@ class Experiment:
|
||||
self.total_time[-1] += looptime*loopiterations
|
||||
|
||||
|
||||
def set_frequency(self, frequency, phase, ttls=0):
|
||||
def set_frequency(self, frequency: float, phase: float, ttls: int = 0) -> None:
|
||||
"""
|
||||
Sets the frequency and phase of the frequency source and optionally further channels.
|
||||
The state length is 2 µs. Stabilisation time depends on RF source.
|
||||
@@ -412,7 +414,7 @@ class Experiment:
|
||||
|
||||
self.total_time[-1] += 2e-6
|
||||
|
||||
def set_pfg(self, dac_value=None, length=None, shape=('rec', 0), trigger=4, is_seq=False):
|
||||
def set_pfg(self, dac_value: int | None = None, length: float | None = None, shape: tuple[str, float] = ('rec', 0), trigger: int = 4, is_seq: bool = False) -> None:
|
||||
"""
|
||||
This sets the value for the PFG, it also sets it back to dac_value=0 automatically.
|
||||
If you don't wish to do so (i.e. line shapes) set is_seq=1
|
||||
@@ -480,7 +482,7 @@ class Experiment:
|
||||
else: # don't know what to do
|
||||
raise SyntaxError("form is unknown: %s"%form)
|
||||
|
||||
def set_dac(self, dac_value, dac_id=1, length=None, is_seq=False, ttls=0):
|
||||
def set_dac(self, dac_value: int, dac_id: int = 1, length: float | None = None, is_seq: bool = False, ttls: int = 0) -> None:
|
||||
"""
|
||||
Sets the value for the DAC (Digital-to-Analog Converter) and optionally additional TTL lines.
|
||||
This command is used to control analog output signals, such as pulsed field gradients.
|
||||
@@ -544,7 +546,7 @@ class Experiment:
|
||||
|
||||
self.total_time[-1] += 42*9e-8
|
||||
|
||||
def set_phase(self, phase, ttls=0):
|
||||
def set_phase(self, phase: float, ttls: int = 0) -> None:
|
||||
"""
|
||||
Sets the phase of the RF source to the specified value.
|
||||
|
||||
@@ -589,7 +591,7 @@ class Experiment:
|
||||
self.total_time[-1] += 0.5e-6
|
||||
|
||||
|
||||
def set_description(self, key, value):
|
||||
def set_description(self, key: str, value: object) -> None:
|
||||
"""
|
||||
Sets a description key-value pair in the experiment description dictionary.
|
||||
|
||||
@@ -629,7 +631,7 @@ class Experiment:
|
||||
print('Warning: Overwriting existing description "%s" = "%s" with "%s"' % (key, self.description[key], value))
|
||||
self.description[key] = value
|
||||
|
||||
def set_pts_local(self):
|
||||
def set_pts_local(self) -> None:
|
||||
"""
|
||||
Sets the PTS310/PTS500 frequency source to local mode.
|
||||
State length is 2 µs.
|
||||
@@ -653,7 +655,7 @@ class Experiment:
|
||||
return self.job_id
|
||||
|
||||
|
||||
def write_xml_string(self):
|
||||
def write_xml_string(self) -> str:
|
||||
"""
|
||||
Returns the current program as a string
|
||||
|
||||
@@ -706,14 +708,14 @@ class Experiment:
|
||||
|
||||
return xml_string
|
||||
|
||||
def write_quit_job(self):
|
||||
def write_quit_job(self) -> str:
|
||||
"""
|
||||
Returns a xml quit-job
|
||||
:returns: XML quit-job
|
||||
"""
|
||||
return '<?xml version="1.0" encoding="ISO-8859-1"?>\n<quit/>'
|
||||
|
||||
def get_length(self):
|
||||
def get_length(self) -> float:
|
||||
timelength = 0.0
|
||||
#calculate the correct timelength also for unclosed loops, if there is no unclosed loop
|
||||
#the timelength of this experiment is self.total_time[-1].
|
||||
@@ -723,13 +725,13 @@ class Experiment:
|
||||
return timelength
|
||||
|
||||
class Quit(Experiment):
|
||||
def write_xml_string(self):
|
||||
def write_xml_string(self) -> str:
|
||||
return '<?xml version="1.0" encoding="ISO-8859-1"?>\n<quit no="%d"/>'%self.job_id
|
||||
|
||||
|
||||
# /Public Methods ------------------------------------------------------------------------------
|
||||
|
||||
def self_test():
|
||||
def self_test() -> None:
|
||||
e = Experiment()
|
||||
e.set_description("key", "value")
|
||||
e.set_frequency(85e6, 90, ttls=16)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"""
|
||||
This module holds everything connected with the DAC and PFG
|
||||
"""
|
||||
def conv(I_out=0):
|
||||
def conv(I_out: float = 0) -> int:
|
||||
"""
|
||||
converts the demanded Output current in Integer
|
||||
"""
|
||||
|
||||
@@ -938,6 +938,25 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyrefly"
|
||||
version = "1.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b3/3e/ea6893be167fa14307d7f9a924bed9ecbbbd91b01953890b9b3c58ed5359/pyrefly-1.4.0.tar.gz", hash = "sha256:bb57c004a4842cfe93f93aebb5203ca6209a5f0c8bda47e8bc289e70940fd910", size = 6962062, upload-time = "2026-10-15T16:54:11.819Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/17/dfce6611acc00cb26667e5e1011438cc510f3067f961e0f07f7a0c68f416/pyrefly-1.4.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:460cec39bc8743915e9c2c8c10ba926ad0b29b099d89c1859fb97e0059f42fa7", size = 15705624, upload-time = "2026-10-15T16:53:43.412Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/78/a7b96442123fa6ed733de0d1ea933e35d6fc6b7c9cf16e05279abb493493/pyrefly-1.4.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5a6370d686b6cbbac8869832f09a52012888371956fbc68d446a349bc85ccd43", size = 14978669, upload-time = "2026-10-15T16:53:46.546Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/97/dfcfec6a9d8948ab4b2746f7e87558a82bffabb7a54c22e7d3ce4bdc1932/pyrefly-1.4.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f1b16923a6583a6764e8aec07787e2ef4df644c7030294cba71339783a9451c", size = 15438858, upload-time = "2026-10-15T16:53:48.904Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/12/6fa414aa87e398d6ddc7145a5d993b0975fc3511198dbb72c47873653ab6/pyrefly-1.4.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:688ad4cb4d6e711d67026fdcfb37b599f86061efe11ba5704287330e7041a69e", size = 16852241, upload-time = "2026-10-15T16:53:51.496Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/73/2d7312262cf6481d6ad46eed55b8f2592c3cff60f95cc2f30a114cd1484e/pyrefly-1.4.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5f3c9dddb6f3128beb49cf4e0f5cb88d4d17f039008d8e0c2be653966acd234", size = 16751917, upload-time = "2026-10-15T16:53:54.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/65/b44a1cb23667bcbcdc88558cbef79fa9e07a1152c2a1da148036b1a2e0d1/pyrefly-1.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6951f51687304caebfedf13dd1a943aeafdbc95abcc4e24a683b97467a77007", size = 16066345, upload-time = "2026-10-15T16:53:57.436Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/07/7ca6ff0c53e3a90ecdab05790d33f430fca5c48687613a0b182744166d98/pyrefly-1.4.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:838de4d4a8b9b8ed39bedd0b8b55629c69661d73a6fa3a3a4adff24b9dbeb399", size = 15461223, upload-time = "2026-10-15T16:54:00.364Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/be/ec7b2f38a898ce5b2219dda730e87d31fc8cfb2108a3d5844f9d590f1281/pyrefly-1.4.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:afb9ce2e0ae3e6106fb45f6d47536ac92b6423e601e08401cdefa850066444f5", size = 16119099, upload-time = "2026-10-15T16:54:02.664Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/16/1b9549168b38a575d9c168e17b4b4ee30028d602ec0f7b07c198ef265dbe/pyrefly-1.4.0-py3-none-win32.whl", hash = "sha256:839db536d0ac29f1b23e2d974fb911075c2283e3e623755c45d826aafac175bc", size = 14858880, upload-time = "2026-10-15T16:54:05.114Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/02/18f075d4de0e255f184f42fc28c1f0ecc9f49dd528678479fc90cf12246c/pyrefly-1.4.0-py3-none-win_amd64.whl", hash = "sha256:7aff37c2b711c8240ed650da0c6148237b327bf7e5dfacee65884f1adea22305", size = 15726220, upload-time = "2026-10-15T16:54:07.452Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/62/92947076681550904c72a9dd03b24e92694ede9a48548f5e487c849e66ea/pyrefly-1.4.0-py3-none-win_arm64.whl", hash = "sha256:88879f0cb749e5fea81d9ff4c2d5431a70349c458bcdf0b61de72c79214d90a5", size = 14943690, upload-time = "2026-10-15T16:54:09.689Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyserial"
|
||||
version = "3.5"
|
||||
@@ -976,6 +995,11 @@ dependencies = [
|
||||
{ name = "tables" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "pyrefly" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "matplotlib", specifier = ">=1.4.1,<=3.6" },
|
||||
@@ -990,6 +1014,9 @@ requires-dist = [
|
||||
{ name = "tables", specifier = ">=3.1.1" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "pyrefly" }]
|
||||
|
||||
[[package]]
|
||||
name = "pyxdg"
|
||||
version = "0.28"
|
||||
|
||||
Reference in new issue
Block a user