Show More
@@ -1,5 +1,12 b'' | |||||
1 | #!/usr/bin/env python |
|
1 | #!/usr/bin/env python | |
2 | """edited session.py to work with streams, and move msg_type to the header |
|
2 | """Session object for building, serializing, sending, and receiving messages in | |
|
3 | IPython. The Session object supports serialization, HMAC signatures, and | |||
|
4 | metadata on messages. | |||
|
5 | ||||
|
6 | Also defined here are utilities for working with Sessions: | |||
|
7 | * A SessionFactory to be used as a base class for configurables that work with | |||
|
8 | Sessions. | |||
|
9 | * A Message object for convenience that allows attribute-access to the msg dict. | |||
3 | """ |
|
10 | """ | |
4 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
5 | # Copyright (C) 2010-2011 The IPython Development Team |
|
12 | # Copyright (C) 2010-2011 The IPython Development Team | |
@@ -31,8 +38,7 b' from zmq.utils import jsonapi' | |||||
31 | from zmq.eventloop.ioloop import IOLoop |
|
38 | from zmq.eventloop.ioloop import IOLoop | |
32 | from zmq.eventloop.zmqstream import ZMQStream |
|
39 | from zmq.eventloop.zmqstream import ZMQStream | |
33 |
|
40 | |||
34 | from IPython.config.application import Application |
|
41 | from IPython.config.configurable import Configurable, LoggingConfigurable | |
35 | from IPython.config.configurable import Configurable |
|
|||
36 | from IPython.utils.importstring import import_item |
|
42 | from IPython.utils.importstring import import_item | |
37 | from IPython.utils.jsonutil import extract_dates, squash_dates, date_default |
|
43 | from IPython.utils.jsonutil import extract_dates, squash_dates, date_default | |
38 | from IPython.utils.traitlets import CStr, Unicode, Bool, Any, Instance, Set |
|
44 | from IPython.utils.traitlets import CStr, Unicode, Bool, Any, Instance, Set | |
@@ -75,15 +81,11 b' DELIM="<IDS|MSG>"' | |||||
75 | # Classes |
|
81 | # Classes | |
76 | #----------------------------------------------------------------------------- |
|
82 | #----------------------------------------------------------------------------- | |
77 |
|
83 | |||
78 | class SessionFactory(Configurable): |
|
84 | class SessionFactory(LoggingConfigurable): | |
79 | """The Base class for configurables that have a Session, Context, logger, |
|
85 | """The Base class for configurables that have a Session, Context, logger, | |
80 | and IOLoop. |
|
86 | and IOLoop. | |
81 | """ |
|
87 | """ | |
82 |
|
88 | |||
83 | log = Instance('logging.Logger') |
|
|||
84 | def _log_default(self): |
|
|||
85 | return Application.instance().log |
|
|||
86 |
|
||||
87 | logname = Unicode('') |
|
89 | logname = Unicode('') | |
88 | def _logname_changed(self, name, old, new): |
|
90 | def _logname_changed(self, name, old, new): | |
89 | self.log = logging.getLogger(new) |
|
91 | self.log = logging.getLogger(new) | |
@@ -161,8 +163,48 b' def extract_header(msg_or_header):' | |||||
161 | return h |
|
163 | return h | |
162 |
|
164 | |||
163 | class Session(Configurable): |
|
165 | class Session(Configurable): | |
164 | """tweaked version of IPython.zmq.session.Session, for development in Parallel""" |
|
166 | """Object for handling serialization and sending of messages. | |
|
167 | ||||
|
168 | The Session object handles building messages and sending them | |||
|
169 | with ZMQ sockets or ZMQStream objects. Objects can communicate with each | |||
|
170 | other over the network via Session objects, and only need to work with the | |||
|
171 | dict-based IPython message spec. The Session will handle | |||
|
172 | serialization/deserialization, security, and metadata. | |||
|
173 | ||||
|
174 | Sessions support configurable serialiization via packer/unpacker traits, | |||
|
175 | and signing with HMAC digests via the key/keyfile traits. | |||
|
176 | ||||
|
177 | Parameters | |||
|
178 | ---------- | |||
|
179 | ||||
|
180 | debug : bool | |||
|
181 | whether to trigger extra debugging statements | |||
|
182 | packer/unpacker : str : 'json', 'pickle' or import_string | |||
|
183 | importstrings for methods to serialize message parts. If just | |||
|
184 | 'json' or 'pickle', predefined JSON and pickle packers will be used. | |||
|
185 | Otherwise, the entire importstring must be used. | |||
|
186 | ||||
|
187 | The functions must accept at least valid JSON input, and output *bytes*. | |||
|
188 | ||||
|
189 | For example, to use msgpack: | |||
|
190 | packer = 'msgpack.packb', unpacker='msgpack.unpackb' | |||
|
191 | pack/unpack : callables | |||
|
192 | You can also set the pack/unpack callables for serialization directly. | |||
|
193 | session : bytes | |||
|
194 | the ID of this Session object. The default is to generate a new UUID. | |||
|
195 | username : unicode | |||
|
196 | username added to message headers. The default is to ask the OS. | |||
|
197 | key : bytes | |||
|
198 | The key used to initialize an HMAC signature. If unset, messages | |||
|
199 | will not be signed or checked. | |||
|
200 | keyfile : filepath | |||
|
201 | The file containing a key. If this is set, `key` will be initialized | |||
|
202 | to the contents of the file. | |||
|
203 | ||||
|
204 | """ | |||
|
205 | ||||
165 | debug=Bool(False, config=True, help="""Debug output in the Session""") |
|
206 | debug=Bool(False, config=True, help="""Debug output in the Session""") | |
|
207 | ||||
166 | packer = Unicode('json',config=True, |
|
208 | packer = Unicode('json',config=True, | |
167 | help="""The name of the packer for serializing messages. |
|
209 | help="""The name of the packer for serializing messages. | |
168 | Should be one of 'json', 'pickle', or an import name |
|
210 | Should be one of 'json', 'pickle', or an import name | |
@@ -194,6 +236,7 b' class Session(Configurable):' | |||||
194 | help="""The UUID identifying this session.""") |
|
236 | help="""The UUID identifying this session.""") | |
195 | def _session_default(self): |
|
237 | def _session_default(self): | |
196 | return bytes(uuid.uuid4()) |
|
238 | return bytes(uuid.uuid4()) | |
|
239 | ||||
197 | username = Unicode(os.environ.get('USER','username'), config=True, |
|
240 | username = Unicode(os.environ.get('USER','username'), config=True, | |
198 | help="""Username for the Session. Default is your system username.""") |
|
241 | help="""Username for the Session. Default is your system username.""") | |
199 |
|
242 | |||
@@ -206,7 +249,6 b' class Session(Configurable):' | |||||
206 | else: |
|
249 | else: | |
207 | self.auth = None |
|
250 | self.auth = None | |
208 | auth = Instance(hmac.HMAC) |
|
251 | auth = Instance(hmac.HMAC) | |
209 | counters = Instance('collections.defaultdict', (int,)) |
|
|||
210 | digest_history = Set() |
|
252 | digest_history = Set() | |
211 |
|
253 | |||
212 | keyfile = Unicode('', config=True, |
|
254 | keyfile = Unicode('', config=True, | |
@@ -227,6 +269,38 b' class Session(Configurable):' | |||||
227 | raise TypeError("unpacker must be callable, not %s"%type(new)) |
|
269 | raise TypeError("unpacker must be callable, not %s"%type(new)) | |
228 |
|
270 | |||
229 | def __init__(self, **kwargs): |
|
271 | def __init__(self, **kwargs): | |
|
272 | """create a Session object | |||
|
273 | ||||
|
274 | Parameters | |||
|
275 | ---------- | |||
|
276 | ||||
|
277 | debug : bool | |||
|
278 | whether to trigger extra debugging statements | |||
|
279 | packer/unpacker : str : 'json', 'pickle' or import_string | |||
|
280 | importstrings for methods to serialize message parts. If just | |||
|
281 | 'json' or 'pickle', predefined JSON and pickle packers will be used. | |||
|
282 | Otherwise, the entire importstring must be used. | |||
|
283 | ||||
|
284 | The functions must accept at least valid JSON input, and output | |||
|
285 | *bytes*. | |||
|
286 | ||||
|
287 | For example, to use msgpack: | |||
|
288 | packer = 'msgpack.packb', unpacker='msgpack.unpackb' | |||
|
289 | pack/unpack : callables | |||
|
290 | You can also set the pack/unpack callables for serialization | |||
|
291 | directly. | |||
|
292 | session : bytes | |||
|
293 | the ID of this Session object. The default is to generate a new | |||
|
294 | UUID. | |||
|
295 | username : unicode | |||
|
296 | username added to message headers. The default is to ask the OS. | |||
|
297 | key : bytes | |||
|
298 | The key used to initialize an HMAC signature. If unset, messages | |||
|
299 | will not be signed or checked. | |||
|
300 | keyfile : filepath | |||
|
301 | The file containing a key. If this is set, `key` will be | |||
|
302 | initialized to the contents of the file. | |||
|
303 | """ | |||
230 | super(Session, self).__init__(**kwargs) |
|
304 | super(Session, self).__init__(**kwargs) | |
231 | self._check_packers() |
|
305 | self._check_packers() | |
232 | self.none = self.pack({}) |
|
306 | self.none = self.pack({}) | |
@@ -290,6 +364,14 b' class Session(Configurable):' | |||||
290 | return h.hexdigest() |
|
364 | return h.hexdigest() | |
291 |
|
365 | |||
292 | def serialize(self, msg, ident=None): |
|
366 | def serialize(self, msg, ident=None): | |
|
367 | """Serialize the message components to bytes. | |||
|
368 | ||||
|
369 | Returns | |||
|
370 | ------- | |||
|
371 | ||||
|
372 | list of bytes objects | |||
|
373 | ||||
|
374 | """ | |||
293 | content = msg.get('content', {}) |
|
375 | content = msg.get('content', {}) | |
294 | if content is None: |
|
376 | if content is None: | |
295 | content = self.none |
|
377 | content = self.none | |
@@ -335,8 +417,8 b' class Session(Configurable):' | |||||
335 | stream : zmq.Socket or ZMQStream |
|
417 | stream : zmq.Socket or ZMQStream | |
336 | the socket-like object used to send the data |
|
418 | the socket-like object used to send the data | |
337 | msg_or_type : str or Message/dict |
|
419 | msg_or_type : str or Message/dict | |
338 |
Normally, msg_or_type will be a msg_type unless a message is being |
|
420 | Normally, msg_or_type will be a msg_type unless a message is being | |
339 | than once. |
|
421 | sent more than once. | |
340 |
|
422 | |||
341 | content : dict or None |
|
423 | content : dict or None | |
342 | the content of the message (ignored if msg_or_type is a message) |
|
424 | the content of the message (ignored if msg_or_type is a message) | |
@@ -436,9 +518,8 b' class Session(Configurable):' | |||||
436 | return None,None |
|
518 | return None,None | |
437 | else: |
|
519 | else: | |
438 | raise |
|
520 | raise | |
439 | # return an actual Message object |
|
521 | # split multipart message into identity list and message dict | |
440 | # determine the number of idents by trying to unpack them. |
|
522 | # invalid large messages can cause very expensive string comparisons | |
441 | # this is terrible: |
|
|||
442 | idents, msg = self.feed_identities(msg, copy) |
|
523 | idents, msg = self.feed_identities(msg, copy) | |
443 | try: |
|
524 | try: | |
444 | return idents, self.unpack_message(msg, content=content, copy=copy) |
|
525 | return idents, self.unpack_message(msg, content=content, copy=copy) | |
@@ -448,8 +529,9 b' class Session(Configurable):' | |||||
448 | raise e |
|
529 | raise e | |
449 |
|
530 | |||
450 | def feed_identities(self, msg, copy=True): |
|
531 | def feed_identities(self, msg, copy=True): | |
451 |
"""feed until DELIM is reached, then return the prefix as idents and |
|
532 | """feed until DELIM is reached, then return the prefix as idents and | |
452 |
msg. This is easily broken by setting an IDENT to DELIM, |
|
533 | remainder as msg. This is easily broken by setting an IDENT to DELIM, | |
|
534 | but that would be silly. | |||
453 |
|
535 | |||
454 | Parameters |
|
536 | Parameters | |
455 | ---------- |
|
537 | ---------- | |
@@ -536,3 +618,4 b' def test_msg2obj():' | |||||
536 | am2 = dict(ao) |
|
618 | am2 = dict(ao) | |
537 | assert am['x'] == am2['x'] |
|
619 | assert am['x'] == am2['x'] | |
538 | assert am['y']['z'] == am2['y']['z'] |
|
620 | assert am['y']['z'] == am2['y']['z'] | |
|
621 |
General Comments 0
You need to be logged in to leave comments.
Login now