summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2006-08-24 23:00:10 +0000
committerMark Spruiell <mes@zeroc.com>2006-08-24 23:00:10 +0000
commitc8d6203027334c6ca01aa75bb799b52c4924b102 (patch)
treeed4c7e774d7a4d20573b1de660041115f952bb96 /py
parentbug 1316: auto_array (diff)
downloadice-c8d6203027334c6ca01aa75bb799b52c4924b102.tar.bz2
ice-c8d6203027334c6ca01aa75bb799b52c4924b102.tar.xz
ice-c8d6203027334c6ca01aa75bb799b52c4924b102.zip
bug 943: map sequence<byte> to string
Diffstat (limited to 'py')
-rw-r--r--py/CHANGES65
-rw-r--r--py/modules/IcePy/.depend27
-rw-r--r--py/modules/IcePy/Operation.cpp122
-rw-r--r--py/modules/IcePy/Types.cpp478
-rw-r--r--py/modules/IcePy/Types.h69
-rw-r--r--py/modules/IcePy/Util.cpp46
-rw-r--r--py/modules/IcePy/Util.h5
-rw-r--r--py/python/Ice.py12
-rw-r--r--py/test/Ice/custom/AllTests.py108
-rw-r--r--py/test/Ice/custom/Client.py46
-rw-r--r--py/test/Ice/custom/Server.py113
-rw-r--r--py/test/Ice/custom/Test.ice70
-rwxr-xr-xpy/test/Ice/custom/run.py26
-rw-r--r--py/test/Ice/operations/Twoways.py100
14 files changed, 1006 insertions, 281 deletions
diff --git a/py/CHANGES b/py/CHANGES
index 4e363bd94d4..530572a968e 100644
--- a/py/CHANGES
+++ b/py/CHANGES
@@ -1,3 +1,60 @@
+NOTE: Please keep changes in the appropriate section for HEAD or 3.1.
+
+Changes since version 3.1.1
+---------------------------
+
+- Added support for metadata to modify the mapping of a Slice
+ sequence type. The default mapping for sequences remains unchanged
+ (except for sequence<byte> as described below): a sequence is
+ received as a Python list. Using metadata, you can now specify that
+ a sequence be received as a tuple instead:
+
+ ["python:seq:tuple"] sequence<string> StringTuple;
+
+ In this example, all occurrences of StringTuple are received as
+ a tuple. You can also apply the metadata more selectively:
+
+ sequence<string> StringList;
+ struct S {
+ StringList l;
+ ["python:seq:tuple"] StringList stringTuple;
+ };
+ interface I {
+ ["python:seq:tuple"] StringList op(StringList l);
+ };
+
+ In this case, the default mapping is used for all occurrences of
+ StringList except for the stringTuple member of the structure and
+ the return value of op().
+
+ The metadata "python:seq:list" forces a sequence to be received
+ as a list, which you can use to override a prior metadata
+ definition:
+
+ ["python:seq:tuple"] sequence<string> StringTuple;
+ struct S {
+ ["python:seq:list"] StringTuple stringList;
+ };
+
+ Finally, the metadata "python:seq:default" directs the extension
+ to use the default mapping for the sequence, which is a list for all
+ sequence types except sequence<byte>.
+
+- The default mapping for the Slice type sequence<byte> is now a
+ Python string, and therefore a string is also accepted as a legal
+ value for sequence<byte>. For programs that need to continue
+ receiving a sequence<byte> value as a list, you can use a metadata
+ directive to modify the mapping as shown below:
+
+ ["python:seq:list"] sequence<byte> ByteList;
+
+- The extension now accepts an object that implements the buffer
+ protocol as a legal value for sequences of most primitive types.
+ For example, it is more efficient to transfer an array of integer
+ values constructed using the "array" module than it is using a tuple
+ or a list. Note that no type- or range-checking is performed on the
+ contents of a buffer.
+
Changes since version 3.1.0
---------------------------
@@ -5,13 +62,13 @@ Changes since version 3.1.0
where the session would not be destroyed in the event of an
allocation failure.
--- Added UnexpectedObjectException. This exception is raised if you
+- Added UnexpectedObjectException. This exception is raised if you
use Slice classes and client and server are compiled with mismatched
Slice definitions. Alternatively, this exception is raised if you
- use dynamic invocation and pass a class of the wrong type as an operation
- parameter.
+ use dynamic invocation and pass a class of the wrong type as an
+ operation parameter.
-- Restored Communicator::setDefaultContext
+- Restored Communicator::setDefaultContext.
Changes since version 3.0.1
---------------------------
diff --git a/py/modules/IcePy/.depend b/py/modules/IcePy/.depend
index dfe6878a40c..9e75a745408 100644
--- a/py/modules/IcePy/.depend
+++ b/py/modules/IcePy/.depend
@@ -1,13 +1,14 @@
-Communicator.o: Communicator.cpp Communicator.h Config.h Logger.h Util.h ObjectAdapter.h ObjectFactory.h Properties.h Proxy.h
-Connection.o: Connection.cpp Connection.h Config.h ObjectAdapter.h Proxy.h Util.h
-Current.o: Current.cpp Current.h Config.h Connection.h ObjectAdapter.h Util.h
-Init.o: Init.cpp Communicator.h Config.h Connection.h Current.h Logger.h Util.h ObjectAdapter.h Operation.h Properties.h Proxy.h Slice.h Types.h
-Logger.o: Logger.cpp Logger.h Config.h Util.h
-ObjectAdapter.o: ObjectAdapter.cpp ObjectAdapter.h Config.h Communicator.h Current.h Operation.h Proxy.h Util.h
-ObjectFactory.o: ObjectFactory.cpp ObjectFactory.h Config.h Types.h Util.h
-Operation.o: Operation.cpp Operation.h Config.h Current.h Proxy.h Types.h Util.h
-Properties.o: Properties.cpp Properties.h Config.h Util.h
-Proxy.o: Proxy.cpp Proxy.h Config.h Communicator.h Connection.h Util.h
-Slice.o: Slice.cpp Slice.h Config.h Util.h
-Types.o: Types.cpp Types.h Config.h Util.h Current.h Proxy.h
-Util.o: Util.cpp Util.h Config.h
+Communicator.o: Communicator.cpp ./Communicator.h ./Config.h ./Logger.h ./Util.h ./ObjectAdapter.h ./ObjectFactory.h ./Properties.h ./Proxy.h ./ThreadNotification.h
+Connection.o: Connection.cpp ./Connection.h ./Config.h ./ObjectAdapter.h ./Proxy.h ./Util.h
+Current.o: Current.cpp ./Current.h ./Config.h ./Connection.h ./ObjectAdapter.h ./Util.h
+Init.o: Init.cpp ./Communicator.h ./Config.h ./Connection.h ./Current.h ./Logger.h ./Util.h ./ObjectAdapter.h ./Operation.h ./Properties.h ./Proxy.h ./Slice.h ./Types.h
+Logger.o: Logger.cpp ./Logger.h ./Config.h ./Util.h
+ObjectAdapter.o: ObjectAdapter.cpp ./ObjectAdapter.h ./Config.h ./Communicator.h ./Current.h ./Operation.h ./Proxy.h ./Util.h
+ObjectFactory.o: ObjectFactory.cpp ./ObjectFactory.h ./Config.h ./Types.h ./Util.h
+Operation.o: Operation.cpp ./Operation.h ./Config.h ./Current.h ./Proxy.h ./Types.h ./Util.h
+Properties.o: Properties.cpp ./Properties.h ./Config.h ./Util.h
+Proxy.o: Proxy.cpp ./Proxy.h ./Config.h ./Communicator.h ./Connection.h ./Util.h
+Slice.o: Slice.cpp ./Slice.h ./Config.h ./Util.h
+ThreadNotification.o: ThreadNotification.cpp ./ThreadNotification.h ./Config.h ./Util.h
+Types.o: Types.cpp ./Types.h ./Config.h ./Util.h ./Current.h ./Proxy.h
+Util.o: Util.cpp ./Util.h ./Config.h
diff --git a/py/modules/IcePy/Operation.cpp b/py/modules/IcePy/Operation.cpp
index 177d3e25557..1808fdc96fa 100644
--- a/py/modules/IcePy/Operation.cpp
+++ b/py/modules/IcePy/Operation.cpp
@@ -38,6 +38,7 @@ public:
virtual void unmarshaled(PyObject*, PyObject*, void*);
+ Ice::StringSeq metaData;
TypeInfoPtr type;
};
typedef IceUtil::Handle<ParamInfo> ParamInfoPtr;
@@ -47,7 +48,7 @@ class OperationI : public Operation
{
public:
- OperationI(const char*, PyObject*, PyObject*, int, PyObject*, PyObject*, PyObject*, PyObject*);
+ OperationI(const char*, PyObject*, PyObject*, int, PyObject*, PyObject*, PyObject*, PyObject*, PyObject*);
virtual PyObject* invoke(const Ice::ObjectPrx&, PyObject*, PyObject*);
virtual PyObject* invokeAsync(const Ice::ObjectPrx&, PyObject*, PyObject*, PyObject*);
@@ -69,6 +70,7 @@ private:
Ice::OperationMode _mode;
Ice::OperationMode _sendMode;
bool _amd;
+ Ice::StringSeq _metaData;
ParamInfoList _inParams;
ParamInfoList _outParams;
ParamInfoPtr _returnType;
@@ -83,6 +85,7 @@ private:
PyObject* unmarshalException(const vector<Ice::Byte>&, const Ice::CommunicatorPtr&);
bool validateException(PyObject*) const;
void checkTwowayOnly(const Ice::ObjectPrx&) const;
+ static void convertParams(PyObject*, ParamInfoList&, bool&);
};
typedef IceUtil::Handle<OperationI> OperationIPtr;
@@ -149,17 +152,19 @@ operationInit(OperationObject* self, PyObject* args, PyObject* /*kwds*/)
PyObject* mode;
PyObject* sendMode;
int amd;
+ PyObject* meta;
PyObject* inParams;
PyObject* outParams;
PyObject* returnType;
PyObject* exceptions;
- if(!PyArg_ParseTuple(args, STRCAST("sO!O!iO!O!OO!"), &name, modeType, &mode, modeType, &sendMode, &amd,
- &PyTuple_Type, &inParams, &PyTuple_Type, &outParams, &returnType, &PyTuple_Type, &exceptions))
+ if(!PyArg_ParseTuple(args, STRCAST("sO!O!iO!O!O!OO!"), &name, modeType, &mode, modeType, &sendMode, &amd,
+ &PyTuple_Type, &meta, &PyTuple_Type, &inParams, &PyTuple_Type, &outParams, &returnType,
+ &PyTuple_Type, &exceptions))
{
return -1;
}
- OperationIPtr op = new OperationI(name, mode, sendMode, amd, inParams, outParams, returnType, exceptions);
+ OperationIPtr op = new OperationI(name, mode, sendMode, amd, meta, inParams, outParams, returnType, exceptions);
self->op = new OperationPtr(op);
return 0;
@@ -394,19 +399,10 @@ IcePy::AMICallback::ice_exception(const Ice::Exception& ex)
//
// OperationI implementation.
//
-IcePy::OperationI::OperationI(const char* name, PyObject* mode, PyObject* sendMode, int amd, PyObject* inParams,
- PyObject* outParams, PyObject* returnType, PyObject* exceptions)
+IcePy::OperationI::OperationI(const char* name, PyObject* mode, PyObject* sendMode, int amd, PyObject* meta,
+ PyObject* inParams, PyObject* outParams, PyObject* returnType, PyObject* exceptions)
{
_name = name;
- _amd = amd ? true : false;
- if(_amd)
- {
- _dispatchName = fixIdent(_name) + "_async";
- }
- else
- {
- _dispatchName = fixIdent(_name);
- }
//
// mode
@@ -422,39 +418,39 @@ IcePy::OperationI::OperationI(const char* name, PyObject* mode, PyObject* sendMo
assert(PyInt_Check(sendModeValue.get()));
_sendMode = (Ice::OperationMode)static_cast<int>(PyInt_AS_LONG(sendModeValue.get()));
+ //
+ // amd
+ //
+ _amd = amd ? true : false;
+ if(_amd)
+ {
+ _dispatchName = fixIdent(_name) + "_async";
+ }
+ else
+ {
+ _dispatchName = fixIdent(_name);
+ }
+
+ //
+ // metaData
+ //
+#ifndef NDEBUG
+ bool b =
+#endif
+ tupleToStringSeq(meta, _metaData);
+ assert(b);
+
int i, sz;
//
// inParams
//
- _sendsClasses = false;
- sz = PyTuple_GET_SIZE(inParams);
- for(i = 0; i < sz; ++i)
- {
- ParamInfoPtr param = new ParamInfo;
- param->type = getType(PyTuple_GET_ITEM(inParams, i));
- _inParams.push_back(param);
- if(!_sendsClasses)
- {
- _sendsClasses = param->type->usesClasses();
- }
- }
+ convertParams(inParams, _inParams, _sendsClasses);
//
// outParams
//
- _returnsClasses = false;
- sz = PyTuple_GET_SIZE(outParams);
- for(i = 0; i < sz; ++i)
- {
- ParamInfoPtr param = new ParamInfo;
- param->type = getType(PyTuple_GET_ITEM(outParams, i));
- _outParams.push_back(param);
- if(!_returnsClasses)
- {
- _returnsClasses = param->type->usesClasses();
- }
- }
+ convertParams(outParams, _outParams, _returnsClasses);
//
// returnType
@@ -708,7 +704,7 @@ IcePy::OperationI::dispatch(PyObject* servant, const Ice::AMD_Object_ice_invokeP
for(ParamInfoList::iterator p = _inParams.begin(); p != _inParams.end(); ++p, ++i)
{
void* closure = reinterpret_cast<void*>(i);
- (*p)->type->unmarshal(is, *p, args.get(), closure);
+ (*p)->type->unmarshal(is, *p, args.get(), closure, &(*p)->metaData);
}
if(_sendsClasses)
{
@@ -923,7 +919,7 @@ IcePy::OperationI::sendResponse(const Ice::AMD_Object_ice_invokePtr& cb, PyObjec
PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str()));
throw Ice::MarshalException(__FILE__, __LINE__);
}
- (*p)->type->marshal(arg, os, &objectMap);
+ (*p)->type->marshal(arg, os, &objectMap, &(*p)->metaData);
}
if(_returnType)
@@ -946,7 +942,7 @@ IcePy::OperationI::sendResponse(const Ice::AMD_Object_ice_invokePtr& cb, PyObjec
PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str()));
throw Ice::MarshalException(__FILE__, __LINE__);
}
- _returnType->type->marshal(res, os, &objectMap);
+ _returnType->type->marshal(res, os, &objectMap, &_metaData);
}
if(_returnsClasses)
@@ -1072,7 +1068,7 @@ IcePy::OperationI::prepareRequest(const Ice::CommunicatorPtr& communicator, PyOb
async ? i + 2 : i + 1, const_cast<char*>(opName.c_str()));
return false;
}
- (*p)->type->marshal(arg, os, &objectMap);
+ (*p)->type->marshal(arg, os, &objectMap, &(*p)->metaData);
}
if(_sendsClasses)
@@ -1113,12 +1109,12 @@ IcePy::OperationI::unmarshalResults(const vector<Ice::Byte>& bytes, const Ice::C
for(ParamInfoList::iterator p = _outParams.begin(); p != _outParams.end(); ++p, ++i)
{
void* closure = reinterpret_cast<void*>(i);
- (*p)->type->unmarshal(is, *p, results.get(), closure);
+ (*p)->type->unmarshal(is, *p, results.get(), closure, &(*p)->metaData);
}
if(_returnType)
{
- _returnType->type->unmarshal(is, _returnType, results.get(), 0);
+ _returnType->type->unmarshal(is, _returnType, results.get(), 0, &_metaData);
}
if(_returnsClasses)
@@ -1200,6 +1196,42 @@ IcePy::OperationI::checkTwowayOnly(const Ice::ObjectPrx& proxy) const
}
}
+void
+IcePy::OperationI::convertParams(PyObject* p, ParamInfoList& params, bool& usesClasses)
+{
+ usesClasses = false;
+ int sz = PyTuple_GET_SIZE(p);
+ for(int i = 0; i < sz; ++i)
+ {
+ PyObject* item = PyTuple_GET_ITEM(p, i);
+ assert(PyTuple_Check(item));
+ assert(PyTuple_GET_SIZE(item) == 2);
+
+ ParamInfoPtr param = new ParamInfo;
+
+ //
+ // metaData
+ //
+ PyObject* meta = PyTuple_GET_ITEM(item, 0);
+ assert(PyTuple_Check(meta));
+#ifndef NDEBUG
+ bool b =
+#endif
+ tupleToStringSeq(meta, param->metaData);
+ assert(b);
+
+ //
+ // type
+ //
+ param->type = getType(PyTuple_GET_ITEM(item, 1));
+ params.push_back(param);
+ if(!usesClasses)
+ {
+ usesClasses = param->type->usesClasses();
+ }
+ }
+}
+
static PyMethodDef OperationMethods[] =
{
{ STRCAST("invoke"), (PyCFunction)operationInvoke, METH_VARARGS,
diff --git a/py/modules/IcePy/Types.cpp b/py/modules/IcePy/Types.cpp
index c17af2bdefd..e658cf835b4 100644
--- a/py/modules/IcePy/Types.cpp
+++ b/py/modules/IcePy/Types.cpp
@@ -15,6 +15,7 @@
#include <Proxy.h>
#include <Util.h>
#include <IceUtil/InputUtil.h>
+#include <IceUtil/ScopedArray.h>
#include <Ice/LocalException.h>
using namespace std;
@@ -372,7 +373,7 @@ IcePy::PrimitiveInfo::validate(PyObject* p)
}
void
-IcePy::PrimitiveInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*)
+IcePy::PrimitiveInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, const Ice::StringSeq*)
{
switch(kind)
{
@@ -519,7 +520,7 @@ IcePy::PrimitiveInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Objec
void
IcePy::PrimitiveInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq*)
{
switch(kind)
{
@@ -620,7 +621,7 @@ IcePy::EnumInfo::validate(PyObject* val)
}
void
-IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*)
+IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, const Ice::StringSeq*)
{
assert(PyObject_IsInstance(p, pythonType.get()) == 1); // validate() should have caught this.
@@ -661,7 +662,7 @@ IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*
void
IcePy::EnumInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq*)
{
int val;
int count = static_cast<int>(enumerators.size());
@@ -748,7 +749,7 @@ IcePy::StructInfo::usesClasses()
}
void
-IcePy::StructInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap)
+IcePy::StructInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, const Ice::StringSeq*)
{
assert(PyObject_IsInstance(p, pythonType.get()) == 1); // validate() should have caught this.
@@ -771,13 +772,13 @@ IcePy::StructInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMa
memberName);
throw AbortMarshaling();
}
- member->type->marshal(attr.get(), os, objectMap);
+ member->type->marshal(attr.get(), os, objectMap, &member->metaData);
}
}
void
IcePy::StructInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq*)
{
PyObjectHandle args = PyTuple_New(0);
PyTypeObject* type = (PyTypeObject*)pythonType.get();
@@ -791,7 +792,7 @@ IcePy::StructInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallb
for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q, ++i)
{
DataMemberPtr member = *q;
- member->type->unmarshal(is, member, p.get(), 0);
+ member->type->unmarshal(is, member, p.get(), 0, &member->metaData);
}
cb->unmarshaled(p.get(), target, closure);
@@ -856,7 +857,8 @@ IcePy::SequenceInfo::usesClasses()
}
void
-IcePy::SequenceInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap)
+IcePy::SequenceInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap,
+ const Ice::StringSeq* metaData)
{
if(p == Py_None)
{
@@ -898,26 +900,40 @@ IcePy::SequenceInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Object
void
IcePy::SequenceInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq* metaData)
{
+ //
+ // Determine the mapping to use for this sequence. Highest priority is given
+ // to the metaData argument, otherwise we use the mapping of the sequence
+ // definition.
+ //
+ SequenceMappingPtr sm;
+ if(metaData)
+ {
+ SequenceMapping::Type type;
+ if(!SequenceMapping::getType(*metaData, type) || type == mapping->type)
+ {
+ sm = mapping;
+ }
+ else
+ {
+ sm = new SequenceMapping(type);
+ }
+ }
+ else
+ {
+ sm = mapping;
+ }
+
PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType);
if(pi)
{
- unmarshalPrimitiveSequence(pi, is, cb, target, closure);
+ unmarshalPrimitiveSequence(pi, is, cb, target, closure, sm);
return;
}
Ice::Int sz = is->readSize();
- PyObjectHandle result;
- if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST)
- {
- result = PyList_New(sz);
- }
- else
- {
- assert(mapping == SEQ_TUPLE);
- result = PyTuple_New(sz);
- }
+ PyObjectHandle result = sm->createContainer(sz);
if(result.get() == NULL)
{
@@ -927,30 +943,13 @@ IcePy::SequenceInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCal
for(Ice::Int i = 0; i < sz; ++i)
{
void* cl = reinterpret_cast<void*>(i);
- elementType->unmarshal(is, this, result.get(), cl);
+ elementType->unmarshal(is, sm, result.get(), cl);
}
cb->unmarshaled(result.get(), target, closure);
}
void
-IcePy::SequenceInfo::unmarshaled(PyObject* val, PyObject* target, void* closure)
-{
- long i = reinterpret_cast<long>(closure);
- if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST)
- {
- PyList_SET_ITEM(target, i, val);
- Py_INCREF(val); // PyList_SET_ITEM steals a reference.
- }
- else
- {
- assert(mapping == SEQ_TUPLE);
- PyTuple_SET_ITEM(target, i, val);
- Py_INCREF(val); // PyTuple_SET_ITEM steals a reference.
- }
-}
-
-void
IcePy::SequenceInfo::print(PyObject* value, IceUtil::Output& out, PrintObjectHistory* history)
{
if(!validate(value))
@@ -1001,27 +1000,88 @@ IcePy::SequenceInfo::destroy()
void
IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObject* p, const Ice::OutputStreamPtr& os)
{
+ //
+ // For most types, we accept an object that implements the buffer protocol
+ // (this includes the array.array type).
+ //
+ const void* buf = 0;
+ int sz;
+ if(PyObject_AsReadBuffer(p, &buf, &sz) == 0)
+ {
+ const Ice::Byte* b = reinterpret_cast<const Ice::Byte*>(buf);
+ switch(pi->kind)
+ {
+ case PrimitiveInfo::KindBool:
+ {
+ os->writeBoolSeq(reinterpret_cast<const bool*>(b), reinterpret_cast<const bool*>(b + sz));
+ break;
+ }
+ case PrimitiveInfo::KindByte:
+ {
+ os->writeByteSeq(reinterpret_cast<const Ice::Byte*>(b), reinterpret_cast<const Ice::Byte*>(b + sz));
+ break;
+ }
+ case PrimitiveInfo::KindShort:
+ {
+ os->writeShortSeq(reinterpret_cast<const Ice::Short*>(b), reinterpret_cast<const Ice::Short*>(b + sz));
+ break;
+ }
+ case PrimitiveInfo::KindInt:
+ {
+ os->writeIntSeq(reinterpret_cast<const Ice::Int*>(b), reinterpret_cast<const Ice::Int*>(b + sz));
+ break;
+ }
+ case PrimitiveInfo::KindLong:
+ {
+ PyErr_Format(PyExc_ValueError, STRCAST("expected sequence value"));
+ throw AbortMarshaling();
+ }
+ case PrimitiveInfo::KindFloat:
+ {
+ os->writeFloatSeq(reinterpret_cast<const Ice::Float*>(b), reinterpret_cast<const Ice::Float*>(b + sz));
+ break;
+ }
+ case PrimitiveInfo::KindDouble:
+ {
+ os->writeDoubleSeq(reinterpret_cast<const Ice::Double*>(b),
+ reinterpret_cast<const Ice::Double*>(b + sz));
+ break;
+ }
+ case PrimitiveInfo::KindString:
+ {
+ PyErr_Format(PyExc_ValueError, STRCAST("expected sequence value"));
+ throw AbortMarshaling();
+ }
+ }
+ return;
+ }
+
+ PyErr_Clear(); // PyObject_AsReadBuffer sets an exception on failure.
+
PyObjectHandle fs;
- if(pi->kind == PrimitiveInfo::KindByte)
+ if(!buf)
{
- //
- // Accept a string or a sequence for sequence<byte>.
- //
- if(!PyString_Check(p))
+ if(pi->kind == PrimitiveInfo::KindByte)
{
- fs = PySequence_Fast(p, STRCAST("expected a string or a sequence value"));
- if(fs.get() == NULL)
+ //
+ // Accept a string or a sequence for sequence<byte>.
+ //
+ if(!PyString_Check(p))
{
- return;
+ fs = PySequence_Fast(p, STRCAST("expected a string, sequence, or buffer value"));
+ if(fs.get() == NULL)
+ {
+ return;
+ }
}
}
- }
- else
- {
- fs = PySequence_Fast(p, STRCAST("expected a sequence value"));
- if(fs.get() == NULL)
+ else
{
- return;
+ fs = PySequence_Fast(p, STRCAST("expected a sequence or buffer value"));
+ if(fs.get() == NULL)
+ {
+ return;
+ }
}
}
@@ -1029,7 +1089,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
{
case PrimitiveInfo::KindBool:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::BoolSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1055,12 +1115,12 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
{
assert(PyString_Check(p));
const char* str = PyString_AS_STRING(p);
- int sz = PyString_GET_SIZE(p);
+ sz = PyString_GET_SIZE(p);
os->writeByteSeq(reinterpret_cast<const Ice::Byte*>(str), reinterpret_cast<const Ice::Byte*>(str + sz));
}
else
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::ByteSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1093,7 +1153,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
}
case PrimitiveInfo::KindShort:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::ShortSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1125,7 +1185,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
}
case PrimitiveInfo::KindInt:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::IntSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1162,7 +1222,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
}
case PrimitiveInfo::KindLong:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::LongSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1199,7 +1259,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
}
case PrimitiveInfo::KindFloat:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::FloatSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1227,7 +1287,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
}
case PrimitiveInfo::KindDouble:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::DoubleSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1255,7 +1315,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
}
case PrimitiveInfo::KindString:
{
- int sz = PySequence_Fast_GET_SIZE(fs.get());
+ sz = PySequence_Fast_GET_SIZE(fs.get());
Ice::StringSeq seq(sz);
for(int i = 0; i < sz; ++i)
{
@@ -1286,7 +1346,8 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje
void
IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, const Ice::InputStreamPtr& is,
- const UnmarshalCallbackPtr& cb, PyObject* target, void* closure)
+ const UnmarshalCallbackPtr& cb, PyObject* target, void* closure,
+ const SequenceMappingPtr& sm)
{
PyObjectHandle result;
@@ -1294,9 +1355,10 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
{
case PrimitiveInfo::KindBool:
{
- Ice::BoolSeq seq = is->readBoolSeq();
- int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ pair<const bool*, const bool*> p;
+ IceUtil::ScopedArray<bool> arr(is->readBoolSeq(p));
+ int sz = static_cast<int>(p.second - p.first);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1304,7 +1366,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
for(int i = 0; i < sz; ++i)
{
- setItem(result.get(), i, seq[i] ? Py_True : Py_False);
+ sm->setItem(result.get(), i, p.first[i] ? Py_True : Py_False);
}
break;
}
@@ -1313,7 +1375,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
pair<const Ice::Byte*, const Ice::Byte*> p;
is->readByteSeq(p);
int sz = static_cast<int>(p.second - p.first);
- if(mapping == SEQ_DEFAULT)
+ if(sm->type == SequenceMapping::SEQ_DEFAULT)
{
result = PyString_FromStringAndSize(reinterpret_cast<const char*>(p.first), sz);
if(result.get() == NULL)
@@ -1323,7 +1385,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
}
else
{
- result = createContainer(sz);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1336,16 +1398,17 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
}
break;
}
case PrimitiveInfo::KindShort:
{
- Ice::ShortSeq seq = is->readShortSeq();
- int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ pair<const Ice::Short*, const Ice::Short*> p;
+ IceUtil::ScopedArray<Ice::Short> arr(is->readShortSeq(p));
+ int sz = static_cast<int>(p.second - p.first);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1353,20 +1416,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
for(int i = 0; i < sz; ++i)
{
- PyObjectHandle item = PyInt_FromLong(seq[i]);
+ PyObjectHandle item = PyInt_FromLong(p.first[i]);
if(item.get() == NULL)
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
break;
}
case PrimitiveInfo::KindInt:
{
- Ice::IntSeq seq = is->readIntSeq();
- int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ pair<const Ice::Int*, const Ice::Int*> p;
+ IceUtil::ScopedArray<Ice::Int> arr(is->readIntSeq(p));
+ int sz = static_cast<int>(p.second - p.first);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1374,20 +1438,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
for(int i = 0; i < sz; ++i)
{
- PyObjectHandle item = PyInt_FromLong(seq[i]);
+ PyObjectHandle item = PyInt_FromLong(p.first[i]);
if(item.get() == NULL)
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
break;
}
case PrimitiveInfo::KindLong:
{
- Ice::LongSeq seq = is->readLongSeq();
- int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ pair<const Ice::Long*, const Ice::Long*> p;
+ IceUtil::ScopedArray<Ice::Long> arr(is->readLongSeq(p));
+ int sz = static_cast<int>(p.second - p.first);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1395,20 +1460,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
for(int i = 0; i < sz; ++i)
{
- PyObjectHandle item = PyLong_FromLongLong(seq[i]);
+ PyObjectHandle item = PyLong_FromLongLong(p.first[i]);
if(item.get() == NULL)
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
break;
}
case PrimitiveInfo::KindFloat:
{
- Ice::FloatSeq seq = is->readFloatSeq();
- int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ pair<const Ice::Float*, const Ice::Float*> p;
+ IceUtil::ScopedArray<Ice::Float> arr(is->readFloatSeq(p));
+ int sz = static_cast<int>(p.second - p.first);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1416,20 +1482,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
for(int i = 0; i < sz; ++i)
{
- PyObjectHandle item = PyFloat_FromDouble(seq[i]);
+ PyObjectHandle item = PyFloat_FromDouble(p.first[i]);
if(item.get() == NULL)
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
break;
}
case PrimitiveInfo::KindDouble:
{
- Ice::DoubleSeq seq = is->readDoubleSeq();
- int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ pair<const Ice::Double*, const Ice::Double*> p;
+ IceUtil::ScopedArray<Ice::Double> arr(is->readDoubleSeq(p));
+ int sz = static_cast<int>(p.second - p.first);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1437,12 +1504,12 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
for(int i = 0; i < sz; ++i)
{
- PyObjectHandle item = PyFloat_FromDouble(seq[i]);
+ PyObjectHandle item = PyFloat_FromDouble(p.first[i]);
if(item.get() == NULL)
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
break;
}
@@ -1450,7 +1517,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
{
Ice::StringSeq seq = is->readStringSeq();
int sz = static_cast<int>(seq.size());
- result = createContainer(sz);
+ result = sm->createContainer(sz);
if(result.get() == NULL)
{
throw AbortMarshaling();
@@ -1463,7 +1530,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
{
throw AbortMarshaling();
}
- setItem(result.get(), i, item.get());
+ sm->setItem(result.get(), i, item.get());
}
break;
}
@@ -1471,31 +1538,89 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons
cb->unmarshaled(result.get(), target, closure);
}
+bool
+IcePy::SequenceInfo::SequenceMapping::getType(const Ice::StringSeq& metaData, Type& t)
+{
+ if(!metaData.empty())
+ {
+ for(Ice::StringSeq::const_iterator p = metaData.begin(); p != metaData.end(); ++p)
+ {
+ if((*p) == "python:seq:default")
+ {
+ t = SEQ_DEFAULT;
+ return true;
+ }
+ else if((*p) == "python:seq:tuple")
+ {
+ t = SEQ_TUPLE;
+ return true;
+ }
+ else if((*p) == "python:seq:list")
+ {
+ t = SEQ_LIST;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+IcePy::SequenceInfo::SequenceMapping::SequenceMapping(Type t) :
+ type(t)
+{
+}
+
+IcePy::SequenceInfo::SequenceMapping::SequenceMapping(const Ice::StringSeq& meta)
+{
+ if(!getType(meta, type))
+ {
+ type = SEQ_DEFAULT;
+ }
+}
+
+void
+IcePy::SequenceInfo::SequenceMapping::unmarshaled(PyObject* val, PyObject* target, void* closure)
+{
+ long i = reinterpret_cast<long>(closure);
+ if(type == SEQ_DEFAULT || type == SEQ_LIST)
+ {
+ PyList_SET_ITEM(target, i, val);
+ Py_INCREF(val); // PyList_SET_ITEM steals a reference.
+ }
+ else
+ {
+ assert(type == SEQ_TUPLE);
+ PyTuple_SET_ITEM(target, i, val);
+ Py_INCREF(val); // PyTuple_SET_ITEM steals a reference.
+ }
+}
+
PyObject*
-IcePy::SequenceInfo::createContainer(int sz) const
+IcePy::SequenceInfo::SequenceMapping::createContainer(int sz) const
{
- if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST)
+ if(type == SEQ_DEFAULT || type == SEQ_LIST)
{
return PyList_New(sz);
}
else
{
- assert(mapping == SEQ_TUPLE);
+ assert(type == SEQ_TUPLE);
return PyTuple_New(sz);
}
}
void
-IcePy::SequenceInfo::setItem(PyObject* cont, int i, PyObject* val) const
+IcePy::SequenceInfo::SequenceMapping::setItem(PyObject* cont, int i, PyObject* val) const
{
- if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST)
+ if(type == SEQ_DEFAULT || type == SEQ_LIST)
{
Py_INCREF(val);
PyList_SET_ITEM(cont, i, val); // PyList_SET_ITEM steals a reference.
}
else
{
- assert(mapping == SEQ_TUPLE);
+ assert(type == SEQ_TUPLE);
Py_INCREF(val);
PyTuple_SET_ITEM(cont, i, val); // PyTuple_SET_ITEM steals a reference.
}
@@ -1523,7 +1648,8 @@ IcePy::DictionaryInfo::usesClasses()
}
void
-IcePy::DictionaryInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap)
+IcePy::DictionaryInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap,
+ const Ice::StringSeq*)
{
if(p == Py_None)
{
@@ -1562,7 +1688,7 @@ IcePy::DictionaryInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Obje
void
IcePy::DictionaryInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq*)
{
PyObjectHandle p = PyDict_New();
if(p.get() == NULL)
@@ -1697,7 +1823,8 @@ IcePy::ClassInfo::usesClasses()
}
void
-IcePy::ClassInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap)
+IcePy::ClassInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap,
+ const Ice::StringSeq*)
{
if(pythonType.get() == NULL)
{
@@ -1751,7 +1878,7 @@ IcePy::ClassInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap
void
IcePy::ClassInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq*)
{
if(pythonType.get() == NULL)
{
@@ -1856,7 +1983,7 @@ IcePy::ProxyInfo::validate(PyObject* val)
}
void
-IcePy::ProxyInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*)
+IcePy::ProxyInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, const Ice::StringSeq*)
{
if(p == Py_None)
{
@@ -1874,7 +2001,7 @@ IcePy::ProxyInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap
void
IcePy::ProxyInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target,
- void* closure)
+ void* closure, const Ice::StringSeq*)
{
Ice::ObjectPrx proxy = is->readProxy();
@@ -1982,7 +2109,7 @@ IcePy::ObjectWriter::write(const Ice::OutputStreamPtr& os) const
throw AbortMarshaling();
}
- member->type->marshal(val.get(), os, _map);
+ member->type->marshal(val.get(), os, _map, &member->metaData);
}
os->endSlice();
@@ -2045,7 +2172,7 @@ IcePy::ObjectReader::read(const Ice::InputStreamPtr& is, bool rid)
for(DataMemberList::iterator p = info->members.begin(); p != info->members.end(); ++p)
{
DataMemberPtr member = *p;
- member->type->unmarshal(is, member, _object, 0);
+ member->type->unmarshal(is, member, _object, 0, &member->metaData);
}
is->endSlice();
@@ -2190,7 +2317,7 @@ IcePy::ExceptionInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Objec
throw AbortMarshaling();
}
- member->type->marshal(val.get(), os, objectMap);
+ member->type->marshal(val.get(), os, objectMap, &member->metaData);
}
os->endSlice();
@@ -2213,7 +2340,7 @@ IcePy::ExceptionInfo::unmarshal(const Ice::InputStreamPtr& is)
for(DataMemberList::iterator q = info->members.begin(); q != info->members.end(); ++q)
{
DataMemberPtr member = *q;
- member->type->unmarshal(is, member, p.get(), 0);
+ member->type->unmarshal(is, member, p.get(), 0, &member->metaData);
}
is->endSlice();
@@ -2539,13 +2666,15 @@ IcePy_defineEnum(PyObject*, PyObject* args)
{
char* id;
PyObject* type;
+ PyObject* meta;
PyObject* enumerators;
- if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &type, &enumerators))
+ if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &type, &meta, &enumerators))
{
return NULL;
}
assert(PyType_Check(type));
+ assert(PyTuple_Check(meta));
assert(PyTuple_Check(enumerators));
EnumInfoPtr info = new EnumInfo;
@@ -2565,19 +2694,49 @@ IcePy_defineEnum(PyObject*, PyObject* args)
return createType(info);
}
+static void
+convertDataMembers(PyObject* members, DataMemberList& l)
+{
+ int sz = PyTuple_GET_SIZE(members);
+ for(int i = 0; i < sz; ++i)
+ {
+ PyObject* m = PyTuple_GET_ITEM(members, i);
+ assert(PyTuple_Check(m));
+ assert(PyTuple_GET_SIZE(m) == 3);
+
+ PyObject* name = PyTuple_GET_ITEM(m, 0); // Member name.
+ assert(PyString_Check(name));
+ PyObject* meta = PyTuple_GET_ITEM(m, 1); // Member metadata.
+ assert(PyTuple_Check(meta));
+ PyObject* t = PyTuple_GET_ITEM(m, 2); // Member type.
+
+ DataMemberPtr member = new DataMember;
+ member->name = string(PyString_AS_STRING(name), PyString_GET_SIZE(name));
+#ifndef NDEBUG
+ bool b =
+#endif
+ tupleToStringSeq(meta, member->metaData);
+ assert(b);
+ member->type = getType(t);
+ l.push_back(member);
+ }
+}
+
extern "C"
PyObject*
IcePy_defineStruct(PyObject*, PyObject* args)
{
char* id;
PyObject* type;
+ PyObject* meta;
PyObject* members;
- if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &type, &members))
+ if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &type, &meta, &members))
{
return NULL;
}
assert(PyType_Check(type));
+ assert(PyTuple_Check(meta));
assert(PyTuple_Check(members));
StructInfoPtr info = new StructInfo;
@@ -2585,20 +2744,7 @@ IcePy_defineStruct(PyObject*, PyObject* args)
info->pythonType = type;
Py_INCREF(type);
- int sz = PyTuple_GET_SIZE(members);
- for(int i = 0; i < sz; ++i)
- {
- PyObject* m = PyTuple_GET_ITEM(members, i);
- assert(PyTuple_Check(m));
- assert(PyTuple_GET_SIZE(m) == 2);
- PyObject* s = PyTuple_GET_ITEM(m, 0); // Member name.
- assert(PyString_Check(s));
- PyObject* t = PyTuple_GET_ITEM(m, 1); // Member type.
- DataMemberPtr member = new DataMember;
- member->name = string(PyString_AS_STRING(s), PyString_GET_SIZE(s));
- member->type = getType(t);
- info->members.push_back(member);
- }
+ convertDataMembers(members, info->members);
return createType(info);
}
@@ -2608,30 +2754,25 @@ PyObject*
IcePy_defineSequence(PyObject*, PyObject* args)
{
char* id;
- int mapping;
+ PyObject* meta;
PyObject* elementType;
- if(!PyArg_ParseTuple(args, STRCAST("siO"), &id, &mapping, &elementType))
+ if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &meta, &elementType))
{
return NULL;
}
+ assert(PyTuple_Check(meta));
+
+ vector<string> metaData;
+#ifndef NDEBUG
+ bool b =
+#endif
+ tupleToStringSeq(meta, metaData);
+ assert(b);
+
SequenceInfoPtr info = new SequenceInfo;
info->id = id;
- switch(mapping)
- {
- case 0:
- info->mapping = SequenceInfo::SEQ_DEFAULT;
- break;
- case 1:
- info->mapping = SequenceInfo::SEQ_TUPLE;
- break;
- case 2:
- info->mapping = SequenceInfo::SEQ_LIST;
- break;
- default:
- assert(false);
- break;
- }
+ info->mapping = new SequenceInfo::SequenceMapping(metaData);
info->elementType = getType(elementType);
return createType(info);
@@ -2642,13 +2783,16 @@ PyObject*
IcePy_defineDictionary(PyObject*, PyObject* args)
{
char* id;
+ PyObject* meta;
PyObject* keyType;
PyObject* valueType;
- if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &keyType, &valueType))
+ if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &meta, &keyType, &valueType))
{
return NULL;
}
+ assert(PyTuple_Check(meta));
+
DictionaryInfoPtr info = new DictionaryInfo;
info->id = id;
info->keyType = getType(keyType);
@@ -2745,16 +2889,18 @@ IcePy_defineClass(PyObject*, PyObject* args)
{
char* id;
PyObject* type;
+ PyObject* meta;
int isAbstract;
PyObject* base;
PyObject* interfaces;
PyObject* members;
- if(!PyArg_ParseTuple(args, STRCAST("sOiOOO"), &id, &type, &isAbstract, &base, &interfaces, &members))
+ if(!PyArg_ParseTuple(args, STRCAST("sOOiOOO"), &id, &type, &meta, &isAbstract, &base, &interfaces, &members))
{
return NULL;
}
assert(PyType_Check(type));
+ assert(PyTuple_Check(meta));
assert(PyTuple_Check(interfaces));
assert(PyTuple_Check(members));
@@ -2790,20 +2936,7 @@ IcePy_defineClass(PyObject*, PyObject* args)
info->interfaces.push_back(iface);
}
- sz = PyTuple_GET_SIZE(members);
- for(i = 0; i < sz; ++i)
- {
- PyObject* m = PyTuple_GET_ITEM(members, i);
- assert(PyTuple_Check(m));
- assert(PyTuple_GET_SIZE(m) == 2);
- PyObject* s = PyTuple_GET_ITEM(m, 0); // Member name.
- assert(PyString_Check(s));
- PyObject* t = PyTuple_GET_ITEM(m, 1); // Member type.
- DataMemberPtr member = new DataMember;
- member->name = string(PyString_AS_STRING(s), PyString_GET_SIZE(s));
- member->type = getType(t);
- info->members.push_back(member);
- }
+ convertDataMembers(members, info->members);
info->pythonType = type;
Py_INCREF(type);
@@ -2820,14 +2953,16 @@ IcePy_defineException(PyObject*, PyObject* args)
{
char* id;
PyObject* type;
+ PyObject* meta;
PyObject* base;
PyObject* members;
- if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &type, &base, &members))
+ if(!PyArg_ParseTuple(args, STRCAST("sOOOO"), &id, &type, &meta, &base, &members))
{
return NULL;
}
assert(PyClass_Check(type));
+ assert(PyTuple_Check(meta));
assert(PyTuple_Check(members));
ExceptionInfoPtr info = new ExceptionInfo;
@@ -2841,22 +2976,13 @@ IcePy_defineException(PyObject*, PyObject* args)
info->usesClasses = false;
- int sz = PyTuple_GET_SIZE(members);
- for(int i = 0; i < sz; ++i)
+ convertDataMembers(members, info->members);
+
+ for(DataMemberList::iterator p = info->members.begin(); p != info->members.end(); ++p)
{
- PyObject* m = PyTuple_GET_ITEM(members, i);
- assert(PyTuple_Check(m));
- assert(PyTuple_GET_SIZE(m) == 2);
- PyObject* s = PyTuple_GET_ITEM(m, 0); // Member name.
- assert(PyString_Check(s));
- PyObject* t = PyTuple_GET_ITEM(m, 1); // Member type.
- DataMemberPtr member = new DataMember;
- member->name = string(PyString_AS_STRING(s), PyString_GET_SIZE(s));
- member->type = getType(t);
- info->members.push_back(member);
if(!info->usesClasses)
{
- info->usesClasses = member->type->usesClasses();
+ info->usesClasses = (*p)->type->usesClasses();
}
}
diff --git a/py/modules/IcePy/Types.h b/py/modules/IcePy/Types.h
index cd1834e1b3c..c710f1f304f 100644
--- a/py/modules/IcePy/Types.h
+++ b/py/modules/IcePy/Types.h
@@ -91,8 +91,9 @@ public:
// The marshal and unmarshal functions can raise Ice exceptions, and may raise
// AbortMarshaling if an error occurs.
//
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*) = 0;
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*) = 0;
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0) = 0;
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0) = 0;
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*) = 0;
};
@@ -109,8 +110,9 @@ public:
virtual bool validate(PyObject*);
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
@@ -143,8 +145,9 @@ public:
virtual bool validate(PyObject*);
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
@@ -161,6 +164,7 @@ public:
virtual void unmarshaled(PyObject*, PyObject*, void*);
std::string name;
+ std::vector<std::string> metaData;
TypeInfoPtr type;
};
typedef IceUtil::Handle<DataMember> DataMemberPtr;
@@ -179,8 +183,9 @@ public:
virtual bool usesClasses();
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
@@ -205,28 +210,41 @@ public:
virtual bool usesClasses();
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
- virtual void unmarshaled(PyObject*, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
virtual void destroy();
- void marshalPrimitiveSequence(const PrimitiveInfoPtr&, PyObject*, const Ice::OutputStreamPtr&);
- void unmarshalPrimitiveSequence(const PrimitiveInfoPtr&, const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&,
- PyObject*, void*);
+ struct SequenceMapping : public UnmarshalCallback
+ {
+ enum Type { SEQ_DEFAULT, SEQ_TUPLE, SEQ_LIST };
+
+ SequenceMapping(Type);
+ SequenceMapping(const Ice::StringSeq&);
+
+ static bool getType(const Ice::StringSeq&, Type&);
- enum Mapping { SEQ_DEFAULT, SEQ_TUPLE, SEQ_LIST };
+ virtual void unmarshaled(PyObject*, PyObject*, void*);
+
+ PyObject* createContainer(int) const;
+ void setItem(PyObject*, int, PyObject*) const;
+
+ Type type;
+ };
+ typedef IceUtil::Handle<SequenceMapping> SequenceMappingPtr;
std::string id;
- Mapping mapping;
+ SequenceMappingPtr mapping;
TypeInfoPtr elementType;
private:
- PyObject* createContainer(int) const;
- void setItem(PyObject*, int, PyObject*) const;
+ void marshalPrimitiveSequence(const PrimitiveInfoPtr&, PyObject*, const Ice::OutputStreamPtr&);
+ void unmarshalPrimitiveSequence(const PrimitiveInfoPtr&, const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&,
+ PyObject*, void*, const SequenceMappingPtr&);
};
typedef IceUtil::Handle<SequenceInfo> SequenceInfoPtr;
@@ -243,8 +261,9 @@ public:
virtual bool usesClasses();
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void unmarshaled(PyObject*, PyObject*, void*);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
@@ -279,8 +298,9 @@ public:
virtual bool usesClasses();
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
@@ -309,8 +329,9 @@ public:
virtual bool validate(PyObject*);
- virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*);
- virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*);
+ virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0);
+ virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*,
+ const Ice::StringSeq* = 0);
virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*);
diff --git a/py/modules/IcePy/Util.cpp b/py/modules/IcePy/Util.cpp
index ee5d4660970..6330f1ee95b 100644
--- a/py/modules/IcePy/Util.cpp
+++ b/py/modules/IcePy/Util.cpp
@@ -310,20 +310,19 @@ IcePy::listToStringSeq(PyObject* l, Ice::StringSeq& seq)
{
assert(PyList_Check(l));
- int sz = PyList_Size(l);
+ int sz = PyList_GET_SIZE(l);
for(int i = 0; i < sz; ++i)
{
- PyObject* item = PyList_GetItem(l, i);
- if(item == NULL)
- {
- return false;
- }
- char* str = PyString_AsString(item);
- if(str == NULL)
- {
- return false;
- }
- seq.push_back(str);
+ PyObject* item = PyList_GET_ITEM(l, i);
+ if(item == NULL)
+ {
+ return false;
+ }
+ if(!PyString_Check(item))
+ {
+ return false;
+ }
+ seq.push_back(string(PyString_AS_STRING(item), PyString_GET_SIZE(item)));
}
return true;
@@ -355,6 +354,29 @@ IcePy::stringSeqToList(const Ice::StringSeq& seq, PyObject* l)
}
bool
+IcePy::tupleToStringSeq(PyObject* t, Ice::StringSeq& seq)
+{
+ assert(PyTuple_Check(t));
+
+ int sz = PyTuple_GET_SIZE(t);
+ for(int i = 0; i < sz; ++i)
+ {
+ PyObject* item = PyTuple_GET_ITEM(t, i);
+ if(item == NULL)
+ {
+ return false;
+ }
+ if(!PyString_Check(item))
+ {
+ return false;
+ }
+ seq.push_back(string(PyString_AS_STRING(item), PyString_GET_SIZE(item)));
+ }
+
+ return true;
+}
+
+bool
IcePy::dictionaryToContext(PyObject* dict, Ice::Context& context)
{
assert(PyDict_Check(dict));
diff --git a/py/modules/IcePy/Util.h b/py/modules/IcePy/Util.h
index fc33a8ca62f..64051b717d6 100644
--- a/py/modules/IcePy/Util.h
+++ b/py/modules/IcePy/Util.h
@@ -114,6 +114,11 @@ bool listToStringSeq(PyObject*, Ice::StringSeq&);
bool stringSeqToList(const Ice::StringSeq&, PyObject*);
//
+// Convert a tuple to Ice::StringSeq.
+//
+bool tupleToStringSeq(PyObject*, Ice::StringSeq&);
+
+//
// Convert Ice::Context to and from a Python dictionary.
//
bool dictionaryToContext(PyObject*, Ice::Context&);
diff --git a/py/python/Ice.py b/py/python/Ice.py
index 1fc0f3713f1..608fc52d177 100644
--- a/py/python/Ice.py
+++ b/py/python/Ice.py
@@ -691,16 +691,16 @@ class Application(object):
#
# Define Ice::Object and Ice::ObjectPrx.
#
-IcePy._t_Object = IcePy.defineClass('::Ice::Object', Object, False, None, (), ())
+IcePy._t_Object = IcePy.defineClass('::Ice::Object', Object, (), False, None, (), ())
IcePy._t_ObjectPrx = IcePy.defineProxy('::Ice::Object', ObjectPrx)
Object.ice_type = IcePy._t_Object
-Object._op_ice_isA = IcePy.Operation('ice_isA', OperationMode.Idempotent, OperationMode.Nonmutating, False, (IcePy._t_string,), (), IcePy._t_bool, ())
-Object._op_ice_ping = IcePy.Operation('ice_ping', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), None, ())
-Object._op_ice_ids = IcePy.Operation('ice_ids', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), _t_StringSeq, ())
-Object._op_ice_id = IcePy.Operation('ice_id', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), IcePy._t_string, ())
+Object._op_ice_isA = IcePy.Operation('ice_isA', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (((), IcePy._t_string),), (), IcePy._t_bool, ())
+Object._op_ice_ping = IcePy.Operation('ice_ping', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), (), None, ())
+Object._op_ice_ids = IcePy.Operation('ice_ids', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), (), _t_StringSeq, ())
+Object._op_ice_id = IcePy.Operation('ice_id', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), (), IcePy._t_string, ())
-IcePy._t_LocalObject = IcePy.defineClass('::Ice::LocalObject', LocalObject, False, None, (), ())
+IcePy._t_LocalObject = IcePy.defineClass('::Ice::LocalObject', LocalObject, (), False, None, (), ())
LocalObject.ice_type = IcePy._t_LocalObject
#
diff --git a/py/test/Ice/custom/AllTests.py b/py/test/Ice/custom/AllTests.py
new file mode 100644
index 00000000000..450453e2d92
--- /dev/null
+++ b/py/test/Ice/custom/AllTests.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import sys, string, re, traceback, Ice, Test
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+def allTests(communicator):
+ ref = "test:default -p 12010 -t 10000"
+ base = communicator.stringToProxy(ref)
+ test(base)
+
+ custom = Test.CustomPrx.checkedCast(base)
+ test(custom)
+
+ byteList = [1, 2, 3, 4, 5]
+ byteString = ''.join(map(chr, byteList))
+ stringList = ['s1', 's2', 's3']
+
+ print "testing custom sequences...",
+
+ (r, b2) = custom.opByteString1(byteString)
+ test(isinstance(r, str))
+ test(isinstance(b2, str))
+ test(r == byteString)
+ test(b2 == byteString)
+
+ (r, b2) = custom.opByteString2(byteString)
+ test(isinstance(r, tuple))
+ test(isinstance(b2, list))
+ for i in range(0, len(byteList)):
+ test(r[i] == byteList[i])
+ test(b2[i] == byteList[i])
+
+ (r, b2) = custom.opByteList1(byteList)
+ test(isinstance(r, list))
+ test(isinstance(b2, list))
+ for i in range(0, len(byteList)):
+ test(r[i] == byteList[i])
+ test(b2[i] == byteList[i])
+
+ (r, b2) = custom.opByteList2(byteList)
+ test(isinstance(r, str))
+ test(isinstance(b2, tuple))
+ test(r == byteString)
+ for i in range(0, len(byteList)):
+ test(b2[i] == byteList[i])
+
+ (r, b2) = custom.opStringList1(stringList)
+ test(isinstance(r, list))
+ test(isinstance(b2, list))
+ test(r == stringList)
+ test(b2 == stringList)
+
+ (r, b2) = custom.opStringList2(stringList)
+ test(isinstance(r, tuple))
+ test(isinstance(b2, tuple))
+ for i in range(0, len(stringList)):
+ test(r[i] == stringList[i])
+ test(b2[i] == stringList[i])
+
+ (r, b2) = custom.opStringTuple1(stringList)
+ test(isinstance(r, tuple))
+ test(isinstance(b2, tuple))
+ for i in range(0, len(stringList)):
+ test(r[i] == stringList[i])
+ test(b2[i] == stringList[i])
+
+ (r, b2) = custom.opStringTuple2(stringList)
+ test(isinstance(r, list))
+ test(isinstance(b2, list))
+ test(r == stringList)
+ test(b2 == stringList)
+
+ s = Test.S()
+ s.b1 = byteList;
+ s.b2 = byteList;
+ s.b3 = byteList;
+ s.b4 = byteList;
+ s.s1 = stringList;
+ s.s2 = stringList;
+ s.s3 = stringList;
+ s.s4 = stringList;
+ custom.sendS(s)
+
+ c = Test.C()
+ c.b1 = byteList;
+ c.b2 = byteList;
+ c.b3 = byteList;
+ c.b4 = byteList;
+ c.s1 = stringList;
+ c.s2 = stringList;
+ c.s3 = stringList;
+ c.s4 = stringList;
+ custom.sendC(c)
+
+ print "ok"
+
+ return custom
diff --git a/py/test/Ice/custom/Client.py b/py/test/Ice/custom/Client.py
new file mode 100644
index 00000000000..4831b78c28d
--- /dev/null
+++ b/py/test/Ice/custom/Client.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys, traceback
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "python", "Ice.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.insert(0, os.path.join(toplevel, "python"))
+sys.path.insert(0, os.path.join(toplevel, "lib"))
+
+import Ice
+Ice.loadSlice('Test.ice')
+import Test, AllTests
+
+def run(args, communicator):
+ custom = AllTests.allTests(communicator)
+ custom.shutdown()
+ return True
+
+try:
+ communicator = Ice.initialize(sys.argv)
+ status = run(sys.argv, communicator)
+except:
+ traceback.print_exc()
+ status = False
+
+if communicator:
+ try:
+ communicator.destroy()
+ except:
+ traceback.print_exc()
+ status = False
+
+sys.exit(not status)
diff --git a/py/test/Ice/custom/Server.py b/py/test/Ice/custom/Server.py
new file mode 100644
index 00000000000..9282c34333a
--- /dev/null
+++ b/py/test/Ice/custom/Server.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys, traceback
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "python", "Ice.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.insert(0, os.path.join(toplevel, "python"))
+sys.path.insert(0, os.path.join(toplevel, "lib"))
+
+import Ice
+Ice.loadSlice('Test.ice')
+import Test
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+class CustomI(Test.Custom):
+ def __init__(self, adapter):
+ self._adapter = adapter
+
+ def opByteString1(self, b1, current=None):
+ test(isinstance(b1, str))
+ return (b1, b1)
+
+ def opByteString2(self, b1, current=None):
+ test(isinstance(b1, list))
+ return (b1, b1)
+
+ def opByteList1(self, b1, current=None):
+ test(isinstance(b1, list))
+ return (b1, b1)
+
+ def opByteList2(self, b1, current=None):
+ test(isinstance(b1, tuple))
+ return (b1, b1)
+
+ def opStringList1(self, s1, current=None):
+ test(isinstance(s1, list))
+ return (s1, s1)
+
+ def opStringList2(self, s1, current=None):
+ test(isinstance(s1, tuple))
+ return (s1, s1)
+
+ def opStringTuple1(self, s1, current=None):
+ test(isinstance(s1, tuple))
+ return (s1, s1)
+
+ def opStringTuple2(self, s1, current=None):
+ test(isinstance(s1, list))
+ return (s1, s1)
+
+ def sendS(self, val, current=None):
+ test(isinstance(val.b1, str))
+ test(isinstance(val.b2, list))
+ test(isinstance(val.b3, str))
+ test(isinstance(val.b4, list))
+ test(isinstance(val.s1, list))
+ test(isinstance(val.s2, tuple))
+ test(isinstance(val.s3, tuple))
+ test(isinstance(val.s4, list))
+
+ def sendC(self, val, current=None):
+ test(isinstance(val.b1, str))
+ test(isinstance(val.b2, list))
+ test(isinstance(val.b3, str))
+ test(isinstance(val.b4, list))
+ test(isinstance(val.s1, list))
+ test(isinstance(val.s2, tuple))
+ test(isinstance(val.s3, tuple))
+ test(isinstance(val.s4, list))
+
+ def shutdown(self, current=None):
+ self._adapter.getCommunicator().shutdown()
+
+def run(args, communicator):
+ communicator.getProperties().setProperty("TestAdapter.Endpoints", "default -p 12010 -t 10000")
+ adapter = communicator.createObjectAdapter("TestAdapter")
+ object = CustomI(adapter)
+ adapter.add(object, communicator.stringToIdentity("test"))
+ adapter.activate()
+ communicator.waitForShutdown()
+ return True
+
+try:
+ communicator = Ice.initialize(sys.argv)
+ status = run(sys.argv, communicator)
+except:
+ traceback.print_exc()
+ status = False
+
+if communicator:
+ try:
+ communicator.destroy()
+ except:
+ traceback.print_exc()
+ status = False
+
+sys.exit(not status)
diff --git a/py/test/Ice/custom/Test.ice b/py/test/Ice/custom/Test.ice
new file mode 100644
index 00000000000..d142530c206
--- /dev/null
+++ b/py/test/Ice/custom/Test.ice
@@ -0,0 +1,70 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#ifndef TEST_ICE
+#define TEST_ICE
+
+module Test
+{
+ sequence<byte> ByteString; // By default, sequence<byte> is received as a string.
+ ["python:seq:list"] sequence<byte> ByteList;
+
+ sequence<string> StringList; // By default, a sequence is received as a list.
+ ["python:seq:tuple"] sequence<string> StringTuple;
+
+ struct S
+ {
+ ByteString b1;
+ ["python:seq:list"] ByteString b2;
+ ["python:seq:default"] ByteList b3;
+ ByteList b4;
+ StringList s1;
+ ["python:seq:tuple"] StringList s2;
+ StringTuple s3;
+ ["python:seq:default"] StringTuple s4;
+ };
+
+ class C
+ {
+ ByteString b1;
+ ["python:seq:list"] ByteString b2;
+ ["python:seq:default"] ByteList b3;
+ ByteList b4;
+ StringList s1;
+ ["python:seq:tuple"] StringList s2;
+ StringTuple s3;
+ ["python:seq:default"] StringTuple s4;
+ };
+
+ interface Custom
+ {
+ ByteString opByteString1(ByteString b1, out ByteString b2);
+ ["python:seq:tuple"] ByteString opByteString2(["python:seq:list"] ByteString b1,
+ out ["python:seq:list"] ByteString b2);
+
+ ByteList opByteList1(ByteList b1, out ByteList b2);
+ ["python:seq:default"] ByteList opByteList2(["python:seq:tuple"] ByteList b1,
+ out ["python:seq:tuple"] ByteList b2);
+
+ StringList opStringList1(StringList s1, out StringList s2);
+ ["python:seq:tuple"] StringList opStringList2(["python:seq:tuple"] StringList s1,
+ out ["python:seq:tuple"] StringList s2);
+
+ StringTuple opStringTuple1(StringTuple s1, out StringTuple s2);
+ ["python:seq:list"] StringTuple opStringTuple2(["python:seq:list"] StringTuple s1,
+ out ["python:seq:default"] StringTuple s2);
+
+ void sendS(S val);
+ void sendC(C val);
+
+ void shutdown();
+ };
+};
+
+#endif
diff --git a/py/test/Ice/custom/run.py b/py/test/Ice/custom/run.py
new file mode 100755
index 00000000000..1bb1ba86d1b
--- /dev/null
+++ b/py/test/Ice/custom/run.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "config", "TestUtil.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.append(os.path.join(toplevel, "config"))
+import TestUtil
+
+name = os.path.join("Ice", "custom")
+
+TestUtil.clientServerTest(name)
+sys.exit(0)
diff --git a/py/test/Ice/operations/Twoways.py b/py/test/Ice/operations/Twoways.py
index f7f784938f5..dcf925df4dc 100644
--- a/py/test/Ice/operations/Twoways.py
+++ b/py/test/Ice/operations/Twoways.py
@@ -8,7 +8,7 @@
#
# **********************************************************************
-import Ice, math, Test
+import Ice, math, Test, array
def test(b):
if not b:
@@ -147,6 +147,31 @@ def twoways(communicator, initData, p):
test(rso[7] == '\xf4')
#
+ # opByteS (array)
+ #
+ print "array",
+ bsi1 = array.array('B')
+ bsi1.fromlist([0x01, 0x11, 0x12, 0x22])
+ bsi2 = array.array('B')
+ bsi2.fromlist([0xf1, 0xf2, 0xf3, 0xf4])
+
+ rso, bso = p.opByteS(bsi1, bsi2)
+ test(len(bso) == 4)
+ test(bso[0] == '\x22')
+ test(bso[1] == '\x12')
+ test(bso[2] == '\x11')
+ test(bso[3] == '\x01')
+ test(len(rso) == 8)
+ test(rso[0] == '\x01')
+ test(rso[1] == '\x11')
+ test(rso[2] == '\x12')
+ test(rso[3] == '\x22')
+ test(rso[4] == '\xf1')
+ test(rso[5] == '\xf2')
+ test(rso[6] == '\xf3')
+ test(rso[7] == '\xf4')
+
+ #
# opBoolS
#
bsi1 = (True, True, False)
@@ -164,6 +189,25 @@ def twoways(communicator, initData, p):
test(rso[2])
#
+ # opBoolS (array)
+ #
+ bsi1 = array.array('B')
+ bsi1.fromlist([1, 1, 0])
+ bsi2 = array.array('B')
+ bsi2.fromlist([0])
+
+ rso, bso = p.opBoolS(bsi1, bsi2)
+ test(len(bso) == 4)
+ test(bso[0])
+ test(bso[1])
+ test(not bso[2])
+ test(not bso[3])
+ test(len(rso) == 3)
+ test(not rso[0])
+ test(rso[1])
+ test(rso[2])
+
+ #
# opShortIntLongS
#
ssi = (1, 2, 3)
@@ -193,6 +237,37 @@ def twoways(communicator, initData, p):
test(rso[2] == 20)
#
+ # opShortIntLongS (array)
+ #
+ ssi = array.array('h')
+ ssi.fromlist([1, 2, 3])
+ isi = array.array('i')
+ isi.fromlist([5, 6, 7, 8])
+ lsi = (10, 30, 20) # Can't store Ice::Long in an array.
+
+ rso, sso, iso, lso = p.opShortIntLongS(ssi, isi, lsi)
+ test(len(sso) == 3)
+ test(sso[0] == 1)
+ test(sso[1] == 2)
+ test(sso[2] == 3)
+ test(len(iso) == 4)
+ test(iso[0] == 8)
+ test(iso[1] == 7)
+ test(iso[2] == 6)
+ test(iso[3] == 5)
+ test(len(lso) == 6)
+ test(lso[0] == 10)
+ test(lso[1] == 30)
+ test(lso[2] == 20)
+ test(lso[3] == 10)
+ test(lso[4] == 30)
+ test(lso[5] == 20)
+ test(len(rso) == 3)
+ test(rso[0] == 10)
+ test(rso[1] == 30)
+ test(rso[2] == 20)
+
+ #
# opFloatDoubleS
#
fsi = (3.14, 1.11)
@@ -214,6 +289,29 @@ def twoways(communicator, initData, p):
test(rso[4] - 1.11 < 0.001)
#
+ # opFloatDoubleS (array)
+ #
+ fsi = array.array('f')
+ fsi.fromlist([3.14, 1.11])
+ dsi = array.array('d')
+ dsi.fromlist([1.1E10, 1.2E10, 1.3E10])
+
+ rso, fso, dso = p.opFloatDoubleS(fsi, dsi)
+ test(len(fso) == 2)
+ test(fso[0] - 3.14 < 0.001)
+ test(fso[1] - 1.11 < 0.001)
+ test(len(dso) == 3)
+ test(dso[0] == 1.3E10)
+ test(dso[1] == 1.2E10)
+ test(dso[2] == 1.1E10)
+ test(len(rso) == 5)
+ test(rso[0] == 1.1E10)
+ test(rso[1] == 1.2E10)
+ test(rso[2] == 1.3E10)
+ test(rso[3] - 3.14 < 0.001)
+ test(rso[4] - 1.11 < 0.001)
+
+ #
# opStringS
#
ssi1 = ('abc', 'de', 'fghi')