diff options
-rw-r--r-- | qpid/python/qpid/codec010.py | 11 | ||||
-rw-r--r-- | qpid/python/qpid/datatypes.py | 50 | ||||
-rw-r--r-- | qpid/python/qpid/spec010.py | 6 | ||||
-rw-r--r-- | qpid/python/tests/codec010.py | 36 | ||||
-rw-r--r-- | qpid/python/tests/datatypes.py | 32 |
5 files changed, 120 insertions, 15 deletions
diff --git a/qpid/python/qpid/codec010.py b/qpid/python/qpid/codec010.py index c2ea7ed512..f34025ef17 100644 --- a/qpid/python/qpid/codec010.py +++ b/qpid/python/qpid/codec010.py @@ -17,8 +17,9 @@ # under the License. # +import datetime from packer import Packer -from datatypes import serial, RangedSet, Struct +from datatypes import serial, timestamp, RangedSet, Struct class CodecException(Exception): pass @@ -103,9 +104,11 @@ class Codec(Packer): self.pack("!q", n) def read_datetime(self): - return self.read_uint64() - def write_datetime(self, n): - self.write_uint64(n) + return timestamp(self.read_uint64()) + def write_datetime(self, t): + if isinstance(t, datetime.datetime): + t = timestamp(t) + self.write_uint64(t) def read_double(self): return self.unpack("!d") diff --git a/qpid/python/qpid/datatypes.py b/qpid/python/qpid/datatypes.py index 7150caded2..38fc163dd9 100644 --- a/qpid/python/qpid/datatypes.py +++ b/qpid/python/qpid/datatypes.py @@ -17,7 +17,7 @@ # under the License. # -import threading, struct +import threading, struct, datetime, time class Struct: @@ -296,3 +296,51 @@ class UUID: def __repr__(self): return "UUID(%r)" % str(self) + +class timestamp(float): + + def __new__(cls, obj=None): + if obj is None: + obj = time.time() + elif isinstance(obj, datetime.datetime): + obj = time.mktime(obj.timetuple()) + 1e-6 * obj.microsecond + return super(timestamp, cls).__new__(cls, obj) + + def datetime(self): + return datetime.datetime.fromtimestamp(self) + + def __add__(self, other): + if isinstance(other, datetime.timedelta): + return timestamp(self.datetime() + other) + else: + return timestamp(float(self) + other) + + def __sub__(self, other): + if isinstance(other, datetime.timedelta): + return timestamp(self.datetime() - other) + else: + return timestamp(float(self) - other) + + def __radd__(self, other): + if isinstance(other, datetime.timedelta): + return timestamp(self.datetime() + other) + else: + return timestamp(other + float(self)) + + def __rsub__(self, other): + if isinstance(other, datetime.timedelta): + return timestamp(self.datetime() - other) + else: + return timestamp(other - float(self)) + + def __neg__(self): + return timestamp(-float(self)) + + def __pos__(self): + return self + + def __abs__(self): + return timestamp(abs(float(self))) + + def __repr__(self): + return "timestamp(%r)" % float(self) diff --git a/qpid/python/qpid/spec010.py b/qpid/python/qpid/spec010.py index 23966e6176..cbc85a5e8b 100644 --- a/qpid/python/qpid/spec010.py +++ b/qpid/python/qpid/spec010.py @@ -17,7 +17,7 @@ # under the License. # -import os, cPickle, datatypes +import os, cPickle, datatypes, datetime from codec010 import StringCodec from util import mtime, fill @@ -477,7 +477,9 @@ class Spec(Node): None.__class__: "void", list: "list", tuple: "list", - dict: "map" + dict: "map", + datatypes.timestamp: "datetime", + datetime.datetime: "datetime" } def __init__(self, major, minor, port, children): diff --git a/qpid/python/tests/codec010.py b/qpid/python/tests/codec010.py index bbe894b7b3..5f9f853744 100644 --- a/qpid/python/tests/codec010.py +++ b/qpid/python/tests/codec010.py @@ -17,22 +17,27 @@ # under the License. # +import time + from unittest import TestCase from qpid.spec010 import load from qpid.codec010 import StringCodec from qpid.testlib import testrunner +from qpid.datatypes import timestamp class CodecTest(TestCase): def setUp(self): self.spec = load(testrunner.get_spec_file("amqp.0-10.xml")) - def check(self, type, value): + def check(self, type, value, compare=True): t = self.spec[type] sc = StringCodec(self.spec) t.encode(sc, value) decoded = t.decode(sc) - assert decoded == value, "%s, %s" % (decoded, value) + if compare: + assert decoded == value, "%s, %s" % (decoded, value) + return decoded def testMapString(self): self.check("map", {"string": "this is a test"}) @@ -43,6 +48,15 @@ class CodecTest(TestCase): def testMapLong(self): self.check("map", {"long": 2**32}) + def testMapTimestamp(self): + decoded = self.check("map", {"timestamp": timestamp(0)}) + assert isinstance(decoded["timestamp"], timestamp) + + def testMapDatetime(self): + decoded = self.check("map", {"datetime": timestamp(0).datetime()}, compare=False) + assert isinstance(decoded["datetime"], timestamp) + assert decoded["datetime"] == 0.0 + def testMapNone(self): self.check("map", {"none": None}) @@ -53,12 +67,14 @@ class CodecTest(TestCase): self.check("map", {"list": [1, "two", 3.0, -4]}) def testMapAll(self): - self.check("map", {"string": "this is a test", - "int": 3, - "long": 2**32, - "none": None, - "map": {"string": "nested map"}, - "list": [1, "two", 3.0, -4]}) + decoded = self.check("map", {"string": "this is a test", + "int": 3, + "long": 2**32, + "timestamp": timestamp(0), + "none": None, + "map": {"string": "nested map"}, + "list": [1, "two", 3.0, -4]}) + assert isinstance(decoded["timestamp"], timestamp) def testMapEmpty(self): self.check("map", {}) @@ -90,3 +106,7 @@ class CodecTest(TestCase): def testInt16(self): self.check("int16", 3) self.check("int16", -3) + + def testDatetime(self): + self.check("datetime", timestamp(0)) + self.check("datetime", timestamp(long(time.time()))) diff --git a/qpid/python/tests/datatypes.py b/qpid/python/tests/datatypes.py index ef98e81da0..4b9e1bcc78 100644 --- a/qpid/python/tests/datatypes.py +++ b/qpid/python/tests/datatypes.py @@ -223,3 +223,35 @@ class MessageTest(TestCase): assert m.get("fragment_properties") is None assert m.get("message_properties") == self.mp assert m.get("delivery_properties") == self.dp + +class TimestampTest(TestCase): + + def check(self, expected, *values): + for v in values: + assert isinstance(v, timestamp) + assert v == expected + assert v == timestamp(expected) + + def testAdd(self): + self.check(4.0, + timestamp(2.0) + 2.0, + 2.0 + timestamp(2.0)) + + def testSub(self): + self.check(2.0, + timestamp(4.0) - 2.0, + 4.0 - timestamp(2.0)) + + def testNeg(self): + self.check(-4.0, -timestamp(4.0)) + + def testPos(self): + self.check(+4.0, +timestamp(4.0)) + + def testAbs(self): + self.check(4.0, abs(timestamp(-4.0))) + + def testConversion(self): + dt = timestamp(0).datetime() + t = timestamp(dt) + assert t == 0 |