summaryrefslogtreecommitdiff
path: root/pyuno
diff options
context:
space:
mode:
authorLionel Elie Mamane <lionel@mamane.lu>2011-08-20 11:39:13 +0200
committerLionel Elie Mamane <lionel@mamane.lu>2011-08-21 01:46:07 +0200
commita9b9b40570e6cf26ac23cd49b043d8bc2e878240 (patch)
treec14d820c5dfc928e723939638ff068be266ef8a9 /pyuno
parentb796c129e296cbd6e9a2d896739441a04a962b08 (diff)
pyuno: allow uno structs to be initliased with keyword arguments
Diffstat (limited to 'pyuno')
-rw-r--r--pyuno/source/module/pyuno_module.cxx182
-rw-r--r--pyuno/source/module/uno.py37
2 files changed, 164 insertions, 55 deletions
diff --git a/pyuno/source/module/pyuno_module.cxx b/pyuno/source/module/pyuno_module.cxx
index 1bada6d10f32..973ef00c8b2e 100644
--- a/pyuno/source/module/pyuno_module.cxx
+++ b/pyuno/source/module/pyuno_module.cxx
@@ -1,4 +1,4 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; eval:(c-set-style "bsd"); tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -28,12 +28,16 @@
#include "pyuno_impl.hxx"
+#include <unordered_map>
+#include <utility>
+
#include <osl/module.hxx>
#include <osl/thread.h>
#include <osl/file.hxx>
#include <typelib/typedescription.hxx>
+#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/uuid.h>
@@ -50,6 +54,7 @@ using osl::Module;
using rtl::OString;
using rtl::OUString;
+using rtl::OUStringHash;
using rtl::OUStringToOString;
using rtl::OUStringBuffer;
using rtl::OStringBuffer;
@@ -83,35 +88,133 @@ namespace {
// dictionary of all extra keyword arguments; the keys are strings,
// which are the names that were used to identify the arguments. If
// they exist, these arguments must be the last one in the list.
-sal_Int32 fillStructWithInitializer(
+
+class fillStructState
+{
+ typedef std::unordered_map <const OUString, bool, OUStringHash> initialised_t;
+ // Keyword arguments used
+ PyObject *used;
+ // Which structure members are initialised
+ std::unordered_map <const OUString, bool, OUStringHash> initialised;
+ // How many positional arguments are consumed
+ // This is always the so-many first ones
+ sal_Int32 nPosConsumed;
+ // The total number of members set, either by a keyword argument or a positional argument
+ unsigned int nMembersSet;
+
+public:
+ fillStructState()
+ : used (PyDict_New())
+ , initialised ()
+ , nPosConsumed (0)
+ , nMembersSet (0)
+ {
+ if ( ! used )
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("pyuno._createUnoStructHelper failed to create new dictionary")), Reference< XInterface > ());
+ }
+ ~fillStructState()
+ {
+ Py_DECREF(used);
+ }
+ void setUsed(PyObject *key)
+ {
+ PyDict_SetItem(used, key, Py_True);
+ }
+ bool isUsed(PyObject *key) const
+ {
+ return Py_True == PyDict_GetItem(used, key);
+ }
+ void setInitialised(OUString key, int pos = -1)
+ {
+ if (initialised[key])
+ {
+ OUStringBuffer buf;
+ buf.appendAscii( "pyuno._createUnoStructHelper: member '");
+ buf.append(key);
+ buf.appendAscii( "'");
+ if ( pos >= 0 )
+ {
+ buf.appendAscii( " at position ");
+ buf.append(pos);
+ }
+ buf.appendAscii( " initialised multiple times.");
+ throw RuntimeException(buf.makeStringAndClear(), Reference< XInterface > ());
+ }
+ initialised[key] = true;
+ ++nMembersSet;
+ if ( pos >= 0 )
+ ++nPosConsumed;
+ }
+ bool isInitialised(OUString key)
+ {
+ return initialised[key];
+ }
+ PyObject *getUsed() const
+ {
+ return used;
+ }
+ sal_Int32 getCntConsumed() const
+ {
+ return nPosConsumed;
+ }
+ int getCntMembersSet() const
+ {
+ return nMembersSet;
+ }
+};
+
+static void fillStruct(
const Reference< XInvocation2 > &inv,
typelib_CompoundTypeDescription *pCompType,
PyObject *initializer,
+ PyObject *kwinitializer,
+ fillStructState &state,
const Runtime &runtime) throw ( RuntimeException )
{
- sal_Int32 nIndex = 0;
if( pCompType->pBaseTypeDescription )
- nIndex = fillStructWithInitializer(
- inv, pCompType->pBaseTypeDescription, initializer, runtime );
+ fillStruct( inv, pCompType->pBaseTypeDescription, initializer, kwinitializer, state, runtime );
- sal_Int32 nTupleSize = PyTuple_Size(initializer);
- int i;
- for( i = 0 ; i < pCompType->nMembers ; i ++ )
+ const sal_Int32 nMembers = pCompType->nMembers;
+ {
+ for( int i = 0 ; i < nMembers ; i ++ )
+ {
+ const OUString OUMemberName (pCompType->ppMemberNames[i]);
+ PyObject *pyMemberName = PyString_FromString(::rtl::OUStringToOString( OUMemberName, RTL_TEXTENCODING_UTF8 ).getStr());
+ if ( PyObject *element = PyDict_GetItem(kwinitializer, pyMemberName ) )
+ {
+ state.setInitialised(OUMemberName);
+ state.setUsed(pyMemberName);
+ Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY );
+ inv->setValue( OUMemberName, a );
+ }
+ }
+ }
+ {
+ const int remainingPosInitialisers = PyTuple_Size(initializer) - state.getCntConsumed();
+ for( int i = 0 ; i < remainingPosInitialisers && i < nMembers ; i ++ )
+ {
+ const int tupleIndex = state.getCntConsumed();
+ const OUString pMemberName (pCompType->ppMemberNames[i]);
+ state.setInitialised(pMemberName, tupleIndex);
+ PyObject *element = PyTuple_GetItem( initializer, tupleIndex );
+ Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY );
+ inv->setValue( pMemberName, a );
+ }
+ }
+ for ( int i = 0; i < nMembers ; ++i)
{
- // LEM TODO: and if too many? Silently ignored?
- if( i + nIndex >= nTupleSize )
+ const OUString memberName (pCompType->ppMemberNames[i]);
+ if ( ! state.isInitialised( memberName ) )
{
OUStringBuffer buf;
- buf.appendAscii( "pyuno._createUnoStructHelper: too few elements in the initializer tuple,");
- buf.appendAscii( "expected at least " ).append( nIndex + pCompType->nMembers );
- buf.appendAscii( ", got " ).append( nTupleSize );
+ buf.appendAscii( "pyuno._createUnoStructHelper: member '");
+ buf.append(memberName);
+ buf.appendAscii( "' of struct type '");
+ buf.append(pCompType->aBase.pTypeName);
+ buf.appendAscii( "' not given a value.");
throw RuntimeException(buf.makeStringAndClear(), Reference< XInterface > ());
}
- PyObject *element = PyTuple_GetItem( initializer, i + nIndex );
- Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY );
- inv->setValue( pCompType->ppMemberNames[i], a );
}
- return i+nIndex;
}
OUString getLibDir()
@@ -249,7 +352,7 @@ PyObject * extractOneStringArg( PyObject *args, char const *funcName )
return obj;
}
-static PyObject *createUnoStructHelper(PyObject *, PyObject* args )
+static PyObject *createUnoStructHelper(PyObject *, PyObject* args, PyObject* keywordArgs)
{
Any IdlStruct;
PyRef ret;
@@ -265,7 +368,7 @@ static PyObject *createUnoStructHelper(PyObject *, PyObject* args )
// in Python 2, only PyString_Check returns true.
if(PyString_Check(structName) || PyUnicode_Check(structName))
{
- if( PyTuple_Check( initializer ) )
+ if( PyTuple_Check( initializer ) && PyDict_Check ( keywordArgs ) )
{
OUString typeName( OUString::createFromAscii(PyString_AsString(structName)));
RuntimeCargo *c = runtime.getImpl()->cargo;
@@ -275,28 +378,25 @@ static PyObject *createUnoStructHelper(PyObject *, PyObject* args )
idl_class->createObject (IdlStruct);
PyUNO *me = (PyUNO*)PyUNO_new_UNCHECKED( IdlStruct, c->xInvocation );
PyRef returnCandidate( (PyObject*)me, SAL_NO_ACQUIRE );
- if( PyTuple_Size( initializer ) > 0 )
+ TypeDescription desc( typeName );
+ OSL_ASSERT( desc.is() ); // could already instantiate an XInvocation2 !
+
+ typelib_CompoundTypeDescription *pCompType =
+ ( typelib_CompoundTypeDescription * ) desc.get();
+ fillStructState state;
+ if ( PyTuple_Size( initializer ) > 0 || PyDict_Size( keywordArgs ) > 0 )
+ fillStruct( me->members->xInvocation, pCompType, initializer, keywordArgs, state, runtime );
+ if( state.getCntConsumed() != PyTuple_Size(initializer) )
{
- TypeDescription desc( typeName );
- OSL_ASSERT( desc.is() ); // could already instantiate an XInvocation2 !
-
- typelib_CompoundTypeDescription *pCompType =
- ( typelib_CompoundTypeDescription * ) desc.get();
- sal_Int32 n = fillStructWithInitializer(
- me->members->xInvocation, pCompType, initializer, runtime );
- if( n != PyTuple_Size(initializer) )
- {
- OUStringBuffer buf;
- buf.appendAscii( "pyuno._createUnoStructHelper: wrong number of ");
- buf.appendAscii( "elements in the initializer list, expected " );
- buf.append( n );
- buf.appendAscii( ", got " );
- buf.append( (sal_Int32) PyTuple_Size(initializer) );
- throw RuntimeException(
- buf.makeStringAndClear(), Reference< XInterface > ());
- }
+ OUStringBuffer buf;
+ buf.appendAscii( "pyuno._createUnoStructHelper: too many ");
+ buf.appendAscii( "elements in the initializer list, expected " );
+ buf.append( state.getCntConsumed() );
+ buf.appendAscii( ", got " );
+ buf.append( (sal_Int32) PyTuple_Size(initializer) );
+ throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > ());
}
- ret = returnCandidate;
+ ret = PyRef( PyTuple_Pack(2, returnCandidate.get(), state.getUsed()), SAL_NO_ACQUIRE);
}
else
{
@@ -321,7 +421,7 @@ static PyObject *createUnoStructHelper(PyObject *, PyObject* args )
}
else
{
- PyErr_SetString (PyExc_AttributeError, "1 Arguments: Structure Name");
+ PyErr_SetString (PyExc_AttributeError, "pyuno._createUnoStructHelper: expects exactly two non-keyword arguments:\n\tStructure Name\n\tinitialiser tuple; may be the empty tuple");
}
}
catch( com::sun::star::uno::RuntimeException & e )
@@ -702,7 +802,7 @@ static PyObject *setCurrentContext( PyObject *, PyObject * args )
struct PyMethodDef PyUNOModule_methods [] =
{
{const_cast< char * >("getComponentContext"), getComponentContext, METH_VARARGS, NULL},
- {const_cast< char * >("_createUnoStructHelper"), createUnoStructHelper, METH_VARARGS | METH_KEYWORDS, NULL},
+ {const_cast< char * >("_createUnoStructHelper"), reinterpret_cast<PyCFunction>(createUnoStructHelper), METH_VARARGS | METH_KEYWORDS, NULL},
{const_cast< char * >("getTypeByName"), getTypeByName, METH_VARARGS, NULL},
{const_cast< char * >("getConstantByName"), getConstantByName, METH_VARARGS, NULL},
{const_cast< char * >("getClass"), getClass, METH_VARARGS, NULL},
diff --git a/pyuno/source/module/uno.py b/pyuno/source/module/uno.py
index bb9720568056..99fd0f04ab3a 100644
--- a/pyuno/source/module/uno.py
+++ b/pyuno/source/module/uno.py
@@ -4,6 +4,7 @@
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# Copyright 2000, 2010 Oracle and/or its affiliates.
+# 2011 Lionel Elie Mamane <lionel@mamane.lu>
#
# OpenOffice.org - a multi-platform office productivity suite
#
@@ -56,20 +57,23 @@ def getTypeByName( typeName):
"""
return pyuno.getTypeByName( typeName )
-def createUnoStruct( typeName, *args ):
- """creates a uno struct or exception given by typeName. The parameter args may
- 1) be empty. In this case, you get a default constructed uno structure.
+def createUnoStruct( typeName, *args, **kwargs ):
+ """creates a uno struct or exception given by typeName. Can be called with:
+ 1) No additional argument.
+ In this case, you get a default constructed uno structure.
( e.g. createUnoStruct( "com.sun.star.uno.Exception" ) )
- 2) be a sequence with exactly one element, that contains an instance of typeName.
+ 2) Exactly one additional argument that is an instance of typeName.
In this case, a copy constructed instance of typeName is returned
( e.g. createUnoStruct( "com.sun.star.uno.Exception" , e ) )
- 3) be a sequence, where the length of the sequence must match the number of
- elements within typeName (e.g.
- createUnoStruct( "com.sun.star.uno.Exception", "foo error" , self) ). The
- elements with in the sequence must match the type of each struct element,
- otherwise an exception is thrown.
+ 3) As many additional arguments as the number of elements within typeName
+ (e.g. createUnoStruct( "com.sun.star.uno.Exception", "foo error" , self) ).
+ 4) Keyword arguments to give values for each element of the struct by name.
+ 5) A mix of 3) and 4), such that each struct element is given a value exactly once,
+ either by a positional argument or by a keyword argument.
+ The additional and/or keyword arguments must match the type of each struct element,
+ otherwise an exception is thrown.
"""
- return getClass(typeName)( *args )
+ return getClass(typeName)( *args, **kwargs )
def getClass( typeName ):
"""returns the class of a concrete uno exception, struct or interface
@@ -310,11 +314,16 @@ def _impl_extractName(name):
return name
# private, referenced from the pyuno shared library
-def _uno_struct__init__(self,*args):
- if len(args) == 1 and hasattr(args[0], "__class__") and args[0].__class__ == self.__class__ :
- self.__dict__["value"] = args[0]
+def _uno_struct__init__(self,*args, **kwargs):
+ if len(kwargs) == 0 and len(args) == 1 and hasattr(args[0], "__class__") and args[0].__class__ == self.__class__ :
+ self.__dict__["value"] = args[0]
else:
- self.__dict__["value"] = pyuno._createUnoStructHelper(self.__class__.__pyunostruct__,args)
+ struct, used = pyuno._createUnoStructHelper(self.__class__.__pyunostruct__,args,**kwargs)
+ for kw in kwargs.keys():
+ if not (kw in used and used[kw]):
+ RuntimeException = pyuno.getClass( "com.sun.star.uno.RuntimeException" )
+ raise RuntimeException("_uno_struct__init__: unused keyword argument '" + kw + "'", None)
+ self.__dict__["value"] = struct
# private, referenced from the pyuno shared library
def _uno_struct__getattr__(self,name):