[PyKDE] Re: dcop

Jim Bublitz jbublitz at nwinternet.com
Thu May 27 18:58:00 BST 2004

On Thursday 27 May 2004 06:33, Stefan Bund wrote:
> Jim Bublitz <jbublitz at nwinternet.com> writes:
> > I haven't looked at the DCOPObject stuff very much, but it shouldn't be
> > too much of a problem (famous last words). Marshalling/demarshalling is
> > the hard part - very ugly in Python, very easy in C++.
> >
> > You can use Python strings as QByteArrays, but much beyond a single int
> > or a real char string that's pretty difficult.
> Inspired by this thread, I revisited an old pyqt application and
> implemented a simple PyDCOP module to support DCOP clients and servers
> from python in a nice and straight forward way. Till now, I have
> implemented marshaling of int's and QStrings, but other types should
> not be to hard. I think, I'll at least implement QStringList, as thats
> used quite often.

the kde-bindings source (ftp from kde.org or mirrors) has some nice code in 
the dcoppython/ directory.

> I have however a Problem in my PyDCOP.DCOPClient implementation. I get
> a "SystemError: ../Objects/classobject.c:518: bad argument to internal
> function" when calling DCOPClient::call from python:
>         (rv, replyType, replyData) = \
>              self._client.call(self._appid, self._object, id, data)
> (self._client is a dcop.DCOPClient instance ...) The call is
> successfully transfered (that is, the remote app receives and
> correctly handles the request), but probably while processing the
> return value, I get this error. This is using sip 3.10.2, pyqt 3.11
> and PyKDE 3.11rc1 (sip and pyqt installed from debian unstable
> packages).
> I don't have any clue, what this is about and would appreciate any
> pointer.

I don't know if I can help you out either. It looks like the error is being 
thrown by Python, so I'd check things like the types of rv, replyType and 
replyData, and look at how the return tuple is assembled if you're doing that 
in your own code. Is the remote app written in Python too?

I haven't run into any problems with PyKDE's 'call' method yet, but it's 
always a possibility.

> PS: It would be much nicer to just have access to the Qt QDataStream
> stream operators under python instead of re-implementing the streaming
> in pure python. It would suffice, to just map all the '<<' and
> '>>' operators to some 'read_<type>' and 'write_<type>'
> functions, I even tried that as a quick hack in an old pykde
> version. Worked flawlessly: s = QDataStream(a); i =
> s.read_int(); q = s.read_QString() ...

The way I have it setup now is:

from kdecore import dcop_add, dcop_next
from qt import *

x = 1
y = QString ("something")
ba= QByteArray ()
s = QDataStream (ba, IO_WriteOnly)
dcop_add (s, x, "int")
dcop_add (s, y)

s1 = QDataStream (ba, IO_ReadOnly)
x1 = dcop_next (s1, "int")
y1 = dcop_next (s1, "QString")

should produce x == x1 and y == y1.

dcop_add needs a type specifier for numeric types, because Python itself has 
no way to account for the possibility that on an arbitrary system, for C++ it 
may be true that:

    sizeof(char) != sizeof(short) != sizeof(int) != sizeof(long)


    sizeof(double) != sizeof(float)

If the type specifier is omitted, it assumes "int" for integer types, so 
"dcop_add (s, x)" would also work above.

There's nothing saying any of those can't occur in DCOP (or other uses of 
dcop_add).  One of the good things about the DCOP implementation is that type 
info is always easily available to the program, and parsing signatures is 
pretty simple in Python (especially if you use 
DCOPClient.normalizeFunctionSignature first), since DCOP doesn't use 
modifiers like "virtual" or "const", or default values.

dcop_add/dcop_next support about 20-25 Qt and KDE class types in addition to 
all of the basic C++ types. It's fairly simple to add others, but I've 
implemented it in C++.

I've also written a small module (based on pydcop from kde-bindings) so the 
user rarely has to worry about packing or unpacking QByteArrays anyway:

from dcopext import DCOPApp, DCOPObj
app = KApplication (...)

d = DCOPApp ("kicker", app.dcopClient ())
x = d.Panel.panelSize ()


o = DCOPObj ("kwrite", app.dcopClient (), "EditInterface#1")
o.insertLine ("Hello, world")

The application/object distinction is necessary because some DCOP object names 
(like "EditInterface#1") are not valid Python identifiers, so

d.EditInterface#1.insertLine("Hello, world")

takes everything after the # as a comment. 

The marshalling code can also convert Python strings to QString or QCString as 
needed (as in insertLine above), since it knows what the DCOP function being 
called expects.


More information about the PyQt mailing list