genie-python 25.2.2__tar.gz → 25.8.0__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 (90) hide show
  1. {genie_python-25.2.2 → genie_python-25.8.0}/.github/workflows/release.yml +1 -1
  2. {genie_python-25.2.2 → genie_python-25.8.0}/PKG-INFO +1 -2
  3. {genie_python-25.2.2 → genie_python-25.8.0}/pyproject.toml +1 -1
  4. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/_version.py +16 -3
  5. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/block_names.py +33 -21
  6. genie_python-25.8.0/src/genie_python/channel_access_exceptions.py +44 -0
  7. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie.py +214 -124
  8. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_advanced.py +25 -17
  9. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_alerts.py +24 -15
  10. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_blockserver.py +18 -10
  11. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_cachannel_wrapper.py +4 -4
  12. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_dae.py +29 -9
  13. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_epics_api.py +106 -43
  14. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_p4p_wrapper.py +2 -2
  15. genie_python-25.8.0/src/genie_python/genie_pre_post_cmd_manager.py +45 -0
  16. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_pv_connection_protocol.py +3 -3
  17. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_script_checker.py +24 -13
  18. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_simulate_impl.py +71 -24
  19. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_wait_for_move.py +35 -18
  20. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_waitfor.py +6 -7
  21. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/matplotlib_backend/ibex_websocket_backend.py +87 -55
  22. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/mysql_abstraction_layer.py +3 -1
  23. genie_python-25.8.0/src/genie_python/scanning_instrument_pylint_plugin.py +53 -0
  24. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/utilities.py +71 -47
  25. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python.egg-info/PKG-INFO +1 -2
  26. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python.egg-info/SOURCES.txt +1 -0
  27. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python.egg-info/requires.txt +0 -1
  28. {genie_python-25.2.2 → genie_python-25.8.0}/tests/py3_test_genie_experimental_data.py +1 -1
  29. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_block_names.py +2 -2
  30. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie.py +17 -1
  31. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_alerts.py +1 -2
  32. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_api_setup.py +1 -1
  33. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_blockserver_tests.py +1 -2
  34. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_dae.py +84 -10
  35. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_epics_api.py +1 -1
  36. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_matplotlib_backend.py +2 -3
  37. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_mysql_abstraction_layer.py +1 -2
  38. genie_python-25.8.0/tests/test_scripts/test.py +2 -0
  39. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_simulation.py +1 -1
  40. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_utilities.py +1 -2
  41. genie_python-25.2.2/src/genie_python/channel_access_exceptions.py +0 -45
  42. genie_python-25.2.2/src/genie_python/genie_pre_post_cmd_manager.py +0 -21
  43. genie_python-25.2.2/src/genie_python/scanning_instrument_pylint_plugin.py +0 -31
  44. {genie_python-25.2.2 → genie_python-25.8.0}/.git-blame-ignore-revs +0 -0
  45. {genie_python-25.2.2 → genie_python-25.8.0}/.gitattributes +0 -0
  46. {genie_python-25.2.2 → genie_python-25.8.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  47. {genie_python-25.2.2 → genie_python-25.8.0}/.github/dependabot.yml +0 -0
  48. {genie_python-25.2.2 → genie_python-25.8.0}/.github/workflows/documentation.yml +0 -0
  49. {genie_python-25.2.2 → genie_python-25.8.0}/.github/workflows/lint-and-test-nightly.yml +0 -0
  50. {genie_python-25.2.2 → genie_python-25.8.0}/.github/workflows/lint_and_test.yml +0 -0
  51. {genie_python-25.2.2 → genie_python-25.8.0}/.gitignore +0 -0
  52. {genie_python-25.2.2 → genie_python-25.8.0}/LICENSE +0 -0
  53. {genie_python-25.2.2 → genie_python-25.8.0}/README.md +0 -0
  54. {genie_python-25.2.2 → genie_python-25.8.0}/doc/conf.py +0 -0
  55. {genie_python-25.2.2 → genie_python-25.8.0}/doc/genie_python.rst +0 -0
  56. {genie_python-25.2.2 → genie_python-25.8.0}/ruff.toml +0 -0
  57. {genie_python-25.2.2 → genie_python-25.8.0}/setup.cfg +0 -0
  58. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/.pylintrc +0 -0
  59. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/__init__.py +0 -0
  60. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_api_setup.py +0 -0
  61. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_change_cache.py +0 -0
  62. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_experimental_data.py +0 -0
  63. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_logging.py +0 -0
  64. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_plot.py +0 -0
  65. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_script_generator.py +0 -0
  66. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_simulate.py +0 -0
  67. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_startup.py +0 -0
  68. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/genie_toggle_settings.py +0 -0
  69. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/matplotlib_backend/__init__.py +0 -0
  70. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/testing_utils/__init__.py +0 -0
  71. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/testing_utils/script_checker.py +0 -0
  72. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/typings/CaChannel/CaChannel.pyi +0 -0
  73. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/typings/CaChannel/__init__.pyi +0 -0
  74. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/typings/CaChannel/_version.pyi +0 -0
  75. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/typings/CaChannel/ca.pyi +0 -0
  76. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python/version.py +0 -0
  77. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python.egg-info/dependency_links.txt +0 -0
  78. {genie_python-25.2.2 → genie_python-25.8.0}/src/genie_python.egg-info/top_level.txt +0 -0
  79. {genie_python-25.2.2 → genie_python-25.8.0}/tests/__init__.py +0 -0
  80. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_change_cache.py +0 -0
  81. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_wait_for_move.py +0 -0
  82. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_genie_waitfor.py +0 -0
  83. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_script_checker.py +0 -0
  84. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_script_generator.py +0 -0
  85. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_scripts/error.py +0 -0
  86. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_scripts/error_for_script_checker.py +0 -0
  87. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_scripts/valid.py +0 -0
  88. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_scripts/valid_python_2.py +0 -0
  89. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_scripts/valid_to_import.py +0 -0
  90. {genie_python-25.2.2 → genie_python-25.8.0}/tests/test_utils_with_unicode_literals.py +0 -0
@@ -67,7 +67,7 @@ jobs:
67
67
  name: python-package-distributions
68
68
  path: dist/
69
69
  - name: Sign the dists with Sigstore
70
- uses: sigstore/gh-action-sigstore-python@v3.0.0
70
+ uses: sigstore/gh-action-sigstore-python@v3.0.1
71
71
  with:
72
72
  inputs: >-
73
73
  ./dist/*.tar.gz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genie_python
3
- Version: 25.2.2
3
+ Version: 25.8.0
4
4
  Summary: Instrument control & scripting for the ISIS Neutron & Muon source
5
5
  Author-email: ISIS Experiment Controls <ISISExperimentControls@stfc.ac.uk>
6
6
  Maintainer-email: ISIS Experiment Controls <ISISExperimentControls@stfc.ac.uk>
@@ -36,7 +36,6 @@ Requires-Dist: myst_parser; extra == "doc"
36
36
  Requires-Dist: sphinx-autobuild; extra == "doc"
37
37
  Provides-Extra: dev
38
38
  Requires-Dist: genie_python[doc,plot]; extra == "dev"
39
- Requires-Dist: mock; extra == "dev"
40
39
  Requires-Dist: parameterized; extra == "dev"
41
40
  Requires-Dist: pyhamcrest; extra == "dev"
42
41
  Requires-Dist: pytest; extra == "dev"
@@ -72,7 +72,6 @@ doc = [
72
72
 
73
73
  dev = [
74
74
  "genie_python[plot,doc]",
75
- "mock",
76
75
  "parameterized",
77
76
  "pyhamcrest",
78
77
  "pytest",
@@ -118,6 +117,7 @@ reportUnnecessaryIsInstance = true
118
117
  reportUntypedBaseClass = true
119
118
  reportUntypedClassDecorator = true
120
119
  reportUntypedFunctionDecorator = true
120
+ stubPath = "src/genie_python/typings"
121
121
 
122
122
  [tool.setuptools_scm]
123
123
  version_file = "src/genie_python/_version.py"
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '25.2.2'
21
- __version_tuple__ = version_tuple = (25, 2, 2)
31
+ __version__ = version = '25.8.0'
32
+ __version_tuple__ = version_tuple = (25, 8, 0)
33
+
34
+ __commit_id__ = commit_id = 'g1fca963b3'
@@ -1,6 +1,7 @@
1
1
  import zlib
2
2
  from keyword import iskeyword
3
3
  from threading import RLock, Timer
4
+ from typing import TYPE_CHECKING, Optional
4
5
 
5
6
  from .channel_access_exceptions import UnableToConnectToPVException
6
7
  from .genie_blockserver import BLOCK_SERVER_PREFIX, PV_BLOCK_NAMES
@@ -9,6 +10,9 @@ from .utilities import dehex_decompress_and_dejson
9
10
 
10
11
  DELAY_BEFORE_RETRYING_BLOCK_NAMES_PV_ON_FAIL = 30.0
11
12
 
13
+ if TYPE_CHECKING:
14
+ from genie_python.genie import PVValue
15
+
12
16
 
13
17
  class BlockNamesManager:
14
18
  """
@@ -17,23 +21,24 @@ class BlockNamesManager:
17
21
 
18
22
  def __init__(
19
23
  self,
20
- block_names,
21
- delay_before_retry_add_monitor=DELAY_BEFORE_RETRYING_BLOCK_NAMES_PV_ON_FAIL,
22
- ):
24
+ block_names: "BlockNames",
25
+ delay_before_retry_add_monitor: float = DELAY_BEFORE_RETRYING_BLOCK_NAMES_PV_ON_FAIL,
26
+ ) -> None:
23
27
  """
24
28
  Constructor.
25
29
  :param block_names: the block name instance that this manger is managing
26
- :param delay_before_retry_add_monitor: if the block names pv doesn't exist on start the delay before retrying
30
+ :param delay_before_retry_add_monitor: if the block names pv doesn't exist
31
+ on start the delay before retrying
27
32
  """
28
33
  self._block_names = block_names
29
34
  self._cancel_monitor_fn = None
30
35
  self._delay_before_retry_add_monitor = delay_before_retry_add_monitor
31
36
  self._timer = None
32
- self._pv_name = None
37
+ self._pv_name = ""
33
38
  # lock used to access _timer or _pv_name
34
39
  self.pv_name_lock = RLock()
35
40
 
36
- def update_prefix(self, pv_prefix):
41
+ def update_prefix(self, pv_prefix: str) -> None:
37
42
  """
38
43
  Update the instrument prefix that the manager is using if it has changed
39
44
  :param pv_prefix: new pv prefix
@@ -45,44 +50,49 @@ class BlockNamesManager:
45
50
  self._pv_name = new_name
46
51
  if self._timer is None:
47
52
  self._timer = Timer(0, self._add_monitor)
48
- self._timer.setDaemon(True)
53
+ self._timer.daemon = True
49
54
  self._timer.start()
50
55
 
51
- def _add_monitor(self):
56
+ def _add_monitor(self) -> None:
52
57
  """
53
- Add a monitor to the block names pv if it is not already monitored, then reschedule task to add monitor. If the
54
- pv is monitored don't run.
58
+ Add a monitor to the block names pv if it is not already monitored,
59
+ then reschedule task to add monitor. If the pv is monitored don't run.
55
60
  """
56
61
 
57
- # Get PV we should monitor and check whether we need to add new monitor if so cancel old monitor
62
+ # Get PV we should monitor and check whether we need to add new monitor
63
+ # if so cancel old monitor
58
64
  with self.pv_name_lock:
59
65
  self._timer = None
60
66
  # not monitoring the correct pv
61
67
  if self._cancel_monitor_fn is not None:
62
68
  self._cancel_monitor_fn()
63
69
 
64
- # Add new monitor if successful then record monitored pv and pull first value, otherwise do nothing
70
+ # Add new monitor if successful then record monitored pv and pull
71
+ # first value, otherwise do nothing
65
72
  try:
66
73
  self._cancel_monitor_fn = CaChannelWrapper.add_monitor(
67
74
  self._pv_name, self._update_block_names, to_string=True
68
75
  )
69
76
  self._update_block_names(
70
- CaChannelWrapper.get_pv_value(self._pv_name, to_string=True), None, None
77
+ CaChannelWrapper.get_pv_value(self._pv_name, to_string=True), "", ""
71
78
  )
72
79
  except UnableToConnectToPVException:
73
- # Schedule next add monitor if needed; i.e. a old pv-prefix change was slower the the last pv-prefix
80
+ # Schedule next add monitor if needed; i.e. a old pv-prefix change
81
+ # was slower the the last pv-prefix
74
82
  # and so we are monitoring the wrong pv.
75
83
  self._timer = Timer(self._delay_before_retry_add_monitor, self._add_monitor)
76
- self._timer.setDaemon(True)
84
+ self._timer.daemon = True
77
85
  self._timer.start()
78
86
 
79
- def _update_block_names(self, value, _, _1):
87
+ def _update_block_names(self, value: "PVValue", _: Optional[str], _1: Optional[str]) -> None:
80
88
  """
81
89
  Update the block names from a pv
82
90
  Args:
83
91
  :param value: new value of block names pv
84
- :param _(CaChannel._ca.AlarmSeverity): severity of any alarm (not used but passed in by monitor)
85
- :param _1(CaChannel._ca.AlarmCondition): status of the alarm (not used but passed in by monitor)
92
+ :param _(CaChannel._ca.AlarmSeverity): severity of any alarm
93
+ (not used but passed in by monitor)
94
+ :param _1(CaChannel._ca.AlarmCondition): status of the alarm
95
+ (not used but passed in by monitor)
86
96
  """
87
97
  # remove old blocks
88
98
  for block_name in list(self._block_names.__dict__.keys()):
@@ -90,6 +100,7 @@ class BlockNamesManager:
90
100
 
91
101
  # add new block as attributes to class
92
102
  try:
103
+ assert isinstance(value, (str, bytes)), value
93
104
  block_names = dehex_decompress_and_dejson(value)
94
105
  for name in block_names:
95
106
  attribute_name = name
@@ -103,11 +114,12 @@ class BlockNamesManager:
103
114
 
104
115
  class BlockNames:
105
116
  """
106
- Hold names of the current blocks in config. If block is requested which does not appear in the current config
107
- block name returned but message printed about it.
117
+ Hold names of the current blocks in config. If block is requested which
118
+ does not appear in the current config block name returned but message
119
+ printed about it.
108
120
  """
109
121
 
110
- def __getattr__(self, attr):
122
+ def __getattr__(self, attr: str) -> str:
111
123
  """
112
124
  If an attribute is not set then return name requested
113
125
  :param attr: attribute name
@@ -0,0 +1,44 @@
1
+ """
2
+ Useful and slightly more explicit exceptions that can be thrown.
3
+ In general catch the super class of these.
4
+ """
5
+
6
+
7
+ class UnableToConnectToPVException(IOError): # noqa N818 Historic name
8
+ """
9
+ The system is unable to connect to a PV for some reason.
10
+ """
11
+
12
+ def __init__(self, pv_name: str, err: str) -> None:
13
+ super(UnableToConnectToPVException, self).__init__(
14
+ f"Unable to connect to PV {pv_name}: {err}"
15
+ )
16
+
17
+
18
+ class InvalidEnumStringException(KeyError): # noqa N818 Historic name
19
+ """
20
+ The enum string that is trying to be set is not listed in the pv.
21
+ """
22
+
23
+ def __init__(self, pv_name: str, valid_states: str) -> None:
24
+ super(InvalidEnumStringException, self).__init__(
25
+ f"Invalid string value entered for {pv_name}. Valid strings are {valid_states}"
26
+ )
27
+
28
+
29
+ class ReadAccessException(IOError): # noqa N818 Historic name
30
+ """
31
+ PV exists but its value is unavailable to read.
32
+ """
33
+
34
+ def __init__(self, pv_name: str) -> None:
35
+ super(ReadAccessException, self).__init__(f"Read access denied for PV {pv_name}")
36
+
37
+
38
+ class WriteAccessException(IOError): # noqa N818 Historic name
39
+ """
40
+ PV was written to but does not allow writes.
41
+ """
42
+
43
+ def __init__(self, pv_name: str) -> None:
44
+ super(WriteAccessException, self).__init__(f"Write access denied for PV {pv_name}")