[prev in list] [next in list] [prev in thread] [next in thread]
List: pyamf-commits
Subject: [pyamf-commits] r75 - in branches/amf3-5/pyamf: . tests
From: pyamf-commits () collab ! com (pyamf-commits () collab ! com)
Date: 2007-10-26 11:59:16
Message-ID: 20071026095907.E101D7BC069 () mail ! collab ! com
[Download RAW message or body]
Author: nick
Date: 2007-10-26 11:59:07 +0200 (Fri, 26 Oct 2007)
New Revision: 75
Modified:
branches/amf3-5/pyamf/__init__.py
branches/amf3-5/pyamf/amf0.py
branches/amf3-5/pyamf/amf3.py
branches/amf3-5/pyamf/tests/amf3.py
branches/amf3-5/pyamf/util.py
Log:
Added a context arg to Parsers/Encoders Added ByteArray support & testsStarted the \
beginnings of class mapping
Modified: branches/amf3-5/pyamf/__init__.py
===================================================================
--- branches/amf3-5/pyamf/__init__.py 2007-10-25 11:53:11 UTC (rev 74)
+++ branches/amf3-5/pyamf/__init__.py 2007-10-26 09:59:07 UTC (rev 75)
@@ -84,6 +84,87 @@
"""
pass
+class Context(object):
+ """
+ """
+ objects = []
+ strings = []
+ classes = []
+ class_cache = {}
+ class_defs = {}
+
+ def clear(self):
+ self.objects = []
+ self.strings = []
+ self.classes = []
+ self.class_cache = {}
+ self.class_defs = {}
+
+ def getObject(self, ref):
+ """
+ Gets an object based on a reference ref
+
+ Raises L{pyamf.ReferenceError} if the object could not be found
+ """
+ try:
+ return self.objects[ref]
+ except IndexError:
+ raise ReferenceError("Object reference %d not found" % ref)
+
+ def getObjectReference(self, obj):
+ try:
+ return self.objects.index(obj)
+ except ValueError:
+ raise ReferenceError("Reference for object %r not found" % obj)
+
+ def addObject(self, obj):
+ """
+ Gets a reference to obj, creating one if necessary
+ """
+ try:
+ return self.objects.index(obj)
+ except ValueError:
+ self.objects.append(obj)
+
+ return len(self.objects)
+
+ def getString(self, ref):
+ """
+ Gets a string based on a reference ref
+
+ Raises L{pyamf.ReferenceError} if the string could not be found
+ """
+ try:
+ return self.strings[ref]
+ except IndexError:
+ raise ReferenceError("String reference %d not found" % ref)
+
+ def getStringReference(self, s):
+ try:
+ return self.strings.index(s)
+ except ValueError:
+ raise ReferenceError("Reference for string %r not found" % s)
+
+ def addString(self, s):
+ """
+ Creates a reference to s
+ """
+ try:
+ return self.strings.index(s)
+ except ValueError:
+ self.strings.append(s)
+
+ return len(self.strings)
+
+ def getClass(self, name):
+ """
+ Gets a class based on the name supplied
+ """
+ try:
+ return self.class_cache[name]
+ except KeyError:
+ pass
+
class AMFMessageDecoder:
def __init__(self, data):
Modified: branches/amf3-5/pyamf/amf0.py
===================================================================
--- branches/amf3-5/pyamf/amf0.py 2007-10-25 11:53:11 UTC (rev 74)
+++ branches/amf3-5/pyamf/amf0.py 2007-10-26 09:59:07 UTC (rev 75)
@@ -71,7 +71,6 @@
"""
Parses an AMF0 stream
"""
- obj_refs = []
# XXX nick: Do we need to support ASTypes.MOVIECLIP here?
type_map = {
ASTypes.NUMBER: 'readNumber',
@@ -93,13 +92,18 @@
ASTypes.AMF3: 'readAMF3'
}
- def __init__(self, data=None):
+ def __init__(self, data=None, context=None):
# coersce data to BufferedByteStream
if isinstance(data, util.BufferedByteStream):
self.input = data
else:
self.input = util.BufferedByteStream(data)
+ if context == None:
+ self.context = pyamf.Context()
+ else:
+ self.context = context
+
def readType(self):
"""
Read and returns the next byte in the stream and determine its type.
@@ -147,11 +151,9 @@
def readList(self):
len = self.input.read_ulong()
- obj = []
- self.obj_refs.append(obj)
+ obj = [self.readElement() for i in xrange(len)]
- obj.extend(self.readElement() for i in xrange(len))
-
+ self.context.addObject(obj)
return obj
def readTypedObject(self):
@@ -165,12 +167,14 @@
from pyamf import amf3
# XXX: Does the amf3 parser have access to the same references as amf0?
- p = amf3.Parser(self.input)
+ p = amf3.Parser(self.input, self.context)
return p.readElement()
def readElement(self):
- """Reads the data type."""
+ """
+ Reads an element from the data stream
+ """
type = self.readType()
try:
@@ -182,9 +186,12 @@
return func()
def readString(self):
+ """
+ Reads a string from the data stream
+ """
len = self.input.read_ushort()
return self.input.read_utf8_string(len)
-
+
def _readObject(self, obj):
key = self.readString()
while self.input.peek() != chr(ASTypes.OBJECTTERM):
@@ -202,17 +209,20 @@
@rettype __builtin__.object
"""
obj = {}
- self.obj_refs.append(obj)
self._readObject(obj)
+ self.context.addObject(obj)
+
return obj
def readReference(self):
idx = self.input.read_ushort()
- return self.obj_refs[idx]
+ return self.context.getObject(idx)
def readDate(self):
- """Reads a date.
+ """
+ Reads a date from the data stream
+
Date: 0x0B T7 T6 .. T0 Z1 Z2 T7 to T0 form a 64 bit Big Endian number
that specifies the number of nanoseconds that have passed since
1/1/1970 0:00 to the specified time. This format is UTC 1970. Z1 an
@@ -247,12 +257,16 @@
((types.InstanceType,types.ObjectType,), "writeObject"),
]
- def __init__(self, output):
+ def __init__(self, output, context=None):
"""Constructs a new Encoder. output should be a writable
file-like object."""
self.output = output
- self.obj_refs = []
+ if context == None:
+ self.context = pyamf.Context()
+ else:
+ self.context = context
+
def writeType(self, type):
"""
Writes the type to the stream. Raises ValueError if type is not
@@ -311,7 +325,7 @@
self.output.write(s)
def writeReference(self, o):
- idx = self.obj_refs.index(o)
+ idx = self.context.getObjectReference(o)
self.writeType(ASTypes.REFERENCE)
self.output.write_ushort(idx)
@@ -349,10 +363,10 @@
try:
self.writeReference(o)
return
- except ValueError, e:
+ except pyamf.ReferenceError:
pass
- self.obj_refs.append(o)
+ self.context.addObject(o)
self.writeType(ASTypes.OBJECT)
# TODO: give objects a chance of controlling what we send
Modified: branches/amf3-5/pyamf/amf3.py
===================================================================
--- branches/amf3-5/pyamf/amf3.py 2007-10-25 11:53:11 UTC (rev 74)
+++ branches/amf3-5/pyamf/amf3.py 2007-10-26 09:59:07 UTC (rev 75)
@@ -27,7 +27,7 @@
#
# Resources:
# http://www.vanrijkom.org/archives/2005/06/amf_format.html
-# http://osflash.org/documentation/amf/astypes
+# http://osflash.org/documentation/amf3
"""AMF3 Implementation"""
@@ -60,7 +60,7 @@
REFERENCE_BIT = 0x01
-class AMF3ObjectTypes:
+class ObjectEncoding:
# Property list encoding.
# The remaining integer-data represents the number of
# class members that exist. The property names are read
@@ -85,32 +85,55 @@
# Proxy object
PROXY = 0x03
- # Flex class mappings.
- flex_mappings = [
- # (RemotingMessage, "flex.messaging.messages.RemotingMessage"),
- # (CommandMessage, "flex.messaging.messages.CommandMessage"),
- # (AcknowledgeMessage, "flex.messaging.messages.AcknowledgeMessage"),
- # (ErrorMessage, "flex.messaging.messages.ErrorMessage"),
- # (ArrayCollection, "flex.messaging.io.ArrayCollection"),
- # (ObjectProxy, "flex.messaging.io.ObjectProxy"),
- ]
+class Bag(dict):
+ """
+ I supply a thin layer over the __builtin__.dict type to support
+ get/setattr calls
+ """
-class Bag(dict):
def __init__(self, d={}):
for k, v in d.items():
self[k] = v
- __setattr__ = dict.__setitem__
+ def __setattr__(self, name, value):
+ self[name] = value
+ def __getattr__(self, name):
+ return self[name]
+
+class ByteArray(str):
+ """
+ I am a file type object containing byte data from the AMF stream
+ """
+
+class ClassDefinition(object):
+ """
+ I contain meta relating to the class definition
+ """
+ attrs = []
+
+ def __init__(self, name, encoding):
+ self.name = name
+ self.encoding = encoding
+
+ def is_external(self):
+ return self.encoding == ObjectEncoding.EXTERNALIZABLE
+
+ def is_static(self):
+ return self.encoding == ObjectEncoding.STATIC
+
+ def is_dynamic(self):
+ return self.encoding == ObjectEncoding.DYNAMIC
+
+ external = property(is_external)
+ static = property(is_static)
+ dynamic = property(is_dynamic)
+
class Parser(object):
"""
Parses an AMF3 data stream
"""
- obj_refs = []
- str_refs = []
- class_refs = []
-
type_map = {
ASTypes.UNDEFINED: 'readNull',
ASTypes.NULL: 'readNull',
@@ -127,12 +150,17 @@
ASTypes.BYTEARRAY: 'readByteArray',
}
- def __init__(self, data=None):
+ def __init__(self, data=None, context=None):
if isinstance(data, util.BufferedByteStream):
self.input = data
else:
self.input = util.BufferedByteStream(data)
+ if context == None:
+ context = pyamf.Context()
+
+ self.context = context
+
def readType(self):
"""
Read and returns the next byte in the stream and determine its type.
@@ -210,23 +238,21 @@
length, is_reference = readLength()
if use_references and is_reference:
- try:
- return self.str_refs[length]
- except IndexError:
- raise pyamf.ReferenceError("Unknown string reference %d" % length)
+ return self.context.getString(length)
buf = self.input.read(length)
try:
# Try decoding as regular utf8 first since that will
# cover most cases and is more efficient.
- # XXX: I'm not sure if it's ok though.. will it always raise exception?
+ # XXX: I'm not sure if it's ok though..
+ # will it always raise exception?
result = unicode(buf, "utf8")
except UnicodeDecodeError:
result = decode_utf8_modified(buf)
if len(result) != 0 and use_references:
- self.str_refs.append(result)
+ self.context.addString(result)
return result
@@ -237,15 +263,13 @@
ref = self.readInteger()
if ref & REFERENCE_BIT == 0:
- try:
- return self.obj_refs[ref >> 1]
- except IndexError:
- raise pyamf.ReferenceError("Unknown date reference %d" % ref)
+ return self.context.getObject(ref >> 1)
ms = self.input.read_double()
result = datetime.datetime.fromtimestamp(ms / 100)
- self.obj_refs.append(result)
+ self.context.addObject(result)
+
return result
def readArray(self):
@@ -264,7 +288,7 @@
size = self.readInteger()
if size & REFERENCE_BIT == 0:
- return self.obj_refs[size >> 1]
+ return self.context.getObject(size >> 1)
size >>= 1
@@ -292,7 +316,7 @@
el = self.readElement()
result[i] = el
- self.obj_refs.append(result)
+ self.context.addObject(result)
return result
@@ -303,67 +327,66 @@
type = self.readInteger()
if type & REFERENCE_BIT == 0:
- return self.obj_refs[type >> 1]
+ return self.context.getObject(type >> 1)
- class_ref = (type >> 1) & REFERENCE_BIT == 0
-
+ class_ref = type >> 1 & REFERENCE_BIT == 0
type >>= 2
if class_ref:
- klass = self.class_refs[type]
+ class_def = self.class_refs[type]
else:
- klass = AMF3Class()
- klass.name = self.readString()
- klass.encoding = type & AMF3ObjectTypes.PROXY
- klass.attrs = []
+ class_def = ClassDefinition(self.readString(), type & 0x03)
+ self.class_refs.append(class_def)
- type >>= 1
+ type >>= 2
- if klass.name:
- # TODO : do some class mapping?
- obj = AMF3Object(klass)
- else:
- obj = Bag()
+ klass = lookup_class(class_def, self)
+ obj = klass()
- if not class_ref:
- self.class_refs.append(klass)
-
- if klass.encoding & AMF3ObjectTypes.EXTERNALIZABLE:
+ if class_def.external:
# TODO: implement externalizeable interface here
obj.__amf_externalized_data = self.readElement()
- elif klass.encoding & AMF3ObjectTypes.DYNAMIC:
- for i in range(type):
- k = self.readString()
- v = self.readElement()
- print k, v
- setattr(obj, k, v)
+ elif class_def.dynamic:
+ attr = self.readString()
- elif klass.encoding & AMF3ObjectTypes.STATIC:
+ while attr != "":
+ if attr not in class_def.attrs:
+ class_def.attrs.append(attr)
+
+ obj[attr] = self.readElement()
+ attr = self.readString()
+
+ elif class_def.static:
if not class_ref:
- klass.attrs = [self.readString() for i in range(type)]
+ class_def.attrs = [self.readString() for i in range(type)]
- for attr in klass.attrs:
- setattr(obj, attr, self.readElement())
+ for attr in class_def.attrs:
+ obj[attr] = self.readElement()
+ else:
+ raise pyamf.ParseError("Unknown object encoding")
- self.obj_refs.append(obj)
+ self.context.addObject(obj)
return obj
def readByteArray(self):
+ """
+ Reads a string of data from the stream.
+ """
length = self.readInteger()
- return self.input.read(length >> 1)
+ return ByteArray(self.input.read(length >> 1))
+
class Encoder(object):
- obj_refs = []
- str_refs = []
type_map = [
# Unsupported types go first
((types.BuiltinFunctionType, types.BuiltinMethodType,), "writeUnsupported"),
((bool,), "writeBoolean"),
((int,long), "writeInteger"),
((float,), "writeNumber"),
+ ((ByteArray,), "writeByteArray"),
((types.StringTypes,), "writeString"),
((util.ET._ElementInterface,), "writeXML"),
((types.DictType,), "writeDict"),
@@ -373,11 +396,16 @@
((types.InstanceType,types.ObjectType,), "writeObject"),
]
- def __init__(self, output):
+ def __init__(self, output, context=None):
"""Constructs a new Encoder. output should be a writable
file-like object."""
self.output = output
+ if context == None:
+ context = pyamf.Context()
+
+ self.context = context
+
def writeType(self, type):
"""
Writes the type to the stream. Raises ValueError if type is not
@@ -411,14 +439,13 @@
else:
self.writeType(ASTypes.BOOL_FALSE)
- def writeArray(self, a):
- self.writeType(ASTypes.ARRAY)
- self.output.write_ulong(len(a))
-
- for data in a:
- self.writeElement(data)
-
def _writeInteger(self, n):
+ """
+ AMF Integers are encoded.
+
+ See http://osflash.org/documentation/amf3/parsing_integers for more
+ info.
+ """
bytes = []
if n & 0xff000000 == 0:
@@ -437,10 +464,16 @@
self.output.write_uchar(bytes[-1])
def writeInteger(self, n):
+ """
+ Writes an integer to the data stream
+ """
self.writeType(ASTypes.INTEGER)
self._writeInteger(n)
def writeNumber(self, n):
+ """
+ Writes a non integer to the data stream
+ """
self.writeType(ASTypes.NUMBER)
self.output.write_double(n)
@@ -448,27 +481,21 @@
"""
Writes a raw string to the stream.
"""
- s = encode_utf8_modified(n)[2:]
- strlen = len(s)
-
- if strlen == 0:
+ if len(n) == 0:
self._writeInteger(REFERENCE_BIT)
return
try:
- ref = self.str_refs.index(n)
- use_ref = 1
- except ValueError:
- # add string reference
- self.str_refs.append(n)
- use_ref = 0
+ ref = self.context.getStringReference(n)
+ self._writeInteger(ref << 1)
- if use_ref == 1:
- self._writeInteger(ref << 1)
return
+ except pyamf.ReferenceError:
+ self.context.addString(n)
- self._writeInteger((strlen << 1) | REFERENCE_BIT)
+ s = encode_utf8_modified(n)[2:]
+ self._writeInteger((len(s) << 1) | REFERENCE_BIT)
for ch in s:
self.output.write_uchar(ord(ch))
@@ -490,21 +517,19 @@
self.writeType(ASTypes.DATE)
try:
- ref = self.obj_refs.index(n)
- use_ref = 1
- except ValueError:
- # add an object reference
- self.obj_refs.append(n)
- use_ref = 0
-
- if use_ref == 1:
+ ref = self.context.getObjectReference(n)
self._writeInteger(ref << 1)
- else:
- self._writeInteger(REFERENCE_BIT)
- ms = time.mktime(n.timetuple())
- self.output.write_double(ms * 100.0)
+ return
+ except pyamf.ReferenceError:
+ pass
+ self.context.addObject(n)
+ self._writeInteger(REFERENCE_BIT)
+
+ ms = time.mktime(n.timetuple())
+ self.output.write_double(ms * 100.0)
+
def writeList(self, n):
"""
Writes a list to the stream.
@@ -512,22 +537,20 @@
self.writeType(ASTypes.ARRAY)
try:
- ref = self.obj_refs.index(n)
- use_ref = 1
- except ValueError:
- # add an object reference
- self.obj_refs.append(n)
- use_ref = 0
-
- if use_ref == 1:
+ ref = self.context.getObjectReference(n)
self._writeInteger(ref << 1)
- else:
- self._writeInteger(len(n) << 1 | REFERENCE_BIT)
- self.output.write_uchar(0x01)
- for x in n:
- self.writeElement(x)
+ return
+ except pyamf.ReferenceError:
+ pass
+ self.context.addObject(n)
+ self._writeInteger(len(n) << 1 | REFERENCE_BIT)
+
+ self.output.write_uchar(0x01)
+ for x in n:
+ self.writeElement(x)
+
def writeDict(self, n):
"""
Writes a dict to the stream.
@@ -535,18 +558,15 @@
self.writeType(ASTypes.ARRAY)
try:
- ref = self.obj_refs.index(n)
- use_ref = 1
- except ValueError:
- # add an object reference
- self.obj_refs.append(n)
- use_ref = 0
-
- if use_ref == 1:
+ ref = self.context.getObjectReference(n)
self._writeInteger(ref << 1)
return
+ except pyamf.ReferenceError:
+ pass
+ self.context.addObject(n)
+
# The AMF3 spec demands that all str based indicies be listed first
keys = n.keys()
int_keys = []
@@ -580,11 +600,12 @@
self._writeInteger(len(int_keys) << 1 | REFERENCE_BIT)
for x in str_keys:
- # Design bug in Flash 9 that cannot read empty key strings
- # see http://www.docuverse.com/blog/donpark/2007/05/14/flash-9-amf3-bug
+ # Design bug in AMF3 that cannot read/write empty key strings
+ # http://www.docuverse.com/blog/donpark/2007/05/14/flash-9-amf3-bug
# for more info
if x == '':
- raise pyamf.EncodeError("dicts cannot contain empty string keys")
+ raise pyamf.EncodeError(
+ "dicts cannot contain empty string keys")
self._writeString(x)
self.writeElement(n[x])
@@ -594,25 +615,42 @@
for k in int_keys:
self.writeElement(n[k])
-class AMF3Class:
+ def writeObject(self, n):
+ """
+ Writes an object to the stream.
+ """
+ try:
+ ref = self.context.getObjectReference(n)
+ self._writeInteger(ref << 1)
- def __init__(self, name=None, encoding=None, attrs=None):
- self.name = name
- self.encoding = encoding
- self.attrs = attrs
+ return
+ except pyamf.ReferenceError:
+ pass
-class AMF3Object:
+ self.context.addObject(n)
- def __init__(self, class_=None):
- self.__amf_class = class_
+ def writeByteArray(self, n):
+ """
+ Writes a L{ByteArray} to the data stream.
+ """
+ self.writeType(ASTypes.BYTEARRAY)
+
+ try:
+ ref = self.context.getObjectReference(n)
+ self._writeInteger(ref << 1)
- def __repr__(self):
- return "<AMF3Object [%s] at 0x%08X>" % (
- self.__amf_class and self.__amf_class.name or "no class",
- id(self))
+ return
+ except pyamf.ReferenceError:
+ pass
-class AbstractMessage:
+ self.context.addObject(n)
+ self._writeInteger(len(n) << 1 | REFERENCE_BIT)
+ for ch in n:
+ self.output.write_uchar(ord(ch))
+
+class AbstractMessage(object):
+
def __init__(self):
# The body of the message.
self.data = None
@@ -759,3 +797,18 @@
utf16 = "".join([chr((c >> 8) & 0xff) + chr(c & 0xff) for c in utf16])
return unicode(utf16, "utf_16_be")
+
+def lookup_class(cl, context):
+ """
+ Looks up a class in the context, based on the supplied ClassDefinition
+
+ @return a callable.
+ """
+ if cl.klass:
+ return cl.klass
+
+
+
+ print cl
+
+ return Bag
Modified: branches/amf3-5/pyamf/tests/amf3.py
===================================================================
--- branches/amf3-5/pyamf/tests/amf3.py 2007-10-25 11:53:11 UTC (rev 74)
+++ branches/amf3-5/pyamf/tests/amf3.py 2007-10-26 09:59:07 UTC (rev 75)
@@ -54,8 +54,7 @@
self.e = amf3.Encoder(self.buf)
def _run(self, data):
- self.e.str_refs = []
- self.e.obj_refs = []
+ self.e.context.clear()
e = EncoderTester(self.e, data)
e.run(self)
@@ -155,6 +154,17 @@
self.failUnlessRaises(pyamf.EncodeError, x)
+ def test_object(self):
+ class Object(object):
+ def __init__(self, di={}):
+ for n, v in di.items():
+ setattr(self, n, v)
+
+ self._run([(Object({'baz': u'hello', 'foo': u'bar'}), '')])
+
+ def test_byte_array(self):
+ self._run([(amf3.ByteArray('hello'), '\x0c\x0bhello')])
+
class ParserTestCase(unittest.TestCase):
def setUp(self):
self.buf = util.BufferedByteStream()
@@ -162,8 +172,7 @@
self.parser.input = self.buf
def _run(self, data):
- self.parser.str_refs = []
- self.parser.obj_refs = []
+ self.parser.context.clear()
e = ParserTester(self.parser, data)
e.run(self)
@@ -263,8 +272,6 @@
'\x09\x09\x03\x62\x06\x00\x03\x64\x06\x02\x03\x61\x06\x04\x03\x63'
'\x06\x06\x01\x04\x00\x04\x01\x04\x02\x04\x03')
])
- self._run([({'': 1, 0: 1}, '\x09\x03\x01\x04\x01\x01\x04\x01')])
- self._run([({'': 1, 0: 2}, '\x09\x03\x01\x04\x01\x01\x04\x02')])
def test_empty_dict(self):
"""
@@ -287,8 +294,22 @@
def test_object(self):
self._run([
- ({'': 1, 0: 2}, '\x0a\x0b\x01\x01\x04\x01\x03\x30\x04\x02\x01')])
+ ({'a': 1, 'b': 2}, '\x0a\x0b\x01\x03\x62\x04\x02\x03\x61\x04\x01'
+ '\x01')])
+ self._run([
+ ({'baz': u'hello'}, '\x0a\x0b\x01\x07\x62\x61\x7a\x06\x0b\x68\x65'
+ '\x6c\x6c\x6f\x01')])
+ self._run([
+ ({'baz': u'hello'}, '\x0a\x13\x01\x07\x62\x61\x7a\x06\x0b\x68\x65'
+ '\x6c\x6c\x6f')])
+ self._run([
+ ({'baz': u'hello'}, '\x0a\x13\x31\x63\x6f\x6d\x2e\x63\x6f\x6c\x6c'
+ '\x61\x62\x2e\x64\x65\x76\x2e\x70\x79\x61\x6d\x66\x2e\x66\x6f'
+ '\x6f\x07\x62\x61\x7a\x06\x0b\x68\x65\x6c\x6c\x6f')])
+ def test_byte_array(self):
+ self._run([(amf3.ByteArray('hello'), '\x0c\x0bhello')])
+
class ModifiedUTF8TestCase(unittest.TestCase):
data = [
('hello', '\x00\x05\x68\x65\x6c\x6c\x6f'),
Modified: branches/amf3-5/pyamf/util.py
===================================================================
--- branches/amf3-5/pyamf/util.py 2007-10-25 11:53:11 UTC (rev 74)
+++ branches/amf3-5/pyamf/util.py 2007-10-26 09:59:07 UTC (rev 75)
@@ -36,7 +36,7 @@
except ImportError:
import elementtree.ElementTree as ET
-class NetworkIOMixIn:
+class NetworkIOMixIn(object):
"""Provides mix-in methods for file like objects to read and write basic
datatypes in network (= big-endian) byte-order."""
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic