session.py
122 lines
| 3.2 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r2597 | import os | ||
import uuid | ||||
import pprint | ||||
import zmq | ||||
class Message(object): | ||||
"""A simple message object that maps dict keys to attributes. | ||||
A Message can be created from a dict and a dict from a Message instance | ||||
simply by calling dict(msg_obj).""" | ||||
def __init__(self, msg_dict): | ||||
dct = self.__dict__ | ||||
for k, v in msg_dict.iteritems(): | ||||
if isinstance(v, dict): | ||||
v = Message(v) | ||||
dct[k] = v | ||||
# Having this iterator lets dict(msg_obj) work out of the box. | ||||
def __iter__(self): | ||||
return iter(self.__dict__.iteritems()) | ||||
def __repr__(self): | ||||
return repr(self.__dict__) | ||||
def __str__(self): | ||||
return pprint.pformat(self.__dict__) | ||||
def __contains__(self, k): | ||||
return k in self.__dict__ | ||||
def __getitem__(self, k): | ||||
return self.__dict__[k] | ||||
def msg_header(msg_id, username, session): | ||||
return { | ||||
'msg_id' : msg_id, | ||||
'username' : username, | ||||
'session' : session | ||||
} | ||||
def extract_header(msg_or_header): | ||||
"""Given a message or header, return the header.""" | ||||
if not msg_or_header: | ||||
return {} | ||||
try: | ||||
# See if msg_or_header is the entire message. | ||||
h = msg_or_header['header'] | ||||
except KeyError: | ||||
try: | ||||
# See if msg_or_header is just the header | ||||
h = msg_or_header['msg_id'] | ||||
except KeyError: | ||||
raise | ||||
else: | ||||
h = msg_or_header | ||||
if not isinstance(h, dict): | ||||
h = dict(h) | ||||
return h | ||||
class Session(object): | ||||
Brian Granger
|
r2606 | def __init__(self, username=os.environ.get('USER','username'), session=None): | ||
Fernando Perez
|
r2597 | self.username = username | ||
Brian Granger
|
r2606 | if session is None: | ||
self.session = str(uuid.uuid4()) | ||||
else: | ||||
self.session = session | ||||
Fernando Perez
|
r2597 | self.msg_id = 0 | ||
def msg_header(self): | ||||
h = msg_header(self.msg_id, self.username, self.session) | ||||
self.msg_id += 1 | ||||
return h | ||||
def msg(self, msg_type, content=None, parent=None): | ||||
msg = {} | ||||
msg['header'] = self.msg_header() | ||||
msg['parent_header'] = {} if parent is None else extract_header(parent) | ||||
msg['msg_type'] = msg_type | ||||
msg['content'] = {} if content is None else content | ||||
return msg | ||||
def send(self, socket, msg_type, content=None, parent=None, ident=None): | ||||
msg = self.msg(msg_type, content, parent) | ||||
if ident is not None: | ||||
socket.send(ident, zmq.SNDMORE) | ||||
socket.send_json(msg) | ||||
omsg = Message(msg) | ||||
return omsg | ||||
def recv(self, socket, mode=zmq.NOBLOCK): | ||||
try: | ||||
msg = socket.recv_json(mode) | ||||
except zmq.ZMQError, e: | ||||
if e.errno == zmq.EAGAIN: | ||||
# We can convert EAGAIN to None as we know in this case | ||||
# recv_json won't return None. | ||||
return None | ||||
else: | ||||
raise | ||||
return Message(msg) | ||||
def test_msg2obj(): | ||||
am = dict(x=1) | ||||
ao = Message(am) | ||||
assert ao.x == am['x'] | ||||
am['y'] = dict(z=1) | ||||
ao = Message(am) | ||||
assert ao.y.z == am['y']['z'] | ||||
k1, k2 = 'y', 'z' | ||||
assert ao[k1][k2] == am[k1][k2] | ||||
am2 = dict(ao) | ||||
assert am['x'] == am2['x'] | ||||
assert am['y']['z'] == am2['y']['z'] | ||||