genie-python 15.1.0rc1__py3-none-any.whl
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.
- genie_python/.pylintrc +539 -0
- genie_python/__init__.py +1 -0
- genie_python/block_names.py +123 -0
- genie_python/channel_access_exceptions.py +45 -0
- genie_python/genie.py +2462 -0
- genie_python/genie_advanced.py +418 -0
- genie_python/genie_alerts.py +195 -0
- genie_python/genie_api_setup.py +451 -0
- genie_python/genie_blockserver.py +64 -0
- genie_python/genie_cachannel_wrapper.py +545 -0
- genie_python/genie_change_cache.py +151 -0
- genie_python/genie_dae.py +2218 -0
- genie_python/genie_epics_api.py +906 -0
- genie_python/genie_experimental_data.py +186 -0
- genie_python/genie_logging.py +200 -0
- genie_python/genie_p4p_wrapper.py +203 -0
- genie_python/genie_plot.py +77 -0
- genie_python/genie_pre_post_cmd_manager.py +21 -0
- genie_python/genie_pv_connection_protocol.py +36 -0
- genie_python/genie_script_checker.py +507 -0
- genie_python/genie_script_generator.py +212 -0
- genie_python/genie_simulate.py +69 -0
- genie_python/genie_simulate_impl.py +1265 -0
- genie_python/genie_startup.py +29 -0
- genie_python/genie_toggle_settings.py +58 -0
- genie_python/genie_wait_for_move.py +154 -0
- genie_python/genie_waitfor.py +576 -0
- genie_python/matplotlib_backend/__init__.py +0 -0
- genie_python/matplotlib_backend/ibex_websocket_backend.py +366 -0
- genie_python/mysql_abstraction_layer.py +272 -0
- genie_python/run_tests.py +56 -0
- genie_python/scanning_instrument_pylint_plugin.py +31 -0
- genie_python/typings/CaChannel/CaChannel.pyi +893 -0
- genie_python/typings/CaChannel/__init__.pyi +9 -0
- genie_python/typings/CaChannel/_version.pyi +6 -0
- genie_python/typings/CaChannel/ca.pyi +31 -0
- genie_python/utilities.py +406 -0
- genie_python/version.py +1 -0
- genie_python-15.1.0rc1.dist-info/LICENSE +28 -0
- genie_python-15.1.0rc1.dist-info/METADATA +95 -0
- genie_python-15.1.0rc1.dist-info/RECORD +43 -0
- genie_python-15.1.0rc1.dist-info/WHEEL +5 -0
- genie_python-15.1.0rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
from abc import ABCMeta, abstractmethod
|
|
2
|
+
from builtins import object
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from functools import wraps
|
|
5
|
+
from typing import Any, Callable, Type
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class GlobalParamValidationError(Exception):
|
|
9
|
+
"""
|
|
10
|
+
An error to throw when a global parameter is invalid
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CopyPreviousRow(object):
|
|
17
|
+
"""
|
|
18
|
+
Class to use when an action should copy its previous row's value when a new action is added.
|
|
19
|
+
Examples:
|
|
20
|
+
Run with temperature kwarg that should copy whatever the previous value a user entered,
|
|
21
|
+
but defaulting to 1.0 if there are no previous actions.
|
|
22
|
+
>>> @cast_parameters_to(temperature=float, field=float, mevents=int)
|
|
23
|
+
>>> def run(self, temperature=CopyPreviousRow(1.0), field=1.0, mevents=10)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, default_value: bool | int | float | str) -> None:
|
|
27
|
+
self.value = default_value
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ScriptDefinition(object, metaclass=ABCMeta):
|
|
31
|
+
global_params: dict[str, Any] | None
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def run(self, **kwargs) -> str | None: # noqa:ANN003 - abstract, can be overridden to any type in subclass
|
|
35
|
+
"""
|
|
36
|
+
Defines the steps of an action which can be used in the script generator.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
**kwargs: The action parameters and their values in a keyword
|
|
40
|
+
argument format. These must have a default value provided
|
|
41
|
+
as shown in examples e.g. value1: str="1" where "1" is the
|
|
42
|
+
default value.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
None if run runs without exception, otherwise a String containing the error message
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
Run with kwargs that are not cast:
|
|
49
|
+
>>> def run(self, value1="1", value2="2"):
|
|
50
|
+
Typical run with kwargs that are cast to float:
|
|
51
|
+
>>> @cast_parameters_to(temperature=float, field=float, uamps=mytype)
|
|
52
|
+
>>> def run(self, temperature=0.0, field=0.0, uamps=0.0):
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def parameters_valid(self, **kwargs) -> str | None: # noqa:ANN003 - abstract, can be overridden to any type in subclass
|
|
58
|
+
"""
|
|
59
|
+
Contains tests to check whether a given set of inputs is valid
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
**kwargs: The action parameters and their values in a keyword
|
|
63
|
+
argument format. These must have a default value provided
|
|
64
|
+
as shown in examples e.g. value1: str="1" where "1" is the
|
|
65
|
+
default value.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
None if all parameters are valid, otherwise a String containing an error message.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
Parameter check with kwargs that are not cast:
|
|
72
|
+
>>> def parameters_valid(self, value1="1", value2="2"):
|
|
73
|
+
Typical parameter check with kwargs that are cast to float:
|
|
74
|
+
>>> @cast_parameters_to(temperature=float, field=float, uamps=mytype)
|
|
75
|
+
>>> def parameters_valid(self, temperature=0.0, field=0.0, uamps=0.0):
|
|
76
|
+
"""
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
def estimate_time(self, **kwargs) -> float | None: # noqa:ANN003 - abstract, can be overridden to any type in subclass
|
|
80
|
+
"""
|
|
81
|
+
Calculates an estimate in seconds of how long the specified parameters
|
|
82
|
+
will take to execute. The Script Generator only calls this function
|
|
83
|
+
if all parameters are valid (i.e. parameters_valid returns None)
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
**kwargs: The action parameters and their values in a keyword argument format.
|
|
87
|
+
These must have a default value provided as shown in the examples e.g.
|
|
88
|
+
value1: str="1" where "1" is the default value.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
The estimated time in seconds or None to signify "no estimate"
|
|
92
|
+
"""
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
def get_help(self) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Shows a help string with useful information about the script.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
The help string shown in the client.
|
|
101
|
+
"""
|
|
102
|
+
return ""
|
|
103
|
+
|
|
104
|
+
def estimate_custom(self, **kwargs) -> OrderedDict: # noqa:ANN003 - abstract, can be overridden to any type in subclass
|
|
105
|
+
"""
|
|
106
|
+
Create custom estimates that display how many events are in the script.
|
|
107
|
+
This function must return an OrderedDict with string keys and string values.
|
|
108
|
+
The keys are the event names and will be displayed as columns in the client.
|
|
109
|
+
The Script Generator only calls this function if all parameters are valid
|
|
110
|
+
(i.e. parameters_valid returns None)
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
**kwargs: The action parameters and their values in a keyword argument format.
|
|
114
|
+
These must have a default value provided as shown in the examples e.g.
|
|
115
|
+
value1: str="1" where "1" is the default value.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
An ordered dictionary
|
|
119
|
+
|
|
120
|
+
Examples:
|
|
121
|
+
Custom estimation with kwargs that are not cast:
|
|
122
|
+
>>> def estimate_custom(self, value1="1", value2="2"):
|
|
123
|
+
>>> ...
|
|
124
|
+
>>> # Values can be numeric or a descriptive string.
|
|
125
|
+
>>> return OrderedDict([("custom1", "42"), ("custom2", "Unstable")])
|
|
126
|
+
"""
|
|
127
|
+
return OrderedDict()
|
|
128
|
+
|
|
129
|
+
def get_file(self) -> str:
|
|
130
|
+
return __file__
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def cast_parameters_to(
|
|
134
|
+
*args_casts: Type | Callable, **keyword_casts: Type | Callable
|
|
135
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
136
|
+
"""
|
|
137
|
+
A decorator to cast args and kwargs using the passed casters.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
*args_casts: An ordered list of casters to use to cast args.
|
|
141
|
+
**keyword_casts: A dictionary of casters to use to cast kwargs.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
return value of wrapped function or a string containing an error message if an error occurs.
|
|
145
|
+
|
|
146
|
+
Examples:
|
|
147
|
+
Cast run parameters (run only takes kwargs currently):
|
|
148
|
+
>>> @cast_parameters_to(kwarg1=int, kwarg2=custom_caster, kwarg3=float, kwarg4=str)
|
|
149
|
+
>>> def run(kwarg1="10", kwarg2="keyword", kwarg3="1.0", kwarg4="mystr")
|
|
150
|
+
Cast parameters_valid parameters (parameters_valid only takes kwargs currently):
|
|
151
|
+
>>> @cast_parameters_to(kwarg1=int, kwarg2=custom_caster, kwarg3=float, kwarg4=str)
|
|
152
|
+
>>> def do_run(kwarg1="10", kwarg2="keyword", kwarg3="1.0", kwarg4="mystr")
|
|
153
|
+
Cast a subset of parameters:
|
|
154
|
+
>>> @cast_parameters_to(kwarg1=int, kwarg3=float)
|
|
155
|
+
>>> def do_run(kwarg1="10", kwarg2="keyword", kwarg3="1.0", kwarg4="mystr")
|
|
156
|
+
Error string returned when more args_casts than args:
|
|
157
|
+
>>> @cast_parameters_to(int, custom_caster, float, str)
|
|
158
|
+
>>> def func(arg1, arg2)
|
|
159
|
+
>>> Returned: There are more casters for arguments than arguments
|
|
160
|
+
Error string returnd when keyword_casts contains keys not present in kwargs:
|
|
161
|
+
>>> @cast_parameters_to(kwarg1=int, kwarg2=custom_caster, kwargs3=float, kwarg4=str)
|
|
162
|
+
>>> def func(kwarg1="10", kwarg2="20")
|
|
163
|
+
>>> Returned: There are more casters for arguments than arguments
|
|
164
|
+
Error string returned when cannot cast:
|
|
165
|
+
>>> @cast_parameters_to(int)
|
|
166
|
+
>>> def run("mystr")
|
|
167
|
+
>>> Returned: "Cannot convert mystr from string to int"
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
171
|
+
@wraps(func)
|
|
172
|
+
def wrapper(self: ScriptDefinition, *args: Any, **kwargs: Any) -> Any:
|
|
173
|
+
# Check for incorrect keyword_casts and args_casts
|
|
174
|
+
if not set(keyword_casts.keys()).issubset(set(kwargs.keys())):
|
|
175
|
+
return (
|
|
176
|
+
"Keyword argument casters contains keys"
|
|
177
|
+
" that are not present in keyword arguments"
|
|
178
|
+
)
|
|
179
|
+
if len(args_casts) > len(args):
|
|
180
|
+
return "There are more casters for arguments than arguments"
|
|
181
|
+
# Cast kwargs
|
|
182
|
+
casting_failures = ""
|
|
183
|
+
cast_kwargs = {}
|
|
184
|
+
for k, v in kwargs.items():
|
|
185
|
+
try:
|
|
186
|
+
cast_kwargs[k] = keyword_casts[k](v)
|
|
187
|
+
except ValueError as e:
|
|
188
|
+
if str(e) != "":
|
|
189
|
+
casting_failures += str(e) + "\n"
|
|
190
|
+
else:
|
|
191
|
+
casting_failures += "Cannot convert {} from string to {}\n".format(
|
|
192
|
+
str(v), str(keyword_casts[k].__name__)
|
|
193
|
+
)
|
|
194
|
+
# Cast args
|
|
195
|
+
cast_args = []
|
|
196
|
+
for i in range(len(args_casts)):
|
|
197
|
+
try:
|
|
198
|
+
cast_args.append(args_casts[i](args[i]))
|
|
199
|
+
except ValueError as e:
|
|
200
|
+
if str(e) != "":
|
|
201
|
+
casting_failures += str(e) + "\n"
|
|
202
|
+
else:
|
|
203
|
+
casting_failures += "Cannot convert {} from string to {}\n".format(
|
|
204
|
+
args[i], str(args_casts[i].__name__)
|
|
205
|
+
)
|
|
206
|
+
if casting_failures != "":
|
|
207
|
+
return casting_failures
|
|
208
|
+
return func(self, *cast_args, **cast_kwargs)
|
|
209
|
+
|
|
210
|
+
return wrapper
|
|
211
|
+
|
|
212
|
+
return decorator
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import absolute_import, print_function
|
|
2
|
+
|
|
3
|
+
from builtins import object
|
|
4
|
+
from collections import OrderedDict
|
|
5
|
+
|
|
6
|
+
import genie_python.genie_api_setup
|
|
7
|
+
import genie_python.genie_simulate_impl as genie_sim
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def in_sim_mode():
|
|
11
|
+
"""
|
|
12
|
+
Get whether genie_python is in simulation mode.
|
|
13
|
+
|
|
14
|
+
Returns (bool): True if in simulation mode, False otherwise
|
|
15
|
+
"""
|
|
16
|
+
from genie_python.genie import _genie_api
|
|
17
|
+
|
|
18
|
+
return isinstance(_genie_api, genie_sim.API)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Simulate(object):
|
|
22
|
+
"""A context manager that will put genie_python into simulation mode and out again.
|
|
23
|
+
For example:
|
|
24
|
+
>>> with g.sim.Simulate():
|
|
25
|
+
>>> g.begin()
|
|
26
|
+
>>> g.cset("my_block", 10)
|
|
27
|
+
>>> g.end()
|
|
28
|
+
Will run only print the results of the g. commands and not change the current experiment.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, populate_with_current_blocks=True, initial_block_values={}):
|
|
32
|
+
"""
|
|
33
|
+
Create the context manager.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
populate_with_current_blocks(bool): if True the simulated environment will be populated with the current blocks
|
|
37
|
+
initial_block_values(dict): If not empty, blocks will be set initially to these values; can be plain values or cget results
|
|
38
|
+
"""
|
|
39
|
+
from genie_python import genie
|
|
40
|
+
from genie_python.genie import _genie_api
|
|
41
|
+
|
|
42
|
+
self.genie = genie
|
|
43
|
+
self.previous_api = _genie_api
|
|
44
|
+
self.new_api = genie_sim.API(None, None, populate_with_current_blocks)
|
|
45
|
+
if populate_with_current_blocks:
|
|
46
|
+
dummy_values = ["INITIAL_VALUE"] * len(self.previous_api.get_block_names())
|
|
47
|
+
self.new_api.set_multiple_blocks(self.previous_api.get_block_names(), dummy_values)
|
|
48
|
+
for ky, vl in initial_block_values.items():
|
|
49
|
+
if isinstance(vl, OrderedDict):
|
|
50
|
+
self.new_api.set_block_value(
|
|
51
|
+
ky, vl["value"], vl["runcontrol"], vl["lowlimit"], vl["highlimit"]
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
self.new_api.set_block_value(ky, vl)
|
|
55
|
+
|
|
56
|
+
def __enter__(self):
|
|
57
|
+
print("Entering genie_python simulation mode")
|
|
58
|
+
print(
|
|
59
|
+
"For more information on simulation mode see https://github.com/ISISComputingGroup/ibex_user_manual/wiki/Simulating-Scripts"
|
|
60
|
+
)
|
|
61
|
+
genie_python.genie_api_setup._exceptions_raised = True
|
|
62
|
+
self.genie._genie_api = self.new_api
|
|
63
|
+
self.previous_api.logger.set_sim_mode(in_sim_mode())
|
|
64
|
+
|
|
65
|
+
def __exit__(self, *args):
|
|
66
|
+
print("Exiting genie_python simulation mode")
|
|
67
|
+
genie_python.genie_api_setup._exceptions_raised = False
|
|
68
|
+
self.genie._genie_api = self.previous_api
|
|
69
|
+
self.genie._genie_api.logger.set_sim_mode(in_sim_mode())
|