Show More
@@ -1,5 +1,12 b'' | |||
|
1 | 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 | 12 | # Copyright (C) 2010-2011 The IPython Development Team |
@@ -31,8 +38,7 b' from zmq.utils import jsonapi' | |||
|
31 | 38 | from zmq.eventloop.ioloop import IOLoop |
|
32 | 39 | from zmq.eventloop.zmqstream import ZMQStream |
|
33 | 40 | |
|
34 | from IPython.config.application import Application | |
|
35 | from IPython.config.configurable import Configurable | |
|
41 | from IPython.config.configurable import Configurable, LoggingConfigurable | |
|
36 | 42 | from IPython.utils.importstring import import_item |
|
37 | 43 | from IPython.utils.jsonutil import extract_dates, squash_dates, date_default |
|
38 | 44 | from IPython.utils.traitlets import CStr, Unicode, Bool, Any, Instance, Set |
@@ -75,15 +81,11 b' DELIM="<IDS|MSG>"' | |||
|
75 | 81 | # Classes |
|
76 | 82 | #----------------------------------------------------------------------------- |
|
77 | 83 | |
|
78 | class SessionFactory(Configurable): | |
|
84 | class SessionFactory(LoggingConfigurable): | |
|
79 | 85 | """The Base class for configurables that have a Session, Context, logger, |
|
80 | 86 | and IOLoop. |
|
81 | 87 | """ |
|
82 | 88 | |
|
83 | log = Instance('logging.Logger') | |
|
84 | def _log_default(self): | |
|
85 | return Application.instance().log | |
|
86 | ||
|
87 | 89 | logname = Unicode('') |
|
88 | 90 | def _logname_changed(self, name, old, new): |
|
89 | 91 | self.log = logging.getLogger(new) |
@@ -161,8 +163,48 b' def extract_header(msg_or_header):' | |||
|
161 | 163 | return h |
|
162 | 164 | |
|
163 | 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 | 206 | debug=Bool(False, config=True, help="""Debug output in the Session""") |
|
207 | ||
|
166 | 208 | packer = Unicode('json',config=True, |
|
167 | 209 | help="""The name of the packer for serializing messages. |
|
168 | 210 | Should be one of 'json', 'pickle', or an import name |
@@ -194,6 +236,7 b' class Session(Configurable):' | |||
|
194 | 236 | help="""The UUID identifying this session.""") |
|
195 | 237 | def _session_default(self): |
|
196 | 238 | return bytes(uuid.uuid4()) |
|
239 | ||
|
197 | 240 | username = Unicode(os.environ.get('USER','username'), config=True, |
|
198 | 241 | help="""Username for the Session. Default is your system username.""") |
|
199 | 242 | |
@@ -206,7 +249,6 b' class Session(Configurable):' | |||
|
206 | 249 | else: |
|
207 | 250 | self.auth = None |
|
208 | 251 | auth = Instance(hmac.HMAC) |
|
209 | counters = Instance('collections.defaultdict', (int,)) | |
|
210 | 252 | digest_history = Set() |
|
211 | 253 | |
|
212 | 254 | keyfile = Unicode('', config=True, |
@@ -227,6 +269,38 b' class Session(Configurable):' | |||
|
227 | 269 | raise TypeError("unpacker must be callable, not %s"%type(new)) |
|
228 | 270 | |
|
229 | 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 | 304 | super(Session, self).__init__(**kwargs) |
|
231 | 305 | self._check_packers() |
|
232 | 306 | self.none = self.pack({}) |
@@ -290,6 +364,14 b' class Session(Configurable):' | |||
|
290 | 364 | return h.hexdigest() |
|
291 | 365 | |
|
292 | 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 | 375 | content = msg.get('content', {}) |
|
294 | 376 | if content is None: |
|
295 | 377 | content = self.none |
@@ -335,8 +417,8 b' class Session(Configurable):' | |||
|
335 | 417 | stream : zmq.Socket or ZMQStream |
|
336 | 418 | the socket-like object used to send the data |
|
337 | 419 | msg_or_type : str or Message/dict |
|
338 |
Normally, msg_or_type will be a msg_type unless a message is being |
|
|
339 | than once. | |
|
420 | Normally, msg_or_type will be a msg_type unless a message is being | |
|
421 | sent more than once. | |
|
340 | 422 | |
|
341 | 423 | content : dict or None |
|
342 | 424 | the content of the message (ignored if msg_or_type is a message) |
@@ -436,9 +518,8 b' class Session(Configurable):' | |||
|
436 | 518 | return None,None |
|
437 | 519 | else: |
|
438 | 520 | raise |
|
439 | # return an actual Message object | |
|
440 | # determine the number of idents by trying to unpack them. | |
|
441 | # this is terrible: | |
|
521 | # split multipart message into identity list and message dict | |
|
522 | # invalid large messages can cause very expensive string comparisons | |
|
442 | 523 | idents, msg = self.feed_identities(msg, copy) |
|
443 | 524 | try: |
|
444 | 525 | return idents, self.unpack_message(msg, content=content, copy=copy) |
@@ -448,8 +529,9 b' class Session(Configurable):' | |||
|
448 | 529 | raise e |
|
449 | 530 | |
|
450 | 531 | def feed_identities(self, msg, copy=True): |
|
451 |
"""feed until DELIM is reached, then return the prefix as idents and |
|
|
452 |
msg. This is easily broken by setting an IDENT to DELIM, |
|
|
532 | """feed until DELIM is reached, then return the prefix as idents and | |
|
533 | remainder as msg. This is easily broken by setting an IDENT to DELIM, | |
|
534 | but that would be silly. | |
|
453 | 535 | |
|
454 | 536 | Parameters |
|
455 | 537 | ---------- |
@@ -536,3 +618,4 b' def test_msg2obj():' | |||
|
536 | 618 | am2 = dict(ao) |
|
537 | 619 | assert am['x'] == am2['x'] |
|
538 | 620 | assert am['y']['z'] == am2['y']['z'] |
|
621 |
General Comments 0
You need to be logged in to leave comments.
Login now