1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import sys, StringIO, warnings, zlib
25
26 from threading import RLock, Semaphore
27
28 import ber
29
30 DICT_TAG = ber.Tag(ber.APPLICATION, 1, container=True)
31 PYOBJ_TAG = ber.Tag(ber.APPLICATION, 2, container=True)
32 PYOBJ_REF_TAG = ber.Tag(ber.APPLICATION, 3)
33 LAZY_DICT_TAG = ber.Tag(ber.APPLICATION, 4, container=True)
34 STRING_BUFF_TAG = ber.Tag(ber.APPLICATION, 5, container=True)
35 PYOBJZ_TAG = ber.Tag(ber.APPLICATION, 6)
36
37 SPOONLINKMSG_TAG = ber.Tag(ber.APPLICATION, 7, container=True)
38 SPOONNETMSG_TAG = ber.Tag(ber.APPLICATION, 8, container=True)
39
41 """
42 When used like a property in a Serial class, it will act as
43 a flag to the serializer that only properties that are of type C{serialprop} or C{lazyprop}
44 are to be serialized.
45
46 Any subclass of this will be treated the same way, so if you need your property to behave like
47 a customizable property, then subclass away.
48 """
50 self.initVal = value
51 self.valDict = {}
52 self.lock = RLock()
53
55 obj._spoon_meta.proplock.acquire()
56 try:
57 return obj._spoon_meta.propdict.setdefault(self, self.initVal)
58 finally:
59 obj._spoon_meta.proplock.release()
60
62 obj._spoon_meta.proplock.acquire()
63 try:
64 obj._spoon_meta.propdict[self] = value
65 finally:
66 obj._spoon_meta.proplock.release()
67
69 self.lock.acquire()
70 try:
71 del obj._spoon_meta.propdict[self]
72 finally:
73 self.lock.release()
74
75
77 """
78 When used like a property in a Serial class, it will act as
79 a flag to the serializer that only properties that are of type C{serialprop} or C{lazyprop}
80 are to be serialized.
81
82 Any subclass of this will be treated the same way, so if you need your property to behave like
83 a customizable property, then subclass away.
84
85 lazyprop indicates that on decoding, the object will have to explicitly decode all of the
86 properties marked with lazyprop. lazyprop and serialprop may be mixed together in a class,
87 and all serialprops will be decoded.
88 """
90 self.initVal = value
91 self.valDict = {}
93 lazydata = getattr(obj, "_spoon_lazydata", None)
94 if (lazydata is not None) and (lazydata.closed != True):
95 obj.decode_lazy()
96 obj._spoon_meta.proplock.acquire()
97 try:
98 return obj._spoon_meta.propdict.setdefault(self, self.initVal)
99 finally:
100 obj._spoon_meta.proplock.release()
101
103 obj._spoon_meta.proplock.acquire()
104 try:
105 obj._spoon_meta.propdict[self] = value
106 finally:
107 obj._spoon_meta.proplock.release()
108
110 obj._spoon_meta.proplock.acquire()
111 try:
112 del obj._spoon_meta.propdict[self]
113 finally:
114 obj._spoon_meta.proplock.release()
115
118 self.proplock = Semaphore()
119 self.decodelock = Semaphore()
120 self.propdict = {}
121
131
133 __metaclass__ = SerialMeta
134
135
136 - def __new__(cls, *args, **kwargs):
137 newobj = super(Serial, cls).__new__(cls, *args, **kwargs)
138 newobj._spoon_meta = SpoonData()
139 return newobj
140
142 """
143 Called after an object is received over the network, instead of the
144 normal C{__init__} method.
145 """
146 pass
147
149 """
150 Called right before this object's attributes are encoded into a stream
151 for network travel.
152 """
153 pass
154
156 """
157 Decode all of the attributes marked as lazy that have not yet been decoded.
158 @return: Number of attributes decoded.
159 @warning: Some sort of instance level locking should be done
160 """
161 if self._spoon_lazydata.closed:
162 return 0
163 self._spoon_meta.decodelock.acquire()
164 try:
165 b = ber.BERStream(self._spoon_lazydata)
166 attrs = b.next()
167 for k, v in attrs.iteritems():
168 setattr(self, k, v)
169
170 self._spoon_lazydata.close()
171 return len(attrs)
172 finally:
173 self._spoon_meta.decodelock.release()
174
176 """
177 Used as a substitute for the file object when serializing Serial objects,
178 so reference cycles are caught and handled.
179 """
180
182 self.fd = fd
183 self.memo = {}
184
187
189 return self.fd.read(n)
190
192 return getattr(self._fd, name)
193
194
196 """
197 Stupid wrapper around StringIO because it isn't a new style class. GRR!
198
199 I'm only implementing the methods that actually make sense for StringIOs and that we actually use.
200 """
202 if sio == None:
203 self.sio = StringIO.StringIO()
204 else:
205 self.sio = sio
206
209
211 return self.sio.next()
212
215
217 return self.sio.write(data)
218
219 - def read(self, cnt):
220 return self.sio.read(cnt)
221
223 return self.sio.close()
224
225 - def seek(self, pos):
226 return self.sio.seek(pos)
227
229 return self.sio.tell()
230
231
234
237
238 len = property(fget=get_len)
239 closed = property(fget=get_closed)
240
241
243 pass
244
245
246 @ber.encoder(StringIOWrap)
260
261 @ber.decoder(STRING_BUFF_TAG)
269
270
271 @ber.encoder(LazyDict)
281
282
283 @ber.decoder(LAZY_DICT_TAG)
298
299
300 @ber.encoder(dict)
307
308
309 @ber.decoder(DICT_TAG)
317
318 @ber.zencoder(Serial)
326
327 @ber.decoder(PYOBJZ_TAG)
332
333
334 @ber.encoder(Serial)
336
337
338 obj.pre_serialize()
339 attrlist = getattr(obj, '_spoon_attrs', None)
340 lazyattrlist = getattr(obj, '_spoon_lazyattrs', None)
341
342 if attrlist is None and lazyattrlist is None:
343
344
345
346 attrlist = [a for a in dir(obj) if ((a[0] != '_') and ('__call__' not in dir(getattr(obj, a, None))))]
347
348 objectlazydata = getattr(obj, "_spoon_lazydata", None)
349
350 attrdict = {}
351 if attrlist is not None:
352 for a in attrlist:
353 if not ber.BERStream.can_encode(getattr(obj, a, None)):
354 warnings.warn("Can't encode attribute %s of %s(type: %s"%(a,
355 type(obj).__name__, repr(type(getattr(obj,a,None)))), RuntimeWarning)
356 continue
357 attrdict[a] = getattr(obj, a, None)
358
359
360 if (objectlazydata is not None) and (not objectlazydata.closed):
361 attrdict["_spoon_lazydata"] = objectlazydata
362
363 lazydict = LazyDict()
364 if (lazyattrlist is not None) and (objectlazydata is None):
365 for a in lazyattrlist:
366 lazydict[a] = getattr(obj, a, None)
367
368
369
370 if getattr(fd, 'memo', None) is None:
371 fd = Memoizer(fd)
372
373 ref = str(id(obj))
374 if ref in fd.memo:
375
376 ber.Tag.from_tag(PYOBJ_REF_TAG, len(ref)).write(fd)
377 fd.write(ref)
378 return
379
380 fd.memo[ref] = obj
381
382 if not omittag:
383 ber.Tag.from_tag(PYOBJ_TAG, None).write(fd)
384 b = ber.BERStream(fd)
385 b.add(ref)
386 b.add(type(obj).__name__)
387 b.add(type(obj).__module__)
388 b.add(attrdict)
389 b.add(lazydict)
390 b._add_eof()
391
392
393 @ber.decoder(PYOBJ_TAG)
395 if getattr(fd, 'memo', None) is None:
396 fd = Memoizer(fd)
397
398 b = ber.BERStream(fd, tag.size)
399 ref = b.next()
400 typename = b.next()
401 modulename = b.next()
402
403
404
405
406
407
408
409
410
411
412
413
414 module = sys.modules.get(modulename, None)
415 if module is None:
416 raise ber.BERException('Unable to find module %r' % (modulename,))
417 cls = getattr(module, typename, None)
418 if cls is None:
419 raise ber.BERException('Unable to find class %r in module %r' % (typename, modulename))
420
421 obj = cls.__new__(cls)
422 fd.memo[ref] = obj
423
424
425
426 setlazydata = False
427 attrs = b.next()
428 for k, v in attrs.iteritems():
429 setattr(obj, k, v)
430 if k == "_spoon_lazydata":
431 setlazydata = True
432
433 lazydata = b.next()
434 if setlazydata is False:
435 setattr(obj, "_spoon_lazydata", lazydata)
436 if b.has_next():
437 pass
438 obj.post_deserialize()
439 return obj
440
441
442 @ber.decoder(PYOBJ_REF_TAG)
444 print 'decode-ref'
445 if getattr(fd, 'memo', None) is None:
446 raise ber.BERException('Python object reference outside of object cycle == impossible?')
447 ref = fd.read(tag.size)
448 obj = fd.memo.get(ref, None)
449 if obj is None:
450 raise ber.BERException('Python object reference to nonexistent entity')
451 return obj
452