diff options
author | Rafael H. Schloming <rhs@apache.org> | 2008-03-07 20:22:18 +0000 |
---|---|---|
committer | Rafael H. Schloming <rhs@apache.org> | 2008-03-07 20:22:18 +0000 |
commit | 9348ffddf9dbeb1029a91f0804a5f3b1e22f8821 (patch) | |
tree | 0526d5636f51483eccb437f1035a9d9a9e1f2670 | |
parent | 039d4461a0c1bb44731bbee6df58c0ee0c1673cf (diff) | |
download | qpid-python-9348ffddf9dbeb1029a91f0804a5f3b1e22f8821.tar.gz |
added support for maps
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@634803 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | python/qpid/codec010.py | 29 | ||||
-rw-r--r-- | python/qpid/delegates.py | 9 | ||||
-rw-r--r-- | python/qpid/spec010.py | 30 | ||||
-rw-r--r-- | python/tests/__init__.py | 1 | ||||
-rw-r--r-- | python/tests/codec010.py | 57 |
5 files changed, 116 insertions, 10 deletions
diff --git a/python/qpid/codec010.py b/python/qpid/codec010.py index f6539ffcee..27df9db974 100644 --- a/python/qpid/codec010.py +++ b/python/qpid/codec010.py @@ -20,11 +20,18 @@ from packer import Packer from datatypes import RangedSet +class CodecException(Exception): pass + class Codec(Packer): def __init__(self, spec): self.spec = spec + def write_void(self, v): + assert v == None + def read_void(self): + return None + def write_bit(self, b): if not b: raise ValueError(b) def read_bit(self): @@ -148,10 +155,26 @@ class Codec(Packer): self.write(b) def write_map(self, m): - self.write_uint32(0) #hack + sc = StringCodec(self.spec) + for k, v in m.items(): + type = self.spec.encoding(v.__class__) + if type == None: + raise CodecException("no encoding for %s" % v.__class__) + sc.write_str8(k) + sc.write_uint8(type.code) + type.encode(sc, v) + # XXX: need to put in count when CPP supports it + self.write_vbin32(sc.encoded) def read_map(self): - size = self.read_uint32() #hack - self.read(size) #hack + sc = StringCodec(self.spec, self.read_vbin32()) + result = {} + while sc.encoded: + k = sc.read_str8() + code = sc.read_uint8() + type = self.spec.types[code] + v = type.decode(sc) + result[k] = v + return result def write_array(self, a): pass diff --git a/python/qpid/delegates.py b/python/qpid/delegates.py index a29d5c5265..d1f615a3fa 100644 --- a/python/qpid/delegates.py +++ b/python/qpid/delegates.py @@ -17,8 +17,7 @@ # under the License. # -import connection010 -import session +import os, connection010, session from util import notify from datatypes import RangedSet @@ -117,12 +116,16 @@ class Server(Delegate): class Client(Delegate): + PROPERTIES = {"product": "qpid python client", + "version": "development", + "platform": os.name} + def start(self): self.connection.write_header(self.spec.major, self.spec.minor) self.connection.read_header() def connection_start(self, ch, start): - ch.connection_start_ok() + ch.connection_start_ok(client_properties=Client.PROPERTIES) def connection_tune(self, ch, tune): ch.connection_tune_ok() diff --git a/python/qpid/spec010.py b/python/qpid/spec010.py index c3f3e6ad57..b84be7a047 100644 --- a/python/qpid/spec010.py +++ b/python/qpid/spec010.py @@ -122,7 +122,6 @@ class Type(Named, Node): def register(self, node): Named.register(self, node) - node.types.append(self) Node.register(self) class Primitive(Coded, Type): @@ -133,6 +132,11 @@ class Primitive(Coded, Type): self.fixed = fixed self.variable = variable + def register(self, node): + Type.register(self, node) + if self.code is not None: + self.spec.types[self.code] = self + def is_present(self, value): if self.fixed == 0: return value @@ -265,7 +269,8 @@ class Struct(Composite): def register(self, node): Composite.register(self, node) - self.spec.structs[self.code] = self + if self.code is not None: + self.spec.structs[self.code] = self def __str__(self): fields = ",\n ".join(["%s: %s" % (f.name, f.type.qname) @@ -384,7 +389,6 @@ class Class(Named, Coded, Node): Named.__init__(self, name) Coded.__init__(self, code) Node.__init__(self, children) - self.types = [] self.controls = [] self.commands = [] @@ -441,6 +445,16 @@ class Exception(Named, Node): class Spec(Node): + ENCODINGS = { + basestring: "vbin16", + int: "int32", + long: "int64", + None.__class__: "void", + list: "list", + tuple: "list", + dict: "map" + } + def __init__(self, major, minor, port, children): Node.__init__(self, children) self.major = major @@ -448,7 +462,7 @@ class Spec(Node): self.port = port self.constants = [] self.classes = [] - self.types = [] + self.types = {} self.qname = None self.spec = self self.klass = None @@ -457,6 +471,14 @@ class Spec(Node): self.commands = {} self.structs = {} + def encoding(self, klass): + if Spec.ENCODINGS.has_key(klass): + return self.named[Spec.ENCODINGS[klass]] + for base in klass.__bases__: + result = self.encoding(base) + if result != None: + return result + class Implement: def __init__(self, handle): diff --git a/python/tests/__init__.py b/python/tests/__init__.py index 8e9eeb44d6..521e2f15c9 100644 --- a/python/tests/__init__.py +++ b/python/tests/__init__.py @@ -27,3 +27,4 @@ from assembler import * from datatypes import * from connection010 import * from spec010 import * +from codec010 import * diff --git a/python/tests/codec010.py b/python/tests/codec010.py new file mode 100644 index 0000000000..65d4525758 --- /dev/null +++ b/python/tests/codec010.py @@ -0,0 +1,57 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from unittest import TestCase +from qpid.spec010 import load +from qpid.codec010 import StringCodec +from qpid.testlib import testrunner + +class CodecTest(TestCase): + + def setUp(self): + self.spec = load(testrunner.get_spec_file("amqp.0-10.xml")) + + def check(self, type, value): + t = self.spec[type] + sc = StringCodec(self.spec) + t.encode(sc, value) + decoded = t.decode(sc) + assert decoded == value + + def testMapString(self): + self.check("map", {"string": "this is a test"}) + + def testMapInt(self): + self.check("map", {"int": 3}) + + def testMapLong(self): + self.check("map", {"long": 2**32}) + + def testMapNone(self): + self.check("map", {"none": None}) + + def testMapNested(self): + self.check("map", {"map": {"string": "nested test"}}) + + def testMapAll(self): + self.check("map", {"string": "this is a test", + "int": 3, + "long": 2**32, + "none": None, + "map": {"string": "nested map"}}) |