Ticket #587 (closed enhancement: fixed)

Opened 3 years ago

Last modified 3 years ago

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) (diff)

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

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

Change History

Changed 3 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 3 years ago by vitja

first try on implementing metaclasses

Changed 3 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 3 years ago by vitja

forget test for metaclass

Changed 3 years ago by vitja

fix classmethod issue

Changed 3 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

Changed 3 years ago by vitja

Metaclasses in Py3 have a little bit different syntax:

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

Changed 3 years ago by vitja

Fix reference leak

Changed 3 years ago by scoder

  • owner changed from somebody to vitja
  • milestone changed from wishlist to 0.13.1

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 3 years ago by vitja

Really support namespace in py3 prepare

Changed 3 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().

Changed 3 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 3 years ago by vitja

Python3-style metaclass implementation

Changed 3 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 3 years ago by vitja

KeywordArgsNode? optimization and one more testcase

Changed 3 years ago by scoder

  • status changed from new to closed
  • resolution set to fixed

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.