pyre-gevent 0.2.4.dev0__tar.gz → 0.3.1__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 (29) hide show
  1. {pyre-gevent-0.2.4.dev0/pyre_gevent.egg-info → pyre-gevent-0.3.1}/PKG-INFO +5 -6
  2. pyre-gevent-0.3.1/pyre_gevent/__init__.py +8 -0
  3. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre.py +1 -1
  4. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_event.py +2 -4
  5. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_node.py +3 -4
  6. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zbeacon.py +138 -82
  7. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zre_msg.py +1 -3
  8. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1/pyre_gevent.egg-info}/PKG-INFO +5 -6
  9. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/SOURCES.txt +6 -1
  10. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/requires.txt +1 -1
  11. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/setup.py +2 -2
  12. pyre-gevent-0.3.1/tests/test_network_disconnect.py +81 -0
  13. pyre-gevent-0.3.1/tests/test_pyre.py +178 -0
  14. pyre-gevent-0.3.1/tests/test_zactor.py +38 -0
  15. pyre-gevent-0.3.1/tests/test_zbeacon.py +82 -0
  16. pyre-gevent-0.3.1/tests/test_zhelper.py +32 -0
  17. pyre-gevent-0.2.4.dev0/pyre_gevent/__init__.py +0 -8
  18. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/AUTHORS +0 -0
  19. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/LICENSE +0 -0
  20. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/MANIFEST.in +0 -0
  21. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/README.md +0 -0
  22. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_group.py +0 -0
  23. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_peer.py +0 -0
  24. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zactor.py +0 -0
  25. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zhelper.py +0 -0
  26. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zsocket.py +0 -0
  27. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/dependency_links.txt +0 -0
  28. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/top_level.txt +0 -0
  29. {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/setup.cfg +0 -0
@@ -1,16 +1,15 @@
1
- Metadata-Version: 1.2
1
+ Metadata-Version: 2.1
2
2
  Name: pyre-gevent
3
- Version: 0.2.4.dev0
3
+ Version: 0.3.1
4
4
  Summary: Python ZRE implementation (green version)
5
5
  Home-page: http://www.github.com/tangb/pyre-gevent/
6
6
  Author: Arnaud Loonstra
7
7
  Author-email: arnaud@sphaero.org
8
8
  Maintainer: Tanguy Bonneau
9
9
  Maintainer-email: tanguy.bonneau@gmail.com
10
- License: UNKNOWN
11
- Description: UNKNOWN
12
- Platform: UNKNOWN
13
10
  Requires: pyzmq
14
11
  Requires: ipaddress
15
12
  Requires: netaddr
16
- Requires: netifaces
13
+ Requires: netifaces2
14
+ License-File: LICENSE
15
+ License-File: AUTHORS
@@ -0,0 +1,8 @@
1
+ import re
2
+
3
+ __all__ = ["pyre", "zbeacon", "zhelper"]
4
+ __version__ = "0.3.1"
5
+ __version_info__ = tuple(int(v) for v in re.sub("[a-zA-Z]", "", __version__).split("."))
6
+
7
+ from .pyre import Pyre
8
+ from .pyre_event import PyreEvent
@@ -39,7 +39,7 @@ class Pyre(object):
39
39
  """
40
40
  super(Pyre, self).__init__(*args, **kwargs)
41
41
  ctx = kwargs.get('ctx')
42
- if ctx == None:
42
+ if ctx is None:
43
43
  ctx = zmq.Context()
44
44
  self._ctx = ctx
45
45
  self._uuid = None
@@ -27,7 +27,7 @@ class PyreEvent(object):
27
27
  if self.type == "ENTER":
28
28
  self.headers = json.loads(incoming.pop(0).decode('utf-8'))
29
29
  self.peer_addr = incoming.pop(0).decode('utf-8')
30
- elif self.type == "JOIN" or self.type == "LEAVE":
30
+ elif self.type in ["JOIN", "LEAVE"]:
31
31
  self.group = incoming.pop(0).decode('utf-8')
32
32
  elif self.type == "WHISPER":
33
33
  self.msg = incoming
@@ -44,9 +44,7 @@ class PyreEvent(object):
44
44
  Returns:
45
45
  str: Header value
46
46
  """
47
- if self.headers and name in self.headers:
48
- return self.headers[name]
49
- return None
47
+ return self.headers[name] if self.headers and name in self.headers else None
50
48
 
51
49
  @property
52
50
  def peer_uuid(self):
@@ -301,7 +301,7 @@ class PyreNode(object):
301
301
  logger.warning("Unkown Node API command: {0}".format(command))
302
302
 
303
303
  def purge_peer(self, peer, endpoint):
304
- if (peer.get_endpoint() == endpoint):
304
+ if peer.get_endpoint() == endpoint:
305
305
  self.remove_peer(peer)
306
306
  peer.disconnect()
307
307
  logger.debug("Purge peer: {0}{1}".format(peer,endpoint))
@@ -411,7 +411,7 @@ class PyreNode(object):
411
411
 
412
412
  # Ignore command if peer isn't ready
413
413
  if not peer or not peer.get_ready():
414
- logger.warning("Peer {0} isn't ready".format(peer))
414
+ logger.debug("Peer {0} isn't ready".format(peer))
415
415
  return
416
416
 
417
417
  if peer.messages_lost(zmsg):
@@ -531,8 +531,7 @@ class PyreNode(object):
531
531
  reap_at = time.time() + REAP_INTERVAL
532
532
  while not self._terminated:
533
533
  timeout = reap_at - time.time()
534
- if timeout < 0:
535
- timeout = 0
534
+ timeout = max(timeout, 0)
536
535
  items = dict(self.poller.poll(timeout * 1000))
537
536
 
538
537
  if self._pipe in items and items[self._pipe] == zmq.POLLIN:
@@ -1,4 +1,3 @@
1
-
2
1
  # ======================================================================
3
2
  # zbeacon - LAN discovery and presence
4
3
  #
@@ -38,28 +37,30 @@ import netaddr
38
37
  logger = logging.getLogger(__name__)
39
38
 
40
39
  INTERVAL_DFLT = 1.0
41
- BEACON_MAX = 255 # Max size of beacon data
42
- MULTICAST_GRP = '225.25.25.25'
43
- ENETDOWN = 50 #socket error, network is down
44
- ENETUNREACH = 51 #socket error, network unreachable
40
+ BEACON_MAX = 255 # Max size of beacon data
41
+ MULTICAST_GRP = "225.25.25.25"
42
+ ENETDOWN = 50 # socket error, network is down
43
+ ENETUNREACH = 51 # socket error, network unreachable
45
44
 
46
45
 
47
46
  class ZBeacon(object):
48
47
 
49
48
  def __init__(self, ctx, pipe, *args, **kwargs):
50
- self.ctx = ctx # ZMQ context
51
- self.pipe = pipe # Actor command pipe
52
- self.udpsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
53
- # UDP socket for send/recv
54
- self.port_nbr = 0 # UDP port number we work on
55
- self.interval = INTERVAL_DFLT # Beacon broadcast interval
56
- self.ping_at = 0 # Next broadcast time
57
- self.transmit = None # Beacon transmit data
58
- self.filter = b"" # Beacon filter data
59
-
60
- self.terminated = False # Did caller ask us to quit?
61
- self.verbose = False # Verbose logging enabled?
62
- self.hostname = "" # Saved host name
49
+ self.ctx = ctx # ZMQ context
50
+ self.pipe = pipe # Actor command pipe
51
+ self.udpsock = socket.socket(
52
+ socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP
53
+ )
54
+ # UDP socket for send/recv
55
+ self.port_nbr = 0 # UDP port number we work on
56
+ self.interval = INTERVAL_DFLT # Beacon broadcast interval
57
+ self.ping_at = 0 # Next broadcast time
58
+ self.transmit = None # Beacon transmit data
59
+ self.filter = b"" # Beacon filter data
60
+
61
+ self.terminated = False # Did caller ask us to quit?
62
+ self.verbose = False # Verbose logging enabled?
63
+ self.hostname = "" # Saved host name
63
64
 
64
65
  self.address = None
65
66
  self.mac = None
@@ -73,23 +74,25 @@ class ZBeacon(object):
73
74
  self.udpsock.close()
74
75
 
75
76
  def prepare_udp(self, interface_name=None):
76
- self._prepare_socket(interface_name)
77
+ try:
78
+ self._prepare_socket(interface_name)
79
+ except ValueError:
80
+ logger.exception("Error preparing socket:")
81
+ return
77
82
  try:
78
83
  self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
79
84
  self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
80
85
 
81
86
  # On some platforms we have to ask to reuse the port
82
87
  try:
83
- self.udpsock.setsockopt(socket.SOL_SOCKET,
84
- socket.SO_REUSEPORT, 1)
88
+ self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
85
89
 
86
90
  except AttributeError:
87
91
  pass
88
92
 
89
93
  if self.broadcast_address.is_multicast:
90
94
  # TTL
91
- self.udpsock.setsockopt(socket.IPPROTO_IP,
92
- socket.IP_MULTICAST_TTL, 2)
95
+ self.udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
93
96
 
94
97
  # TODO: This should only be used if we do not have inproc method!
95
98
  self.udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
@@ -117,48 +120,63 @@ class ZBeacon(object):
117
120
  self.udpsock.bind(("", self.port_nbr))
118
121
 
119
122
  group = socket.inet_aton("{0}".format(self.broadcast_address))
120
- mreq = struct.pack('4sl', group, socket.INADDR_ANY)
123
+ mreq = struct.pack("4sl", group, socket.INADDR_ANY)
121
124
 
122
- self.udpsock.setsockopt(socket.SOL_IP,
123
- socket.IP_ADD_MEMBERSHIP, mreq)
125
+ self.udpsock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, mreq)
124
126
 
125
127
  else:
126
128
  # Platform specifics
127
129
  if platform.startswith("linux"):
128
130
  # on linux we bind to the broadcast address and send to
129
131
  # the broadcast address
130
- self.udpsock.bind((str(self.broadcast_address),
131
- self.port_nbr))
132
+ self.udpsock.bind((str(self.broadcast_address), self.port_nbr))
132
133
  else:
133
134
  self.udpsock.bind(("", self.port_nbr))
134
135
 
135
- logger.debug("Set up a broadcast beacon to {0}:{1}".format(self.broadcast_address, self.port_nbr))
136
+ logger.debug(
137
+ "Set up a broadcast beacon to {0}:{1}".format(
138
+ self.broadcast_address, self.port_nbr
139
+ )
140
+ )
136
141
  except socket.error:
137
- logger.exception("Initializing of {0} raised an exception".format(self.__class__.__name__))
142
+ logger.exception(
143
+ "Initializing of {0} raised an exception".format(
144
+ self.__class__.__name__
145
+ )
146
+ )
138
147
 
139
148
  def _prepare_socket(self, interface_name=None):
140
149
  netinf = zhelper.get_ifaddrs()
141
150
  logger.debug("Available interfaces: {0}".format(netinf))
142
151
 
143
- #get default gateway interface
152
+ # get default gateway interface
144
153
  default_interface_names = []
145
154
  netifaces_default_interface_names = []
146
155
  gateways = netifaces.gateways()
147
156
  logger.debug("Gateways: {0}".format(gateways))
148
157
  if netifaces.AF_INET in gateways:
149
158
  for address, interface, is_default in gateways[netifaces.AF_INET]:
150
- #fix for windows (netifaces.gateway() returns adapter name instead of interface name)
159
+ # fix for windows (netifaces.gateway() returns adapter name instead of interface name)
151
160
  if platform.startswith("win"):
152
161
  netifaces_default_interface_names.append(interface)
153
162
  for iface in netinf:
154
163
  for name, data in iface.items():
155
- if netifaces.AF_INET in data and data[netifaces.AF_INET]['adapter']==interface:
164
+ if (
165
+ netifaces.AF_INET in data
166
+ and data[netifaces.AF_INET]["adapter"] == interface
167
+ ):
156
168
  default_interface_names.append(name)
157
169
  else:
158
170
  default_interface_names.append(interface)
159
-
160
- logger.debug('Default interface names "{0}"'.format(list(default_interface_names)))
161
- logger.debug('Netifaces default interface names "{0}"'.format(list(netifaces_default_interface_names)))
171
+
172
+ logger.debug(
173
+ "Default interface names '{0}'".format(list(default_interface_names))
174
+ )
175
+ logger.debug(
176
+ "Netifaces default interface names '{0}'".format(
177
+ list(netifaces_default_interface_names)
178
+ )
179
+ )
162
180
 
163
181
  for iface in netinf:
164
182
  # Loop over the interfaces and their settings to try to find the broadcast address.
@@ -168,39 +186,53 @@ class ZBeacon(object):
168
186
  if interface_name and interface_name != name:
169
187
  continue
170
188
 
171
- #Interface of default route found, skip other ones
172
- #This trick allows to skip invalid interfaces like docker ones.
173
- if len(default_interface_names)>0 and name not in default_interface_names:
174
- logger.debug('Interface "{0}" is not interface of default route'.format(name))
189
+ # Interface of default route found, skip other ones
190
+ # This trick allows to skip invalid interfaces like docker ones.
191
+ if (
192
+ len(default_interface_names) > 0
193
+ and name not in default_interface_names
194
+ ):
195
+ logger.debug(
196
+ "Interface '{0}' is not interface of default route".format(name)
197
+ )
175
198
  continue
176
199
 
177
- logger.debug('Checking out interface "{0}".'.format(name))
200
+ logger.debug("Checking out interface '{0}'.".format(name))
178
201
 
179
- #Get addr and netmask infos
202
+ # Get addr and netmask infos
180
203
  data_2 = data.get(netifaces.AF_INET)
181
204
  if not data_2:
182
- logger.debug('No data_2 found for interface "{0}".'.format(name))
205
+ logger.debug("No data_2 found for interface '{0}'.".format(name))
183
206
  continue
184
207
 
185
- #get mac address infos
186
- data_17 = data.get(netifaces.AF_LINK)
208
+ # get mac address infos
209
+ data_17 = data.get(netifaces.AF_PACKET)
187
210
  if not data_17 and platform.startswith("win"):
188
- #last chance to get mac address on windows platform
189
- for netifaces_default_interface_name in netifaces_default_interface_names:
190
- ifaddresses = netifaces.ifaddresses(netifaces_default_interface_name)
191
- if netifaces.AF_LINK in ifaddresses and len(ifaddresses[netifaces.AF_LINK])>0:
192
- data_17 = ifaddresses[netifaces.AF_LINK][0]
211
+ # last chance to get mac address on windows platform
212
+ for (
213
+ netifaces_default_interface_name
214
+ ) in netifaces_default_interface_names:
215
+ ifaddresses = netifaces.ifaddresses(
216
+ netifaces_default_interface_name
217
+ )
218
+ if (
219
+ netifaces.AF_PACKET in ifaddresses
220
+ and len(ifaddresses[netifaces.AF_PACKET]) > 0
221
+ ):
222
+ data_17 = ifaddresses[netifaces.AF_PACKET][0]
193
223
  break
194
224
  if not data_17:
195
- logger.debug('No data_17 found for interface "{0}".'.format(name))
225
+ logger.debug("No data_17 found for interface '{0}'.".format(name))
196
226
  continue
197
227
 
198
228
  address_str = data_2.get("addr")
199
229
  netmask_str = data_2.get("netmask")
200
- mac_str = data_17.get("addr")
230
+ mac_str = data_17.get("addr")
201
231
 
202
232
  if not address_str or not netmask_str:
203
- logger.debug('Address or netmask not found for interface "{0}".'.format(name))
233
+ logger.debug(
234
+ "Address or netmask not found for interface '{0}'.".format(name)
235
+ )
204
236
  continue
205
237
 
206
238
  if isinstance(address_str, bytes):
@@ -212,10 +244,24 @@ class ZBeacon(object):
212
244
  if isinstance(mac_str, bytes):
213
245
  mac_str = mac_str.decode("utf8")
214
246
 
215
- #keep only private interface
247
+ # keep only private interface
216
248
  ip_address = netaddr.IPAddress(address_str)
217
- if ip_address and not ip_address.is_private():
218
- logger.debug('Interface "{0}" refers to public ip address, drop it.'.format(name))
249
+ # handle netaddr breaking changes
250
+ if netaddr.__version__.startswith("0."):
251
+ # is_private does not exist anymore on new IpAddress lib version
252
+ # pylint: disable=no-member
253
+ ip_is_private = ip_address.is_private()
254
+ else:
255
+ ip_is_private = (
256
+ ip_address.is_ipv4_private_use()
257
+ or ip_address.is_ipv6_unique_local()
258
+ )
259
+ if ip_address and not ip_is_private:
260
+ logger.debug(
261
+ "Interface '{0}' refers to public ip address, drop it.".format(
262
+ name
263
+ )
264
+ )
219
265
  continue
220
266
 
221
267
  interface_string = "{0}/{1}".format(address_str, netmask_str)
@@ -223,11 +269,11 @@ class ZBeacon(object):
223
269
  interface = ipaddress.ip_interface(u(interface_string))
224
270
 
225
271
  if interface.is_loopback:
226
- logger.debug('Interface "{0}" is a loopback device.'.format(name))
272
+ logger.debug("Interface {0} is a loopback device.".format(name))
227
273
  continue
228
274
 
229
275
  if interface.is_link_local:
230
- logger.debug('Interface "{0}" is a link-local device.'.format(name))
276
+ logger.debug("Interface {0} is a link-local device.".format(name))
231
277
  continue
232
278
 
233
279
  self.address = interface.ip
@@ -238,17 +284,17 @@ class ZBeacon(object):
238
284
 
239
285
  if self.address:
240
286
  break
241
-
287
+
242
288
  if self.address:
243
289
  break
244
290
 
245
291
  logger.debug("Finished scanning interfaces.")
246
292
 
247
293
  if not self.address:
248
- self.network_address = ipaddress.IPv4Address(u('127.0.0.1'))
294
+ self.network_address = ipaddress.IPv4Address(u("127.0.0.1"))
249
295
  self.broadcast_address = ipaddress.IPv4Address(u(MULTICAST_GRP))
250
- self.interface_name = 'loopback'
251
- self.address = u('127.0.0.1')
296
+ self.interface_name = "loopback"
297
+ self.address = u("127.0.0.1")
252
298
  self.mac = None
253
299
 
254
300
  logger.debug("Address: {0}".format(self.address))
@@ -265,9 +311,9 @@ class ZBeacon(object):
265
311
  def handle_pipe(self):
266
312
  # Get just the commands off the pipe
267
313
  request = self.pipe.recv_multipart()
268
- command = request.pop(0).decode('UTF-8')
314
+ command = request.pop(0).decode("UTF-8")
269
315
  if not command:
270
- return -1 # Interrupted
316
+ return -1 # Interrupted
271
317
 
272
318
  if self.verbose:
273
319
  logger.debug("zbeacon: API command={0}".format(command))
@@ -278,10 +324,13 @@ class ZBeacon(object):
278
324
  # unpacking code from https://bit.ly/2qN3ZUz
279
325
  interface_data = request.pop(0)
280
326
 
281
- (interface_name_len,), interface = struct.unpack('I', interface_data[:4]), interface_data[4:]
282
- interface = interface.decode('UTF-8')
327
+ (interface_name_len,), interface = (
328
+ struct.unpack("I", interface_data[:4]),
329
+ interface_data[4:],
330
+ )
331
+ interface = interface.decode("UTF-8")
283
332
 
284
- port = struct.unpack('I', request.pop(0))[0]
333
+ port = struct.unpack("I", request.pop(0))[0]
285
334
  self.configure(interface, port)
286
335
  elif command == "PUBLISH":
287
336
  self.transmit = request.pop(0)
@@ -314,8 +363,8 @@ class ZBeacon(object):
314
363
  is_valid = False
315
364
  if self.filter is not None:
316
365
  if len(self.filter) <= len(frame):
317
- match_data = frame[:len(self.filter)]
318
- if (match_data == self.filter):
366
+ match_data = frame[: len(self.filter)]
367
+ if match_data == self.filter:
319
368
  is_valid = True
320
369
 
321
370
  # If valid, discard our own broadcasts, which UDP echoes to us
@@ -330,22 +379,24 @@ class ZBeacon(object):
330
379
 
331
380
  def send_beacon(self):
332
381
  try:
333
- self.udpsock.sendto(self.transmit, (str(self.broadcast_address),
334
- self.port_nbr))
335
-
382
+ self.udpsock.sendto(
383
+ self.transmit, (str(self.broadcast_address), self.port_nbr)
384
+ )
385
+
336
386
  except OSError as e:
337
-
387
+
338
388
  # network down, just wait, it could come back up again.
339
389
  # socket call errors 50 and 51 relate to the network being
340
- # down or unreachable, the recommended action to take is to
390
+ # down or unreachable, the recommended action to take is to
341
391
  # try again so we don't terminate in these cases.
342
- if e.errno in [ENETDOWN, ENETUNREACH]: pass
343
-
392
+ if e.errno in [ENETDOWN, ENETUNREACH]:
393
+ pass
394
+
344
395
  # all other cases, we'll terminate
345
396
  else:
346
397
  logger.debug("Network seems gone, exiting zbeacon")
347
398
  self.terminated = True
348
-
399
+
349
400
  except socket.error:
350
401
  logger.debug("Network seems gone, exiting zbeacon")
351
402
  self.terminated = True
@@ -368,7 +419,10 @@ class ZBeacon(object):
368
419
  items = dict(self.poller.poll(timeout * 1000))
369
420
  if self.pipe in items and items[self.pipe] == zmq.POLLIN:
370
421
  self.handle_pipe()
371
- if self.udpsock.fileno() in items and items[self.udpsock.fileno()] == zmq.POLLIN:
422
+ if (
423
+ self.udpsock.fileno() in items
424
+ and items[self.udpsock.fileno()] == zmq.POLLIN
425
+ ):
372
426
  self.handle_udp()
373
427
 
374
428
  if self.transmit and time.time() >= self.ping_at:
@@ -376,18 +430,20 @@ class ZBeacon(object):
376
430
  self.ping_at = time.time() + self.interval
377
431
 
378
432
 
379
- if __name__ == '__main__':
433
+ if __name__ == "__main__":
380
434
  import zmq
381
435
  import struct
382
436
  import time
437
+
383
438
  speaker = ZActor(zmq.Context(), ZBeacon)
384
439
  speaker.send_unicode("VERBOSE")
385
440
  speaker.send_unicode("CONFIGURE", zmq.SNDMORE)
386
441
  speaker.send(struct.pack("I", 9999))
387
442
  speaker.send_unicode("PUBLISH", zmq.SNDMORE)
388
443
  import uuid
389
- transmit = struct.pack('cccb16sH', b'Z', b'R', b'E',
390
- 1, uuid.uuid4().bytes,
391
- socket.htons(1300))
444
+
445
+ transmit = struct.pack(
446
+ "cccb16sH", b"Z", b"R", b"E", 1, uuid.uuid4().bytes, socket.htons(1300)
447
+ )
392
448
  speaker.send(transmit)
393
449
  speaker.destroy()
@@ -414,9 +414,7 @@ class ZreMsg(object):
414
414
  group_len = self._get_number4()
415
415
  #print("needle is at: %i"% self._needle )
416
416
  #print("grouplen: ", group_len)
417
- self.groups = []
418
- for x in range(group_len):
419
- self.groups.append(self._get_long_string())
417
+ self.groups = [self._get_long_string() for _ in range(group_len)]
420
418
  #print(self.groups)
421
419
  #print("post_group: needle is at: %i"% self._needle )
422
420
  self.status = self._get_number1()
@@ -1,16 +1,15 @@
1
- Metadata-Version: 1.2
1
+ Metadata-Version: 2.1
2
2
  Name: pyre-gevent
3
- Version: 0.2.4.dev0
3
+ Version: 0.3.1
4
4
  Summary: Python ZRE implementation (green version)
5
5
  Home-page: http://www.github.com/tangb/pyre-gevent/
6
6
  Author: Arnaud Loonstra
7
7
  Author-email: arnaud@sphaero.org
8
8
  Maintainer: Tanguy Bonneau
9
9
  Maintainer-email: tanguy.bonneau@gmail.com
10
- License: UNKNOWN
11
- Description: UNKNOWN
12
- Platform: UNKNOWN
13
10
  Requires: pyzmq
14
11
  Requires: ipaddress
15
12
  Requires: netaddr
16
- Requires: netifaces
13
+ Requires: netifaces2
14
+ License-File: LICENSE
15
+ License-File: AUTHORS
@@ -19,4 +19,9 @@ pyre_gevent.egg-info/PKG-INFO
19
19
  pyre_gevent.egg-info/SOURCES.txt
20
20
  pyre_gevent.egg-info/dependency_links.txt
21
21
  pyre_gevent.egg-info/requires.txt
22
- pyre_gevent.egg-info/top_level.txt
22
+ pyre_gevent.egg-info/top_level.txt
23
+ tests/test_network_disconnect.py
24
+ tests/test_pyre.py
25
+ tests/test_zactor.py
26
+ tests/test_zbeacon.py
27
+ tests/test_zhelper.py
@@ -1,4 +1,4 @@
1
1
  ipaddress
2
2
  netaddr
3
- netifaces
3
+ netifaces2
4
4
  pyzmq
@@ -37,6 +37,6 @@ setup(
37
37
  url='http://www.github.com/tangb/pyre-gevent/',
38
38
  packages=['pyre_gevent'],
39
39
  include_package_data=True,
40
- requires=['pyzmq', 'ipaddress', 'netaddr', 'netifaces'],
41
- install_requires=['pyzmq', 'ipaddress', 'netaddr', 'netifaces'],
40
+ requires=['pyzmq', 'ipaddress', 'netaddr', 'netifaces2'],
41
+ install_requires=['pyzmq', 'ipaddress', 'netaddr', 'netifaces2'],
42
42
  )
@@ -0,0 +1,81 @@
1
+ import os
2
+ import time
3
+ import logging
4
+ import subprocess
5
+ import pyre
6
+
7
+
8
+ # The test needs the device name of the active network interface.
9
+ # The device name can be found under `DEVICE` column after running `nmcli c`.
10
+ # The device name should be set to the variable bellow, or as the `DEVICE` env variable.
11
+ NMCLI_DEVICE: str = None
12
+
13
+ NMCLI_LINETERMINATOR = "\n"
14
+ NMCLI_DELIMITER = " "
15
+
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ def _network_device() -> str:
21
+ return NMCLI_DEVICE or os.environ.get("DEVICE", None)
22
+
23
+
24
+ def _network_device_is_enabled(device: str) -> bool:
25
+ result = subprocess.run(["nmcli", "c"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
26
+ assert result.returncode == 0, result.stderr.decode("ascii")
27
+ output = result.stdout.decode("ascii")
28
+ rows = [[val.strip() for val in row.split(NMCLI_DELIMITER) if val.strip()] for row in output.split(NMCLI_LINETERMINATOR) if row.strip()]
29
+ head, rows = rows[0], rows[1:]
30
+ devices = [dict(zip(head, row)) for row in rows]
31
+ return any(d["DEVICE"] == device for d in devices)
32
+
33
+
34
+ def _network_device_enable(device: str, enable: bool):
35
+ if _network_device_is_enabled(device) == enable:
36
+ return
37
+ cmd = 'connect' if enable else 'disconnect'
38
+ result = subprocess.run(["nmcli", "d", cmd, f"{device}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
39
+ assert result.returncode == 0, result.stderr.decode("ascii")
40
+ time.sleep(3)
41
+ while _network_device_is_enabled(device) != enable:
42
+ pass
43
+ logger.debug("Device \"{device}\" was {cmd}ed")
44
+
45
+
46
+ def test_network_disconnect(group="best-group"):
47
+
48
+ device = _network_device()
49
+
50
+ if device is None:
51
+ logger.warn("Skipping test. Please specify an active network interface to use for testing.")
52
+ return
53
+
54
+ _network_device_enable(device, enable=True)
55
+
56
+ try:
57
+ pyre_node = pyre.Pyre(name="foo")
58
+ pyre_node.join(group)
59
+ pyre_node.start()
60
+ logger.debug("Pyre started")
61
+
62
+ _network_device_enable(device, enable=False)
63
+
64
+ pyre_node.leave(group)
65
+ logger.debug("Pyre left group")
66
+
67
+ pyre_node.stop()
68
+ logger.debug("Pyre stopped")
69
+
70
+ del pyre_node
71
+ logger.debug("Pyre destroyed")
72
+
73
+ except KeyboardInterrupt:
74
+ pass
75
+
76
+ finally:
77
+ _network_device_enable(device, enable=True)
78
+
79
+
80
+ if __name__ == '__main__':
81
+ test_network_disconnect()
@@ -0,0 +1,178 @@
1
+ import unittest
2
+ import pyre
3
+ import zmq
4
+ import time
5
+ import logging
6
+ import sys
7
+
8
+
9
+ if sys.version.startswith('3'):
10
+ unicode = str
11
+
12
+
13
+ class PyreTest(unittest.TestCase):
14
+ def setUp(self, *args, **kwargs):
15
+ ctx = zmq.Context()
16
+ self.node1 = pyre.Pyre("node1", ctx=ctx)
17
+ self.node1.set_header("X-TEST", "1")
18
+ self.node2 = pyre.Pyre("node2", ctx=ctx)
19
+ self.node2.set_header("X-TEST", "1")
20
+ self.node1.start()
21
+ self.node2.start()
22
+ # give time for nodes to exchange
23
+ time.sleep(1)
24
+ # end setUp
25
+
26
+ def tearDown(self):
27
+ self.node1.stop()
28
+ self.node2.stop()
29
+ # end tearDown
30
+
31
+ def test_get_name(self):
32
+ self.assertEqual("node1", self.node1.name())
33
+ self.assertEqual("node2", self.node2.name())
34
+ # end test_get_name
35
+
36
+ def test_get_peers(self):
37
+ id1 = self.node1.uuid()
38
+ peers = self.node2.peers()
39
+
40
+ self.assertIsInstance(peers, list)
41
+ self.assertIn(id1, peers)
42
+ # end test_get_peers
43
+
44
+ def test_get_peers_by_group(self):
45
+ id1 = self.node1.uuid()
46
+ self.node1.join("TEST")
47
+ # pyre works asynchronous so give some time to let changes disperse
48
+ time.sleep(0.5)
49
+
50
+ peers = self.node2.peers_by_group("TEST")
51
+ self.node1.leave("TEST")
52
+
53
+ self.assertIsInstance(peers, list)
54
+ self.assertIn(id1, peers)
55
+ # end test_get_peers
56
+
57
+ def test_get_peer_address(self):
58
+ id1 = self.node1.uuid()
59
+ id2 = self.node2.uuid()
60
+
61
+ self.assertIsInstance(self.node1.peer_address(id2), unicode)
62
+ self.assertIsInstance(self.node2.peer_address(id1), unicode)
63
+ # end test_get_peer_address
64
+
65
+ def test_peer_header_value(self):
66
+ id1 = self.node1.uuid()
67
+ id2 = self.node2.uuid()
68
+
69
+ self.assertEqual("1", self.node1.peer_header_value(id2, "X-TEST"))
70
+ self.assertEqual("1", self.node2.peer_header_value(id1, "X-TEST"))
71
+ # end test_get_peer_header_value
72
+
73
+ def test_get_own_groups(self):
74
+ self.node1.join("TEST")
75
+ self.node2.join("TEST")
76
+ # pyre works asynchronous so give some time to let changes disperse
77
+ time.sleep(0.5)
78
+
79
+ self.assertIn("TEST", self.node1.own_groups())
80
+ self.assertIn("TEST", self.node2.own_groups())
81
+ # end test_get_own_groups
82
+
83
+ def test_join_leave_msg(self):
84
+ msg = self.node1.recv()
85
+ self.assertEqual(msg[0], b'ENTER')
86
+ msg = self.node2.recv()
87
+ self.assertEqual(msg[0], b'ENTER')
88
+ self.node1.join("TEST")
89
+ self.node2.join("TEST")
90
+ msg = self.node1.recv()
91
+ self.assertEqual(msg[0], b'JOIN')
92
+ msg = self.node2.recv()
93
+ self.assertEqual(msg[0], b'JOIN')
94
+ self.node1.leave("TEST")
95
+ self.node2.leave("TEST")
96
+ msg = self.node1.recv()
97
+ self.assertEqual(msg[0], b'LEAVE')
98
+ msg = self.node2.recv()
99
+ self.assertEqual(msg[0], b'LEAVE')
100
+
101
+ def test_get_peer_groups(self):
102
+ self.node1.join("TEST")
103
+ self.node2.join("TEST")
104
+
105
+ # pyre works asynchronous so give some time to let changes disperse
106
+ time.sleep(0.5)
107
+
108
+ self.assertIn("TEST", self.node1.peer_groups())
109
+ self.assertIn("TEST", self.node2.peer_groups())
110
+ # end test_get_peer_groups
111
+
112
+ def test_whispers(self):
113
+ msg = self.node1.recv()
114
+ self.assertEqual(msg[0], b'ENTER')
115
+ msg = self.node2.recv()
116
+ self.assertEqual(msg[0], b'ENTER')
117
+ self.node1.whispers(self.node2.uuid(), "Hi")
118
+ msg = self.node2.recv()
119
+ self.assertEqual(b"WHISPER", msg[0])
120
+ self.assertEqual(self.node1.uuid().bytes, msg[1])
121
+ self.assertEqual(b"node1", msg[2])
122
+ self.assertEqual(b"Hi", msg[3])
123
+
124
+ def test_shouts(self):
125
+ msg = self.node1.recv()
126
+ self.assertEqual(msg[0], b'ENTER')
127
+ msg = self.node2.recv()
128
+ self.assertEqual(msg[0], b'ENTER')
129
+ self.node1.join("TEST")
130
+ self.node2.join("TEST")
131
+ msg = self.node1.recv()
132
+ self.assertEqual(msg[0], b'JOIN')
133
+ msg = self.node2.recv()
134
+ self.assertEqual(msg[0], b'JOIN')
135
+ self.node1.shouts("TEST", "Hi")
136
+ msg = self.node2.recv()
137
+ self.assertEqual(b"SHOUT", msg[0])
138
+ self.assertEqual(self.node1.uuid().bytes, msg[1])
139
+ self.assertEqual(b"node1", msg[2])
140
+ self.assertEqual(b"TEST", msg[3])
141
+ self.assertEqual(b"Hi", msg[4])
142
+
143
+ def test_shout(self):
144
+ msg = self.node1.recv()
145
+ self.assertEqual(msg[0], b'ENTER')
146
+ msg = self.node2.recv()
147
+ self.assertEqual(msg[0], b'ENTER')
148
+ self.node1.join("TEST")
149
+ self.node2.join("TEST")
150
+ msg = self.node1.recv()
151
+ self.assertEqual(msg[0], b'JOIN')
152
+ msg = self.node2.recv()
153
+ self.assertEqual(msg[0], b'JOIN')
154
+ self.node1.shout("TEST", b"Hi")
155
+ msg = self.node2.recv()
156
+ self.assertEqual(b"SHOUT", msg[0])
157
+ self.assertEqual(self.node1.uuid().bytes, msg[1])
158
+ self.assertEqual(b"node1", msg[2])
159
+ self.assertEqual(b"TEST", msg[3])
160
+ self.assertEqual(b"Hi", msg[4])
161
+
162
+ def test_zfinal(self):
163
+ global inst_count
164
+ inst_count = 1
165
+ self.assertTrue(True)
166
+ # end test_zfinal
167
+ # end PyreTest
168
+
169
+ if __name__ == '__main__':
170
+ inst_count = 0
171
+
172
+ logger = logging.getLogger("pyre")
173
+ logger.setLevel(logging.DEBUG)
174
+
175
+ try:
176
+ unittest.main()
177
+ except Exception as a:
178
+ print(a)
@@ -0,0 +1,38 @@
1
+ import unittest
2
+ import zmq
3
+ import logging
4
+ from pyre import zactor
5
+ from pyre.zactor import ZActor
6
+ from pyre.zbeacon import ZBeacon
7
+
8
+ class ZBeaconTest(unittest.TestCase):
9
+
10
+ def setUp(self, *args, **kwargs):
11
+ ctx = zmq.Context()
12
+ self.actor = ZActor(ctx, zactor.echo_actor, "Hello, World")
13
+ # end setUp
14
+
15
+ def tearDown(self):
16
+ self.actor.destroy()
17
+ # end tearDown
18
+
19
+ def test_echo(self):
20
+ self.actor.send_multipart((b"ECHO", b"This is a string"))
21
+ msg = self.actor.recv()
22
+ self.assertEqual(b"This is a string", msg)
23
+ # end ZActorTest
24
+
25
+
26
+ if __name__ == '__main__':
27
+ #print(logging.Logger.manager.loggerDict)
28
+ logger = logging.getLogger()
29
+ logger.setLevel(logging.DEBUG)
30
+ ch = logging.StreamHandler()
31
+ ch.setLevel(logging.DEBUG)
32
+ logger.addHandler(ch)
33
+ logging.getLogger("pyre.zactor").setLevel(logging.DEBUG)
34
+
35
+ try:
36
+ unittest.main()
37
+ except Exception as a:
38
+ print(a)
@@ -0,0 +1,82 @@
1
+ import unittest
2
+ #import pyre
3
+ import zmq
4
+ import time
5
+ import struct
6
+ import uuid
7
+ import logging
8
+ import socket
9
+ from pyre.zactor import ZActor
10
+ from pyre.zbeacon import ZBeacon
11
+
12
+ class ZBeaconTest(unittest.TestCase):
13
+
14
+ def setUp(self, *args, **kwargs):
15
+ ctx = zmq.Context()
16
+ ctx = zmq.Context()
17
+ # two beacon frames
18
+ self.transmit1 = struct.pack('cccb16sH', b'Z', b'R', b'E',
19
+ 1, uuid.uuid4().bytes,
20
+ socket.htons(9999))
21
+ self.transmit2 = struct.pack('cccb16sH', b'Z', b'R', b'E',
22
+ 1, uuid.uuid4().bytes,
23
+ socket.htons(9999))
24
+
25
+ self.node1 = ZActor(ctx, ZBeacon)
26
+ self.node1.send_unicode("VERBOSE")
27
+ self.node1.send_unicode("CONFIGURE", zmq.SNDMORE)
28
+ self.node1.send(struct.pack("I", 9999))
29
+ print("Hostname 1:", self.node1.recv_unicode())
30
+
31
+ self.node2 = ZActor(ctx, ZBeacon)
32
+ self.node2.send_unicode("VERBOSE")
33
+ self.node2.send_unicode("CONFIGURE", zmq.SNDMORE)
34
+ self.node2.send(struct.pack("I", 9999))
35
+ print("Hostname 2:", self.node2.recv_unicode())
36
+ # end setUp
37
+
38
+ def tearDown(self):
39
+ self.node1.destroy()
40
+ self.node2.destroy()
41
+ # end tearDown
42
+
43
+ def test_node1(self):
44
+ self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
45
+ self.node1.send(self.transmit1)
46
+
47
+ def test_node2(self):
48
+ self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
49
+ self.node2.send(self.transmit2)
50
+
51
+ def test_recv_beacon1(self):
52
+ self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
53
+ self.node1.send(self.transmit1)
54
+ self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
55
+ self.node2.send(self.transmit2)
56
+ req = self.node1.recv_multipart()
57
+ self.assertEqual(self.transmit2, req[1])
58
+
59
+ def test_recv_beacon1(self):
60
+ self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
61
+ self.node1.send(self.transmit1)
62
+ self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
63
+ self.node2.send(self.transmit2)
64
+ req = self.node2.recv_multipart()
65
+ self.assertEqual(self.transmit1, req[1])
66
+
67
+ # end ZBeaconTest
68
+
69
+ if __name__ == '__main__':
70
+
71
+ #print(logging.Logger.manager.loggerDict)
72
+ logger = logging.getLogger()
73
+ logger.setLevel(logging.DEBUG)
74
+ ch = logging.StreamHandler()
75
+ ch.setLevel(logging.DEBUG)
76
+ logger.addHandler(ch)
77
+ logging.getLogger("pyre.zbeacon2").setLevel(logging.DEBUG)
78
+
79
+ try:
80
+ unittest.main()
81
+ except Exception as a:
82
+ print(a)
@@ -0,0 +1,32 @@
1
+ import unittest
2
+ from pyre import zhelper
3
+ from pyre import zbeacon
4
+ import zmq
5
+ import time
6
+
7
+ class ZHelperTest(unittest.TestCase):
8
+
9
+ def test_get_ifaddrs(self):
10
+ ifs = zhelper.get_ifaddrs()
11
+ self.assertIsInstance(ifs, list)
12
+ self.assertIsInstance(ifs[0], dict)
13
+ # end test_get_ifaddrs
14
+
15
+ def test_get_ifaddrs_loopback(self):
16
+ ifs = zhelper.get_ifaddrs()
17
+ addrs = []
18
+ for iface in ifs:
19
+ #print(iface)
20
+ for i,v in iface.items():
21
+ #print(i,v)
22
+ # 2 is for ipv4
23
+ if v.get(2):
24
+ addrs.append(v[2]['addr'])
25
+ self.assertIn('127.0.0.1', addrs)
26
+ # end test_get_ifaddrs_loopback
27
+
28
+ # end ZHelperTest
29
+
30
+ if __name__ == '__main__':
31
+ unittest.main()
32
+
@@ -1,8 +0,0 @@
1
- import re
2
-
3
- __all__ = ['pyre', 'zbeacon', 'zhelper']
4
- __version__ = '0.2.4.dev0'
5
- __version_info__ = tuple(int(v) for v in re.sub('[a-zA-Z]', '', __version__).split('.'))
6
-
7
- from .pyre import Pyre
8
- from .pyre_event import PyreEvent
File without changes
File without changes
File without changes
File without changes