This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Structure sub-subclass does not initialize with base class positional arguments
Type: behavior Stage:
Components: ctypes Versions: Python 3.1, Python 3.2, Python 2.7, Python 2.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: theller Nosy List: jaraco, theller
Priority: normal Keywords: patch

Created on 2009-01-24 16:04 by jaraco, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
ctypes subclassing issues.py jaraco, 2009-01-24 16:04 problem description and demo workaround script
init.c jaraco, 2009-09-17 20:09
ctypes-structinit.patch theller, 2009-09-18 08:25
Messages (6)
msg80457 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2009-01-24 16:04
When trying to create a sub-subclass of a ctypes.Structure, the behavior
is not as expected.

An executable example that describes the problem in detail and
demonstrates the issue is available at
http://paste.turbogears.org/paste/29555 and also attached.

The failing behavior is near the beginning, following the description.

Three unsuccessful workarounds follow.

The expected behavior is found at the end, where a final workaround has
been implemented.

Can this behavior be improved in subsequent releases of ctypes?  If not,
can ctypes at least support the workaround natively (perhaps by
providing a method in the Structure class that performs the workaround
and can be called by a sub-subclass during __init__)?
msg92792 - (view) Author: Thomas Heller (theller) * (Python committer) Date: 2009-09-17 19:53
The problem is the implementation of the current __init__ method, in
Modules/_ctypes/_ctypes.c, line 4024.  Rewritten in Python, and slightly
simplified it looks like this:

    def __init__(self, *args, **kw):
        """The current BUGGY __init__ method"""
        names = [f[0] for f in self._fields_]
        for n, v in zip(names, args):
            setattr(self, n, v)
        for n, v in kw.iteritems():
            setattr(self, n, v)

It assigns positional parameters to the names found in the _fields_ list
of the subclass, but it should look up all the _fields_ definitions in
all the superclasses, too.  Working pseudo Python code:

    def __init__(self, *args, **kw):
        """This is how the Structure's __init__method SHOULD be"""
        if args:
            names = []
            for tp in self.__class__.mro()[2::-1]:
                for n, _ in tp._fields_:
                    names.append(n)
            for n, v in zip(names, args):
                setattr(self, n, v)
        for n, v in kw.iteritems():
            setattr(self, n, v)

Now, I don't really want to write the above code in C ;-).
msg92793 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2009-09-17 20:00
Heh.  Me neither.

Is it possible to use something like Cython to generate the C code?
msg92794 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2009-09-17 20:09
That was easier than I thought. The generated code is _ugly_ but it did
seem to be able to generate it.

I created init.pyx

{{{
class X(object):
	def __init__(self, *args, **kw):
		"""This is how the Structure's __init__method SHOULD be"""
		if args:
			names = []
			for tp in self.__class__.mro()[2::-1]:
				for n, _ in tp._fields_:
					names.append(n)
			for n, v in zip(names, args):
				setattr(self, n, v)
		for n, v in kw.iteritems():
			setattr(self, n, v)
}}}

Then, ran cython init.pyx and got the attached file.

Is that any help?
msg92816 - (view) Author: Thomas Heller (theller) * (Python committer) Date: 2009-09-18 08:25
> Is that any help?
Not really ;-).

Here is a patch I just wrote - it must still be checked for correctness,
and tests for it must be added.  I hope the comment in the code explains
how it works.  ctypes-structinit.patch
msg92838 - (view) Author: Thomas Heller (theller) * (Python committer) Date: 2009-09-18 19:48
I've commited a slightly changed patch plus a test.

trunk: 74917, py3k: 74918, release26-maint: 74919, release31-maint: 74920.
History
Date User Action Args
2022-04-11 14:56:44adminsetgithub: 49292
2009-09-18 19:48:44thellersetstatus: open -> closed
resolution: fixed
versions: - Python 2.5
2009-09-18 19:48:24thellersetmessages: + msg92838
2009-09-18 08:25:09thellersetfiles: + ctypes-structinit.patch
keywords: + patch
messages: + msg92816
2009-09-17 20:09:06jaracosetfiles: + init.c

messages: + msg92794
2009-09-17 20:00:13jaracosetmessages: + msg92793
2009-09-17 19:53:37thellersetmessages: + msg92792
2009-09-17 19:49:03thellersetversions: + Python 3.1, Python 2.7, Python 3.2, - Python 3.0
2009-01-24 16:04:18jaracocreate