np-services 0.1.62__py3-none-any.whl → 0.1.73__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 (207) hide show
  1. np_services/__init__.py +8 -8
  2. np_services/open_ephys.py +377 -378
  3. np_services/protocols.py +185 -185
  4. np_services/proxies.py +1489 -1488
  5. np_services/resources/mvr_connector.py +260 -260
  6. np_services/resources/zro.py +325 -325
  7. np_services/scripts/pretest.py +412 -328
  8. np_services/stim_computer_theme_changer.py +41 -41
  9. np_services/utils.py +167 -167
  10. {np_services-0.1.62.dist-info → np_services-0.1.73.dist-info}/METADATA +6 -7
  11. np_services-0.1.73.dist-info/RECORD +15 -0
  12. {np_services-0.1.62.dist-info → np_services-0.1.73.dist-info}/WHEEL +2 -1
  13. {np_services-0.1.62.dist-info → np_services-0.1.73.dist-info}/entry_points.txt +1 -1
  14. np_services-0.1.73.dist-info/top_level.txt +1 -0
  15. np_services/.mypy_cache/.gitignore +0 -2
  16. np_services/.mypy_cache/3.9/@plugins_snapshot.json +0 -1
  17. np_services/.mypy_cache/3.9/__future__.data.json +0 -1
  18. np_services/.mypy_cache/3.9/__future__.meta.json +0 -1
  19. np_services/.mypy_cache/3.9/_ast.data.json +0 -1
  20. np_services/.mypy_cache/3.9/_ast.meta.json +0 -1
  21. np_services/.mypy_cache/3.9/_codecs.data.json +0 -1
  22. np_services/.mypy_cache/3.9/_codecs.meta.json +0 -1
  23. np_services/.mypy_cache/3.9/_collections_abc.data.json +0 -1
  24. np_services/.mypy_cache/3.9/_collections_abc.meta.json +0 -1
  25. np_services/.mypy_cache/3.9/_ctypes.data.json +0 -1
  26. np_services/.mypy_cache/3.9/_ctypes.meta.json +0 -1
  27. np_services/.mypy_cache/3.9/_decimal.data.json +0 -1
  28. np_services/.mypy_cache/3.9/_decimal.meta.json +0 -1
  29. np_services/.mypy_cache/3.9/_random.data.json +0 -1
  30. np_services/.mypy_cache/3.9/_random.meta.json +0 -1
  31. np_services/.mypy_cache/3.9/_socket.data.json +0 -1
  32. np_services/.mypy_cache/3.9/_socket.meta.json +0 -1
  33. np_services/.mypy_cache/3.9/_thread.data.json +0 -1
  34. np_services/.mypy_cache/3.9/_thread.meta.json +0 -1
  35. np_services/.mypy_cache/3.9/_typeshed/__init__.data.json +0 -1
  36. np_services/.mypy_cache/3.9/_typeshed/__init__.meta.json +0 -1
  37. np_services/.mypy_cache/3.9/_warnings.data.json +0 -1
  38. np_services/.mypy_cache/3.9/_warnings.meta.json +0 -1
  39. np_services/.mypy_cache/3.9/_weakref.data.json +0 -1
  40. np_services/.mypy_cache/3.9/_weakref.meta.json +0 -1
  41. np_services/.mypy_cache/3.9/_weakrefset.data.json +0 -1
  42. np_services/.mypy_cache/3.9/_weakrefset.meta.json +0 -1
  43. np_services/.mypy_cache/3.9/_winapi.data.json +0 -1
  44. np_services/.mypy_cache/3.9/_winapi.meta.json +0 -1
  45. np_services/.mypy_cache/3.9/abc.data.json +0 -1
  46. np_services/.mypy_cache/3.9/abc.meta.json +0 -1
  47. np_services/.mypy_cache/3.9/array.data.json +0 -1
  48. np_services/.mypy_cache/3.9/array.meta.json +0 -1
  49. np_services/.mypy_cache/3.9/atexit.data.json +0 -1
  50. np_services/.mypy_cache/3.9/atexit.meta.json +0 -1
  51. np_services/.mypy_cache/3.9/builtins.data.json +0 -1
  52. np_services/.mypy_cache/3.9/builtins.meta.json +0 -1
  53. np_services/.mypy_cache/3.9/codecs.data.json +0 -1
  54. np_services/.mypy_cache/3.9/codecs.meta.json +0 -1
  55. np_services/.mypy_cache/3.9/collections/__init__.data.json +0 -1
  56. np_services/.mypy_cache/3.9/collections/__init__.meta.json +0 -1
  57. np_services/.mypy_cache/3.9/collections/abc.data.json +0 -1
  58. np_services/.mypy_cache/3.9/collections/abc.meta.json +0 -1
  59. np_services/.mypy_cache/3.9/contextlib.data.json +0 -1
  60. np_services/.mypy_cache/3.9/contextlib.meta.json +0 -1
  61. np_services/.mypy_cache/3.9/ctypes/__init__.data.json +0 -1
  62. np_services/.mypy_cache/3.9/ctypes/__init__.meta.json +0 -1
  63. np_services/.mypy_cache/3.9/datetime.data.json +0 -1
  64. np_services/.mypy_cache/3.9/datetime.meta.json +0 -1
  65. np_services/.mypy_cache/3.9/decimal.data.json +0 -1
  66. np_services/.mypy_cache/3.9/decimal.meta.json +0 -1
  67. np_services/.mypy_cache/3.9/email/__init__.data.json +0 -1
  68. np_services/.mypy_cache/3.9/email/__init__.meta.json +0 -1
  69. np_services/.mypy_cache/3.9/email/charset.data.json +0 -1
  70. np_services/.mypy_cache/3.9/email/charset.meta.json +0 -1
  71. np_services/.mypy_cache/3.9/email/contentmanager.data.json +0 -1
  72. np_services/.mypy_cache/3.9/email/contentmanager.meta.json +0 -1
  73. np_services/.mypy_cache/3.9/email/errors.data.json +0 -1
  74. np_services/.mypy_cache/3.9/email/errors.meta.json +0 -1
  75. np_services/.mypy_cache/3.9/email/header.data.json +0 -1
  76. np_services/.mypy_cache/3.9/email/header.meta.json +0 -1
  77. np_services/.mypy_cache/3.9/email/message.data.json +0 -1
  78. np_services/.mypy_cache/3.9/email/message.meta.json +0 -1
  79. np_services/.mypy_cache/3.9/email/policy.data.json +0 -1
  80. np_services/.mypy_cache/3.9/email/policy.meta.json +0 -1
  81. np_services/.mypy_cache/3.9/enum.data.json +0 -1
  82. np_services/.mypy_cache/3.9/enum.meta.json +0 -1
  83. np_services/.mypy_cache/3.9/errno.data.json +0 -1
  84. np_services/.mypy_cache/3.9/errno.meta.json +0 -1
  85. np_services/.mypy_cache/3.9/fractions.data.json +0 -1
  86. np_services/.mypy_cache/3.9/fractions.meta.json +0 -1
  87. np_services/.mypy_cache/3.9/genericpath.data.json +0 -1
  88. np_services/.mypy_cache/3.9/genericpath.meta.json +0 -1
  89. np_services/.mypy_cache/3.9/importlib/__init__.data.json +0 -1
  90. np_services/.mypy_cache/3.9/importlib/__init__.meta.json +0 -1
  91. np_services/.mypy_cache/3.9/importlib/abc.data.json +0 -1
  92. np_services/.mypy_cache/3.9/importlib/abc.meta.json +0 -1
  93. np_services/.mypy_cache/3.9/importlib/machinery.data.json +0 -1
  94. np_services/.mypy_cache/3.9/importlib/machinery.meta.json +0 -1
  95. np_services/.mypy_cache/3.9/importlib/metadata/__init__.data.json +0 -1
  96. np_services/.mypy_cache/3.9/importlib/metadata/__init__.meta.json +0 -1
  97. np_services/.mypy_cache/3.9/io.data.json +0 -1
  98. np_services/.mypy_cache/3.9/io.meta.json +0 -1
  99. np_services/.mypy_cache/3.9/json/__init__.data.json +0 -1
  100. np_services/.mypy_cache/3.9/json/__init__.meta.json +0 -1
  101. np_services/.mypy_cache/3.9/json/decoder.data.json +0 -1
  102. np_services/.mypy_cache/3.9/json/decoder.meta.json +0 -1
  103. np_services/.mypy_cache/3.9/json/encoder.data.json +0 -1
  104. np_services/.mypy_cache/3.9/json/encoder.meta.json +0 -1
  105. np_services/.mypy_cache/3.9/logging/__init__.data.json +0 -1
  106. np_services/.mypy_cache/3.9/logging/__init__.meta.json +0 -1
  107. np_services/.mypy_cache/3.9/math.data.json +0 -1
  108. np_services/.mypy_cache/3.9/math.meta.json +0 -1
  109. np_services/.mypy_cache/3.9/mmap.data.json +0 -1
  110. np_services/.mypy_cache/3.9/mmap.meta.json +0 -1
  111. np_services/.mypy_cache/3.9/np_services/__init__.data.json +0 -1
  112. np_services/.mypy_cache/3.9/np_services/__init__.meta.json +0 -1
  113. np_services/.mypy_cache/3.9/np_services/config.data.json +0 -1
  114. np_services/.mypy_cache/3.9/np_services/config.meta.json +0 -1
  115. np_services/.mypy_cache/3.9/np_services/protocols.data.json +0 -1
  116. np_services/.mypy_cache/3.9/np_services/protocols.meta.json +0 -1
  117. np_services/.mypy_cache/3.9/np_services/zro.data.json +0 -1
  118. np_services/.mypy_cache/3.9/np_services/zro.meta.json +0 -1
  119. np_services/.mypy_cache/3.9/ntpath.data.json +0 -1
  120. np_services/.mypy_cache/3.9/ntpath.meta.json +0 -1
  121. np_services/.mypy_cache/3.9/numbers.data.json +0 -1
  122. np_services/.mypy_cache/3.9/numbers.meta.json +0 -1
  123. np_services/.mypy_cache/3.9/os/__init__.data.json +0 -1
  124. np_services/.mypy_cache/3.9/os/__init__.meta.json +0 -1
  125. np_services/.mypy_cache/3.9/os/path.data.json +0 -1
  126. np_services/.mypy_cache/3.9/os/path.meta.json +0 -1
  127. np_services/.mypy_cache/3.9/pathlib.data.json +0 -1
  128. np_services/.mypy_cache/3.9/pathlib.meta.json +0 -1
  129. np_services/.mypy_cache/3.9/pickle.data.json +0 -1
  130. np_services/.mypy_cache/3.9/pickle.meta.json +0 -1
  131. np_services/.mypy_cache/3.9/platform.data.json +0 -1
  132. np_services/.mypy_cache/3.9/platform.meta.json +0 -1
  133. np_services/.mypy_cache/3.9/posixpath.data.json +0 -1
  134. np_services/.mypy_cache/3.9/posixpath.meta.json +0 -1
  135. np_services/.mypy_cache/3.9/random.data.json +0 -1
  136. np_services/.mypy_cache/3.9/random.meta.json +0 -1
  137. np_services/.mypy_cache/3.9/re.data.json +0 -1
  138. np_services/.mypy_cache/3.9/re.meta.json +0 -1
  139. np_services/.mypy_cache/3.9/shutil.data.json +0 -1
  140. np_services/.mypy_cache/3.9/shutil.meta.json +0 -1
  141. np_services/.mypy_cache/3.9/socket.data.json +0 -1
  142. np_services/.mypy_cache/3.9/socket.meta.json +0 -1
  143. np_services/.mypy_cache/3.9/sre_compile.data.json +0 -1
  144. np_services/.mypy_cache/3.9/sre_compile.meta.json +0 -1
  145. np_services/.mypy_cache/3.9/sre_constants.data.json +0 -1
  146. np_services/.mypy_cache/3.9/sre_constants.meta.json +0 -1
  147. np_services/.mypy_cache/3.9/sre_parse.data.json +0 -1
  148. np_services/.mypy_cache/3.9/sre_parse.meta.json +0 -1
  149. np_services/.mypy_cache/3.9/string.data.json +0 -1
  150. np_services/.mypy_cache/3.9/string.meta.json +0 -1
  151. np_services/.mypy_cache/3.9/subprocess.data.json +0 -1
  152. np_services/.mypy_cache/3.9/subprocess.meta.json +0 -1
  153. np_services/.mypy_cache/3.9/sys.data.json +0 -1
  154. np_services/.mypy_cache/3.9/sys.meta.json +0 -1
  155. np_services/.mypy_cache/3.9/threading.data.json +0 -1
  156. np_services/.mypy_cache/3.9/threading.meta.json +0 -1
  157. np_services/.mypy_cache/3.9/time.data.json +0 -1
  158. np_services/.mypy_cache/3.9/time.meta.json +0 -1
  159. np_services/.mypy_cache/3.9/types.data.json +0 -1
  160. np_services/.mypy_cache/3.9/types.meta.json +0 -1
  161. np_services/.mypy_cache/3.9/typing.data.json +0 -1
  162. np_services/.mypy_cache/3.9/typing.meta.json +0 -1
  163. np_services/.mypy_cache/3.9/typing_extensions.data.json +0 -1
  164. np_services/.mypy_cache/3.9/typing_extensions.meta.json +0 -1
  165. np_services/.mypy_cache/3.9/warnings.data.json +0 -1
  166. np_services/.mypy_cache/3.9/warnings.meta.json +0 -1
  167. np_services/.mypy_cache/3.9/weakref.data.json +0 -1
  168. np_services/.mypy_cache/3.9/weakref.meta.json +0 -1
  169. np_services/.mypy_cache/3.9/zmq/__init__.data.json +0 -1
  170. np_services/.mypy_cache/3.9/zmq/__init__.meta.json +0 -1
  171. np_services/.mypy_cache/3.9/zmq/_typing.data.json +0 -1
  172. np_services/.mypy_cache/3.9/zmq/_typing.meta.json +0 -1
  173. np_services/.mypy_cache/3.9/zmq/backend/__init__.data.json +0 -1
  174. np_services/.mypy_cache/3.9/zmq/backend/__init__.meta.json +0 -1
  175. np_services/.mypy_cache/3.9/zmq/backend/select.data.json +0 -1
  176. np_services/.mypy_cache/3.9/zmq/backend/select.meta.json +0 -1
  177. np_services/.mypy_cache/3.9/zmq/constants.data.json +0 -1
  178. np_services/.mypy_cache/3.9/zmq/constants.meta.json +0 -1
  179. np_services/.mypy_cache/3.9/zmq/error.data.json +0 -1
  180. np_services/.mypy_cache/3.9/zmq/error.meta.json +0 -1
  181. np_services/.mypy_cache/3.9/zmq/sugar/__init__.data.json +0 -1
  182. np_services/.mypy_cache/3.9/zmq/sugar/__init__.meta.json +0 -1
  183. np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.data.json +0 -1
  184. np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.meta.json +0 -1
  185. np_services/.mypy_cache/3.9/zmq/sugar/context.data.json +0 -1
  186. np_services/.mypy_cache/3.9/zmq/sugar/context.meta.json +0 -1
  187. np_services/.mypy_cache/3.9/zmq/sugar/frame.data.json +0 -1
  188. np_services/.mypy_cache/3.9/zmq/sugar/frame.meta.json +0 -1
  189. np_services/.mypy_cache/3.9/zmq/sugar/poll.data.json +0 -1
  190. np_services/.mypy_cache/3.9/zmq/sugar/poll.meta.json +0 -1
  191. np_services/.mypy_cache/3.9/zmq/sugar/socket.data.json +0 -1
  192. np_services/.mypy_cache/3.9/zmq/sugar/socket.meta.json +0 -1
  193. np_services/.mypy_cache/3.9/zmq/sugar/tracker.data.json +0 -1
  194. np_services/.mypy_cache/3.9/zmq/sugar/tracker.meta.json +0 -1
  195. np_services/.mypy_cache/3.9/zmq/sugar/version.data.json +0 -1
  196. np_services/.mypy_cache/3.9/zmq/sugar/version.meta.json +0 -1
  197. np_services/.mypy_cache/3.9/zmq/utils/__init__.data.json +0 -1
  198. np_services/.mypy_cache/3.9/zmq/utils/__init__.meta.json +0 -1
  199. np_services/.mypy_cache/3.9/zmq/utils/interop.data.json +0 -1
  200. np_services/.mypy_cache/3.9/zmq/utils/interop.meta.json +0 -1
  201. np_services/.mypy_cache/3.9/zmq/utils/jsonapi.data.json +0 -1
  202. np_services/.mypy_cache/3.9/zmq/utils/jsonapi.meta.json +0 -1
  203. np_services/.mypy_cache/CACHEDIR.TAG +0 -3
  204. np_services/resources/black_desktop.ps1 +0 -66
  205. np_services/resources/grey_desktop.ps1 +0 -66
  206. np_services/resources/reset_desktop.ps1 +0 -66
  207. np_services-0.1.62.dist-info/RECORD +0 -206
@@ -1,325 +1,325 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- proxy.py
4
-
5
- @author: derricw
6
-
7
- Proxy device and manager for ZRO devices.
8
-
9
- `Proxy` is a remote object proxy designed to interact with objects
10
- extending `BasePubRepDevice` (from device.py).
11
-
12
- """
13
- import np_logging
14
- import zmq
15
-
16
- logger = np_logging.getLogger(__name__)
17
-
18
-
19
- def get_address(ip="", port=None):
20
- """
21
- Trys to get a properly formatted address given a port and ip.
22
-
23
- ZMQ likes address to be in this format:
24
-
25
- {protocol}://{ip}:{port}
26
-
27
- Args:
28
- ip (Optional[str]): ip address with some semblance of correct formatting
29
- port (Optional[int]): port to use in the event that the port is not
30
- included in the IP
31
-
32
- Returns:
33
- str: a properly formatted ip str.
34
-
35
- """
36
- if not ip and not port:
37
- raise ValueError("Need a port or IP.")
38
- elif not ip and port:
39
- return "tcp://*:{}".format(port)
40
- else:
41
- if ip[:6] != "tcp://":
42
- ip = "tcp://" + ip
43
- if len(ip.split(":")) == 2:
44
- return "{}:{}".format(ip, port)
45
- else:
46
- return ip
47
-
48
-
49
- class DeviceProxy(object):
50
- """
51
- Proxy object for a BasePubRepDevice.
52
-
53
- args:
54
- ip (Optional[str]): IP/DNS address of actual device. Defaults to
55
- "localhost".
56
- port (Optional[int]): REP port for actual device, if it isn't include
57
- in IP.
58
- timeout (Optional[float]): Timeout in seconds for all commands.
59
- Defaults to 10.
60
- serialization (Optional[str]): Serialization method. "pickle" (default)
61
- or "json".
62
-
63
- Example:
64
- >>> dev = DeviceProxy("localhost:5556")
65
- >>> dev.call_method_on_device(some_argument)
66
- >>> dev.attr_on_device = 5
67
-
68
- """
69
-
70
- _context = zmq.Context()
71
- _context.setsockopt(zmq.LINGER, 1)
72
-
73
- def __init__(
74
- self, ip="localhost", port=None, timeout=10.0, serialization="pickle",
75
- ):
76
- super().__init__()
77
- self.__dict__["ip"] = ip
78
- self.__dict__["rep_port"] = port
79
- self.__dict__["timeout"] = timeout
80
- self.__dict__["serialization"] = serialization.lower()
81
-
82
- self._setup_socket()
83
- # self._setup_getset()
84
-
85
- def __setattr__(self, name, value):
86
- """
87
- Overwrite __setattr__ so that attributes are set on target object
88
- instead of this object.
89
- """
90
- packet = {"command": "set", "args": (name, value)}
91
- self._send_packet(packet)
92
- response = self.__dict__["recv"]()
93
- if response == "0":
94
- return None
95
- else:
96
- raise ZroError(message=str(response))
97
-
98
- def __getattr__(self, name):
99
- """
100
- Overwrite __getattr__ so that attributes are grabbed from target object
101
- instead of this object.
102
- """
103
- packet = {"command": "get", "args": (name,)}
104
- self._send_packet(packet)
105
- response = self.__dict__["recv"]()
106
- if isinstance(response, ZroError):
107
- raise ZroError(message=str(response))
108
- elif response in ("callable", "__callable__"):
109
- self.__dict__["to_call"] = name # HOLD ON TO YOUR BUTTS
110
- return self._call
111
- else:
112
- return response
113
-
114
- def __dir__(self):
115
- """
116
- Overwrite __dir__ so that attributes and methods come from target
117
- object.
118
- """
119
- self.__dict__["to_call"] = "get_attribute_list"
120
- attrs = self._call()
121
- self.__dict__["to_call"] = "get_command_list"
122
- methods = self._call()
123
- return attrs + methods
124
-
125
- def _send_packet(self, packet):
126
- """
127
- Sends a packet. Attempts to reconnect once if there is a failure.
128
-
129
- #TODO: Make packet a class.
130
- """
131
- try:
132
- self.__dict__["send"](packet)
133
- except zmq.ZMQError:
134
- self.__dict__["req_socket"].close()
135
- self._setup_socket()
136
- self.__dict__["send"](packet)
137
-
138
- def _setup_socket(self):
139
- """
140
- Sets up the request socket.
141
- """
142
- ip = self.__dict__["ip"]
143
- rep_port = self.__dict__["rep_port"]
144
- addr_str = get_address(ip, rep_port)
145
- timeout = self.__dict__["timeout"]
146
- self.__dict__["req_socket"] = self._context.socket(zmq.REQ)
147
- self.__dict__["req_socket"].setsockopt(zmq.SNDTIMEO, int(timeout * 1000))
148
- self.__dict__["req_socket"].setsockopt(zmq.RCVTIMEO, int(timeout * 1000))
149
- self.__dict__["req_socket"].connect(addr_str)
150
-
151
- if self.__dict__["serialization"] in ["pickle", "pkl", "p"]:
152
- self.__dict__["send"] = self.__dict__["req_socket"].send_pyobj
153
- self.__dict__["recv"] = self.__dict__["req_socket"].recv_pyobj
154
- elif self.__dict__["serialization"] in ["json", "j"]:
155
- self.__dict__["send"] = self.__dict__["req_socket"].send_json
156
- self.__dict__["recv"] = self.__dict__["req_socket"].recv_json
157
- else:
158
- raise ValueError("Incorrect serialization type. Try 'pickle' or 'json'.")
159
-
160
- def _call(self, *args, **kwargs):
161
- """
162
- Used for calling arbitrary methods in the device.
163
- """
164
- packet = {
165
- "command": "run",
166
- "callable": self.to_call,
167
- "args": args,
168
- "kwargs": kwargs,
169
- }
170
- self.__dict__["send"](packet)
171
- response = self.__dict__["recv"]()
172
- if isinstance(response, dict) and response.get("ZroError", False):
173
- response = ZroError.from_dict(response)
174
- if isinstance(response, ZroError):
175
- raise ZroError(message=str(response))
176
- return response
177
-
178
- def __del__(self):
179
- """
180
- Close the socket on cleanup.
181
- """
182
- self.__dict__["req_socket"].close()
183
-
184
-
185
- Proxy = DeviceProxy
186
-
187
-
188
- class ZroError(Exception):
189
- """Base class for zro errors."""
190
-
191
- error_codes = {
192
- 1: "{} -> HAS_NO_ATTRIBUTE -> {}",
193
- 2: "{} -> HAS_NO_CALLABLE -> {}",
194
- 3: "{} -> ATTRIBUTE_NOT_CALLABLE -> {}",
195
- 4: "{} -> CALLABLE_FAILED -> {}",
196
- 5: "{} -> ARGUMENTS_INVALID -> {}",
197
- 6: "{} -> UNHANDLED_ERROR -> {}",
198
- 7: "{} -> ASYNC_RESULT_INVALID_HANDLE -> {}",
199
- 8: "{} -> ASYNC_RESULT_UNFINISHED -> {}",
200
- 9: "{} -> ASYNC_CALLBACK_FAILED -> {}",
201
- }
202
-
203
- HAS_NO_ATTRIBUTE = 1
204
- HAS_NO_CALLABLE = 2
205
- ATTRIBUTE_NOT_CALLABLE = 3
206
- CALLABLE_FAILED = 4
207
- ARGUMENTS_INVALID = 5
208
- UNHANDLED_ERROR = 6
209
- ASYNC_RESULT_INVALID_HANDLE = 7
210
- ASYNC_RESULT_UNFINISHED = 8
211
- ASYNC_CALLBACK_FAILED = 9
212
-
213
- def __init__(self, obj=None, target=None, error_code=6, message=""):
214
- if not message:
215
- message = self.error_codes[error_code].format(obj, target)
216
- self.message = message
217
- self.error_code = error_code
218
- super(ZroError, self).__init__(message)
219
-
220
- def to_JSON(self):
221
- return {
222
- "ZroError": str(
223
- type(self.get_specific_error())
224
- ), # this key lets zro convert this on the receive side
225
- "error_code": self.error_code,
226
- "message": str(self.message),
227
- }
228
-
229
- @staticmethod
230
- def from_dict(d):
231
- return ZroError(
232
- error_code=d["error_code"], message=d["message"]
233
- ).get_specific_error()
234
-
235
- def get_specific_error(self, to_raise=False):
236
- """Get the appropriate ZroError for the error type."""
237
- err = _SPECIFIC_ERRORS[self.error_code](message=self.message)
238
- if to_raise:
239
- raise err
240
- return err
241
-
242
-
243
- class ZroNoAttributeError(ZroError):
244
- """Error for HAS_NO_ATTRIBUTE."""
245
-
246
- def __init__(self, obj=None, target=None, message=""):
247
- super(ZroNoAttributeError, self).__init__(
248
- obj, target, ZroError.HAS_NO_ATTRIBUTE, message
249
- )
250
-
251
-
252
- class ZroNoCallableError(ZroError):
253
- """Error for HAS_NO_CALLABLE."""
254
-
255
- def __init__(self, obj=None, target=None, message=""):
256
- super(ZroNoCallableError, self).__init__(
257
- obj, target, ZroError.HAS_NO_CALLABLE, message
258
- )
259
-
260
-
261
- class ZroAttrNotCallableError(ZroError):
262
- """Error for ATTRIBUTE_NOT_CALLABLE."""
263
-
264
- def __init__(self, obj=None, target=None, message=""):
265
- super(ZroAttrNotCallableError, self).__init__(
266
- obj, target, ZroError.ATTRIBUTE_NOT_CALLABLE, message
267
- )
268
-
269
-
270
- class ZroCallableFailedError(ZroError):
271
- """Error for CALLABLE_FAILED."""
272
-
273
- def __init__(self, obj=None, target=None, message=""):
274
- super(ZroCallableFailedError, self).__init__(
275
- obj, target, ZroError.CALLABLE_FAILED, message
276
- )
277
-
278
-
279
- class ZroArgumentsInvalidError(ZroError):
280
- """Error for ARGUMENTS_INVALID."""
281
-
282
- def __init__(self, obj=None, target=None, message=""):
283
- super(ZroArgumentsInvalidError, self).__init__(
284
- obj, target, ZroError.ARGUMENTS_INVALID, message
285
- )
286
-
287
-
288
- class ZroAsyncHandleInvalidError(ZroError):
289
- """Error for ASYNC_RESULT_INVALID_HANDLE."""
290
-
291
- def __init__(self, obj=None, target=None, message=""):
292
- super(ZroAsyncHandleInvalidError, self).__init__(
293
- obj, target, ZroError.ASYNC_RESULT_INVALID_HANDLE, message
294
- )
295
-
296
-
297
- class ZroResultUnfinishedError(ZroError):
298
- """Error for ASYNC_RESULT_UNFINISHED."""
299
-
300
- def __init__(self, obj=None, target=None, message=""):
301
- super(ZroResultUnfinishedError, self).__init__(
302
- obj, target, ZroError.ASYNC_RESULT_UNFINISHED, message
303
- )
304
-
305
-
306
- class ZroCallbackFailedError(ZroError):
307
- """Error for ASYNC_CALLBACK_FAILED."""
308
-
309
- def __init__(self, obj=None, target=None, message=""):
310
- super(ZroCallbackFailedError, self).__init__(
311
- obj, target, ZroError.ASYNC_CALLBACK_FAILED, message
312
- )
313
-
314
-
315
- _SPECIFIC_ERRORS = {
316
- 1: ZroNoAttributeError,
317
- 2: ZroNoCallableError,
318
- 3: ZroAttrNotCallableError,
319
- 4: ZroCallableFailedError,
320
- 5: ZroArgumentsInvalidError,
321
- 6: ZroError,
322
- 7: ZroAsyncHandleInvalidError,
323
- 8: ZroResultUnfinishedError,
324
- 9: ZroCallbackFailedError,
325
- }
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ proxy.py
4
+
5
+ @author: derricw
6
+
7
+ Proxy device and manager for ZRO devices.
8
+
9
+ `Proxy` is a remote object proxy designed to interact with objects
10
+ extending `BasePubRepDevice` (from device.py).
11
+
12
+ """
13
+ import np_logging
14
+ import zmq
15
+
16
+ logger = np_logging.getLogger(__name__)
17
+
18
+
19
+ def get_address(ip="", port=None):
20
+ """
21
+ Trys to get a properly formatted address given a port and ip.
22
+
23
+ ZMQ likes address to be in this format:
24
+
25
+ {protocol}://{ip}:{port}
26
+
27
+ Args:
28
+ ip (Optional[str]): ip address with some semblance of correct formatting
29
+ port (Optional[int]): port to use in the event that the port is not
30
+ included in the IP
31
+
32
+ Returns:
33
+ str: a properly formatted ip str.
34
+
35
+ """
36
+ if not ip and not port:
37
+ raise ValueError("Need a port or IP.")
38
+ elif not ip and port:
39
+ return "tcp://*:{}".format(port)
40
+ else:
41
+ if ip[:6] != "tcp://":
42
+ ip = "tcp://" + ip
43
+ if len(ip.split(":")) == 2:
44
+ return "{}:{}".format(ip, port)
45
+ else:
46
+ return ip
47
+
48
+
49
+ class DeviceProxy(object):
50
+ """
51
+ Proxy object for a BasePubRepDevice.
52
+
53
+ args:
54
+ ip (Optional[str]): IP/DNS address of actual device. Defaults to
55
+ "localhost".
56
+ port (Optional[int]): REP port for actual device, if it isn't include
57
+ in IP.
58
+ timeout (Optional[float]): Timeout in seconds for all commands.
59
+ Defaults to 10.
60
+ serialization (Optional[str]): Serialization method. "pickle" (default)
61
+ or "json".
62
+
63
+ Example:
64
+ >>> dev = DeviceProxy("localhost:5556")
65
+ >>> dev.call_method_on_device(some_argument)
66
+ >>> dev.attr_on_device = 5
67
+
68
+ """
69
+
70
+ _context = zmq.Context()
71
+ _context.setsockopt(zmq.LINGER, 1)
72
+
73
+ def __init__(
74
+ self, ip="localhost", port=None, timeout=10.0, serialization="pickle",
75
+ ):
76
+ super().__init__()
77
+ self.__dict__["ip"] = ip
78
+ self.__dict__["rep_port"] = port
79
+ self.__dict__["timeout"] = timeout
80
+ self.__dict__["serialization"] = serialization.lower()
81
+
82
+ self._setup_socket()
83
+ # self._setup_getset()
84
+
85
+ def __setattr__(self, name, value):
86
+ """
87
+ Overwrite __setattr__ so that attributes are set on target object
88
+ instead of this object.
89
+ """
90
+ packet = {"command": "set", "args": (name, value)}
91
+ self._send_packet(packet)
92
+ response = self.__dict__["recv"]()
93
+ if response == "0":
94
+ return None
95
+ else:
96
+ raise ZroError(message=str(response))
97
+
98
+ def __getattr__(self, name):
99
+ """
100
+ Overwrite __getattr__ so that attributes are grabbed from target object
101
+ instead of this object.
102
+ """
103
+ packet = {"command": "get", "args": (name,)}
104
+ self._send_packet(packet)
105
+ response = self.__dict__["recv"]()
106
+ if isinstance(response, ZroError):
107
+ raise ZroError(message=str(response))
108
+ elif response in ("callable", "__callable__"):
109
+ self.__dict__["to_call"] = name # HOLD ON TO YOUR BUTTS
110
+ return self._call
111
+ else:
112
+ return response
113
+
114
+ def __dir__(self):
115
+ """
116
+ Overwrite __dir__ so that attributes and methods come from target
117
+ object.
118
+ """
119
+ self.__dict__["to_call"] = "get_attribute_list"
120
+ attrs = self._call()
121
+ self.__dict__["to_call"] = "get_command_list"
122
+ methods = self._call()
123
+ return attrs + methods
124
+
125
+ def _send_packet(self, packet):
126
+ """
127
+ Sends a packet. Attempts to reconnect once if there is a failure.
128
+
129
+ #TODO: Make packet a class.
130
+ """
131
+ try:
132
+ self.__dict__["send"](packet)
133
+ except zmq.ZMQError:
134
+ self.__dict__["req_socket"].close()
135
+ self._setup_socket()
136
+ self.__dict__["send"](packet)
137
+
138
+ def _setup_socket(self):
139
+ """
140
+ Sets up the request socket.
141
+ """
142
+ ip = self.__dict__["ip"]
143
+ rep_port = self.__dict__["rep_port"]
144
+ addr_str = get_address(ip, rep_port)
145
+ timeout = self.__dict__["timeout"]
146
+ self.__dict__["req_socket"] = self._context.socket(zmq.REQ)
147
+ self.__dict__["req_socket"].setsockopt(zmq.SNDTIMEO, int(timeout * 1000))
148
+ self.__dict__["req_socket"].setsockopt(zmq.RCVTIMEO, int(timeout * 1000))
149
+ self.__dict__["req_socket"].connect(addr_str)
150
+
151
+ if self.__dict__["serialization"] in ["pickle", "pkl", "p"]:
152
+ self.__dict__["send"] = self.__dict__["req_socket"].send_pyobj
153
+ self.__dict__["recv"] = self.__dict__["req_socket"].recv_pyobj
154
+ elif self.__dict__["serialization"] in ["json", "j"]:
155
+ self.__dict__["send"] = self.__dict__["req_socket"].send_json
156
+ self.__dict__["recv"] = self.__dict__["req_socket"].recv_json
157
+ else:
158
+ raise ValueError("Incorrect serialization type. Try 'pickle' or 'json'.")
159
+
160
+ def _call(self, *args, **kwargs):
161
+ """
162
+ Used for calling arbitrary methods in the device.
163
+ """
164
+ packet = {
165
+ "command": "run",
166
+ "callable": self.to_call,
167
+ "args": args,
168
+ "kwargs": kwargs,
169
+ }
170
+ self.__dict__["send"](packet)
171
+ response = self.__dict__["recv"]()
172
+ if isinstance(response, dict) and response.get("ZroError", False):
173
+ response = ZroError.from_dict(response)
174
+ if isinstance(response, ZroError):
175
+ raise ZroError(message=str(response))
176
+ return response
177
+
178
+ def __del__(self):
179
+ """
180
+ Close the socket on cleanup.
181
+ """
182
+ self.__dict__["req_socket"].close()
183
+
184
+
185
+ Proxy = DeviceProxy
186
+
187
+
188
+ class ZroError(Exception):
189
+ """Base class for zro errors."""
190
+
191
+ error_codes = {
192
+ 1: "{} -> HAS_NO_ATTRIBUTE -> {}",
193
+ 2: "{} -> HAS_NO_CALLABLE -> {}",
194
+ 3: "{} -> ATTRIBUTE_NOT_CALLABLE -> {}",
195
+ 4: "{} -> CALLABLE_FAILED -> {}",
196
+ 5: "{} -> ARGUMENTS_INVALID -> {}",
197
+ 6: "{} -> UNHANDLED_ERROR -> {}",
198
+ 7: "{} -> ASYNC_RESULT_INVALID_HANDLE -> {}",
199
+ 8: "{} -> ASYNC_RESULT_UNFINISHED -> {}",
200
+ 9: "{} -> ASYNC_CALLBACK_FAILED -> {}",
201
+ }
202
+
203
+ HAS_NO_ATTRIBUTE = 1
204
+ HAS_NO_CALLABLE = 2
205
+ ATTRIBUTE_NOT_CALLABLE = 3
206
+ CALLABLE_FAILED = 4
207
+ ARGUMENTS_INVALID = 5
208
+ UNHANDLED_ERROR = 6
209
+ ASYNC_RESULT_INVALID_HANDLE = 7
210
+ ASYNC_RESULT_UNFINISHED = 8
211
+ ASYNC_CALLBACK_FAILED = 9
212
+
213
+ def __init__(self, obj=None, target=None, error_code=6, message=""):
214
+ if not message:
215
+ message = self.error_codes[error_code].format(obj, target)
216
+ self.message = message
217
+ self.error_code = error_code
218
+ super(ZroError, self).__init__(message)
219
+
220
+ def to_JSON(self):
221
+ return {
222
+ "ZroError": str(
223
+ type(self.get_specific_error())
224
+ ), # this key lets zro convert this on the receive side
225
+ "error_code": self.error_code,
226
+ "message": str(self.message),
227
+ }
228
+
229
+ @staticmethod
230
+ def from_dict(d):
231
+ return ZroError(
232
+ error_code=d["error_code"], message=d["message"]
233
+ ).get_specific_error()
234
+
235
+ def get_specific_error(self, to_raise=False):
236
+ """Get the appropriate ZroError for the error type."""
237
+ err = _SPECIFIC_ERRORS[self.error_code](message=self.message)
238
+ if to_raise:
239
+ raise err
240
+ return err
241
+
242
+
243
+ class ZroNoAttributeError(ZroError):
244
+ """Error for HAS_NO_ATTRIBUTE."""
245
+
246
+ def __init__(self, obj=None, target=None, message=""):
247
+ super(ZroNoAttributeError, self).__init__(
248
+ obj, target, ZroError.HAS_NO_ATTRIBUTE, message
249
+ )
250
+
251
+
252
+ class ZroNoCallableError(ZroError):
253
+ """Error for HAS_NO_CALLABLE."""
254
+
255
+ def __init__(self, obj=None, target=None, message=""):
256
+ super(ZroNoCallableError, self).__init__(
257
+ obj, target, ZroError.HAS_NO_CALLABLE, message
258
+ )
259
+
260
+
261
+ class ZroAttrNotCallableError(ZroError):
262
+ """Error for ATTRIBUTE_NOT_CALLABLE."""
263
+
264
+ def __init__(self, obj=None, target=None, message=""):
265
+ super(ZroAttrNotCallableError, self).__init__(
266
+ obj, target, ZroError.ATTRIBUTE_NOT_CALLABLE, message
267
+ )
268
+
269
+
270
+ class ZroCallableFailedError(ZroError):
271
+ """Error for CALLABLE_FAILED."""
272
+
273
+ def __init__(self, obj=None, target=None, message=""):
274
+ super(ZroCallableFailedError, self).__init__(
275
+ obj, target, ZroError.CALLABLE_FAILED, message
276
+ )
277
+
278
+
279
+ class ZroArgumentsInvalidError(ZroError):
280
+ """Error for ARGUMENTS_INVALID."""
281
+
282
+ def __init__(self, obj=None, target=None, message=""):
283
+ super(ZroArgumentsInvalidError, self).__init__(
284
+ obj, target, ZroError.ARGUMENTS_INVALID, message
285
+ )
286
+
287
+
288
+ class ZroAsyncHandleInvalidError(ZroError):
289
+ """Error for ASYNC_RESULT_INVALID_HANDLE."""
290
+
291
+ def __init__(self, obj=None, target=None, message=""):
292
+ super(ZroAsyncHandleInvalidError, self).__init__(
293
+ obj, target, ZroError.ASYNC_RESULT_INVALID_HANDLE, message
294
+ )
295
+
296
+
297
+ class ZroResultUnfinishedError(ZroError):
298
+ """Error for ASYNC_RESULT_UNFINISHED."""
299
+
300
+ def __init__(self, obj=None, target=None, message=""):
301
+ super(ZroResultUnfinishedError, self).__init__(
302
+ obj, target, ZroError.ASYNC_RESULT_UNFINISHED, message
303
+ )
304
+
305
+
306
+ class ZroCallbackFailedError(ZroError):
307
+ """Error for ASYNC_CALLBACK_FAILED."""
308
+
309
+ def __init__(self, obj=None, target=None, message=""):
310
+ super(ZroCallbackFailedError, self).__init__(
311
+ obj, target, ZroError.ASYNC_CALLBACK_FAILED, message
312
+ )
313
+
314
+
315
+ _SPECIFIC_ERRORS = {
316
+ 1: ZroNoAttributeError,
317
+ 2: ZroNoCallableError,
318
+ 3: ZroAttrNotCallableError,
319
+ 4: ZroCallableFailedError,
320
+ 5: ZroArgumentsInvalidError,
321
+ 6: ZroError,
322
+ 7: ZroAsyncHandleInvalidError,
323
+ 8: ZroResultUnfinishedError,
324
+ 9: ZroCallbackFailedError,
325
+ }