Opened 4 years ago

Closed 4 years ago

#587 closed enhancement (fixed)

Support __metaclass__ in Python classes

Reported by: vitja Owned by: vitja
Priority: major Milestone: 0.14
Component: Python Semantics Keywords:
Cc: vitja.makarov@…

Description (last modified by scoder)

Add support for metaclasses in Python classes.

Problem: now class object is created with empty attributes dict (only __module__ is set) and then attributes are assigned via PyObject_SetItem()

To support metaclasses attributes dict should be initialized first then __metaclass__ attribute should be handled in __Pyx_CreateClass()

Attachments (7)

metaclass-try000.diff (8.1 KB) - added by vitja 4 years ago.
first try on implementing metaclasses
metaclass-001.diff (8.8 KB) - added by vitja 4 years ago.
forget test for metaclass
metaclass-002.patch (10.3 KB) - added by vitja 4 years ago.
fix classmethod issue
metaclass-py3.diff (12.9 KB) - added by vitja 4 years ago.
Fix reference leak
py3-prepare.patch (22.3 KB) - added by vitja 4 years ago.
Really support namespace in py3 prepare
py3-prepare.2.patch (22.7 KB) - added by vitja 4 years ago.
Python3-style metaclass implementation
py3-prepare.3.patch (25.1 KB) - added by vitja 4 years ago.
KeywordArgsNode? optimization and one more testcase

Download all attachments as: .zip

Change History (16)

comment:1 Changed 4 years ago by scoder

  • Component changed from Code Generation to Python Semantics
  • Description modified (diff)
  • Summary changed from Support __metaclass__ in pure python to Support __metaclass__ in Python classes

Changed 4 years ago by vitja

first try on implementing metaclasses

comment:2 Changed 4 years ago by vitja

  • Cc vitja.makarov@… added

metaclass-try000.diff

classmethods are broken, all other tests are passed.

This patch implements new behavior of new method and staticmethod now they are PyCFunction objects.

Changed 4 years ago by vitja

forget test for metaclass

Changed 4 years ago by vitja

fix classmethod issue

comment:3 Changed 4 years ago by vitja

With latest patch now works:

  • __metaclass__ (global __metaclass__ is not now handled, Python3 support not tested)
  • staticmethod as decorator
  • classmethod as decorator
  • class methods can now be decorated

comment:4 Changed 4 years ago by vitja

Metaclasses in Py3 have a little bit different syntax:

class Meta(type):
    pass
class Foo(object, metaclass=Meta):
    pass

Changed 4 years ago by vitja

Fix reference leak

comment:5 Changed 4 years ago by scoder

  • Milestone changed from wishlist to 0.13.1
  • Owner changed from somebody to vitja

Latest patch (metaclass-py3.diff) pushed here:

http://hg.cython.org/cython-devel/rev/8fddada359d5

With some cleanup here:

http://hg.cython.org/cython-devel/rev/0fb4e5f671d8
http://hg.cython.org/cython-devel/rev/e7c80035b869

The next steps are to create two new classes that represent the looked-up metaclass and the class namespace (potentially created by the 'prepare' method of the metaclass).

Changed 4 years ago by vitja

Really support namespace in py3 prepare

comment:6 Changed 4 years ago by scoder

Things I noticed:

The patch lacks tests for passing kwargs to the metaclass, and ISTM that this feature can't work.

The PyClassBasesNode class seems to be useless. Just use a plain TupleNode instead.

The KeywordArgsNode is specific enough to be named PyClassMetaclassKeywordArgsNode. I doubt that it would be used anywhere else in the future.

Utility code is best injected at code generation time using code.globalstate.use_utility_code() instead of the older (and somewhat quirky) env.use_utility_code().

comment:7 Changed 4 years ago by scoder

The error handling code in __Pyx_Py3MetaclassPrepare is very redundant. The way this is commonly handled in Cython utility functions is a "bad:" label that cleans up all local references (potentially using Py_XDECREF for NULL initialised variables) and that is simply jumped to with a "goto bad" on error.

A potential optimisation could special case this (which I consider the most common case):

    class MyType(*bases, metaclass=MyMetaclass, other=False):
        ...

i.e. only explicit keyword arguments, including the metaclass, no **kwargs. Here, no metaclass node and no metaclass lookup would be needed, and the metaclass object could be used directly. If there are no other keyword arguments, the keyword dict could even be NULL. Not sure how tricky this is to implement, though.

Changed 4 years ago by vitja

Python3-style metaclass implementation

comment:8 Changed 4 years ago by vitja

py3-prepare.2.patch

  • Actually implement py3-style metaclasses with real support for prepare and namespaces

Between py4-prepare.patch

Changed 4 years ago by vitja

KeywordArgsNode? optimization and one more testcase

comment:9 Changed 4 years ago by scoder

  • Resolution set to fixed
  • Status changed from new to closed

Pushed, followed by a couple of cleanups.

http://hg.cython.org/cython-devel/rev/75f69a3141f0

Thanks a lot!

Note: See TracTickets for help on using tickets.