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.
Files changed (43) hide show
  1. genie_python/.pylintrc +539 -0
  2. genie_python/__init__.py +1 -0
  3. genie_python/block_names.py +123 -0
  4. genie_python/channel_access_exceptions.py +45 -0
  5. genie_python/genie.py +2462 -0
  6. genie_python/genie_advanced.py +418 -0
  7. genie_python/genie_alerts.py +195 -0
  8. genie_python/genie_api_setup.py +451 -0
  9. genie_python/genie_blockserver.py +64 -0
  10. genie_python/genie_cachannel_wrapper.py +545 -0
  11. genie_python/genie_change_cache.py +151 -0
  12. genie_python/genie_dae.py +2218 -0
  13. genie_python/genie_epics_api.py +906 -0
  14. genie_python/genie_experimental_data.py +186 -0
  15. genie_python/genie_logging.py +200 -0
  16. genie_python/genie_p4p_wrapper.py +203 -0
  17. genie_python/genie_plot.py +77 -0
  18. genie_python/genie_pre_post_cmd_manager.py +21 -0
  19. genie_python/genie_pv_connection_protocol.py +36 -0
  20. genie_python/genie_script_checker.py +507 -0
  21. genie_python/genie_script_generator.py +212 -0
  22. genie_python/genie_simulate.py +69 -0
  23. genie_python/genie_simulate_impl.py +1265 -0
  24. genie_python/genie_startup.py +29 -0
  25. genie_python/genie_toggle_settings.py +58 -0
  26. genie_python/genie_wait_for_move.py +154 -0
  27. genie_python/genie_waitfor.py +576 -0
  28. genie_python/matplotlib_backend/__init__.py +0 -0
  29. genie_python/matplotlib_backend/ibex_websocket_backend.py +366 -0
  30. genie_python/mysql_abstraction_layer.py +272 -0
  31. genie_python/run_tests.py +56 -0
  32. genie_python/scanning_instrument_pylint_plugin.py +31 -0
  33. genie_python/typings/CaChannel/CaChannel.pyi +893 -0
  34. genie_python/typings/CaChannel/__init__.pyi +9 -0
  35. genie_python/typings/CaChannel/_version.pyi +6 -0
  36. genie_python/typings/CaChannel/ca.pyi +31 -0
  37. genie_python/utilities.py +406 -0
  38. genie_python/version.py +1 -0
  39. genie_python-15.1.0rc1.dist-info/LICENSE +28 -0
  40. genie_python-15.1.0rc1.dist-info/METADATA +95 -0
  41. genie_python-15.1.0rc1.dist-info/RECORD +43 -0
  42. genie_python-15.1.0rc1.dist-info/WHEEL +5 -0
  43. 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())