GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — PyType_FromSpec refuses to create classes with tp_new · Issue #103968 · python/cpython

PyType_FromSpec refuses to create classes with tp_new #103968

New issue
Copy link
New issue
Copy link
Closed
Closed
PyType_FromSpec refuses to create classes with tp_new#103968
Copy link
Assignees
encukou
Labels
3.12only security fixesonly security fixesdeferred-blockerdocsDocumentation in the Doc dirDocumentation in the Doc dirtopic-C-APItype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@encukou
encukou
opened on Apr 28, 2023
Issue body actions

As reported in #60074, since PyType_FromMetaclass was added, other functions from the PyType_FromSpec family refuse to create classes whose metaclass has a non-default tp_new. IMO this is the correct default behaviour -- we don't have the arguments to call tp_new with, and skipping it may be dangerous.
Nevertheless, it's a backwards-incompatible change. It should only be made after a deprecation period.

I'm working on a fix.

Linked PRs

  • gh-103968: Deprecate creating heap types whose metaclass has custom tp_new. #103972
  • gh-103968: PyType_FromMetaclass: Allow metaclasses with tp_new=NULL #105386
  • [3.12] gh-103968: PyType_FromMetaclass: Allow metaclasses with tp_new=NULL (GH-105386) #105697
  • gh-103968: What's New: Add porting hints for PyType_From with metaclasses #105698
  • [3.12] gh-103968: What's New: Add porting hints for PyType_From with metaclasses (GH-105698) #106619

Activity

Next
  1. encukou
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    topic-C-API
    on Apr 28, 2023
  2. encukou
    self-assigned this
    on Apr 28, 2023
  3. encukou
    added 2 commits that reference this issue on Apr 28, 2023

    pythongh-103968: Deprecate creating heap types whose metaclass has cu…

    2ca04bb

    gh-103968: Deprecate creating heap types whose metaclass has custom t…

    524a7f7
  4. encukou commented on May 3, 2023

    @encukou
    encukou
    on May 3, 2023
    MemberAuthor
    More actions

    Deprecation period started.

    Reacted by Erlend E. Aasland
  5. encukou
    closed this as completedon May 3, 2023
  6. gpshead commented on Jun 2, 2023

    @gpshead
    gpshead
    on Jun 2, 2023
    Member
    More actions

    The 3.12 docs now say "The tp_new of the metaclass is ignored. which may result in incomplete initialization." statements, but it isn't clear if this is a part of the versionchanged in 3.12 behavior, or if this was always the case.

    Basically, we need explicit instructions on what code finding itself in the situation that protobuf protocolbuffers/protobuf#12186 finds itself in is supposed to do to reconcile the situation.

    3.12's "What's New" does not directly address this today. It just talks about tp_new being ignored as if that is a behavior change rather than if it was always ignored without being documented as such or what should be done to get the previous behavior.

    Reacted by C.A.M. Gerlach
  7. gpshead
    reopened this on Jun 2, 2023
  8. gpshead
    added
    3.12only security fixesonly security fixes
    docsDocumentation in the Doc dirDocumentation in the Doc dir
    on Jun 2, 2023
  9. gpshead commented on Jun 2, 2023

    @gpshead
    gpshead
    on Jun 2, 2023
    Member
    More actions

    Late discussion on #60074 which created the TypeError that this issue properly made into a DeprecationWarning has suggestions for a workaround but they definitely qualify as hacks. Deeper understanding of why that tp_new was set and what it's goal was and when it was ever called or not in the past is likely required.

  10. gpshead
    added
    deferred-blocker
    on Jun 2, 2023
  11. ezio-melotti
    added this to Release and Deferred blockers 🚫on Jun 2, 2023
  12. github-project-automation
    moved this to Todo in Release and Deferred blockers 🚫on Jun 2, 2023
  13. 7 remaining items

  14. haberman commented on Jun 13, 2023

    @haberman
    haberman
    on Jun 13, 2023
    More actions

    protobuf uses PyType_FromSpecWithBases to create ScalarMapContainer and MessageMapContainer, which derive from collections.abc.MutableMapping, so their metaclass is abc.ABCMeta.

    Protobuf is using MutableMapping as a mixin. The goal is that we can define only a core set of methods (__getitem__, __setitem__, etc.) and get correct implementations of all other MutableMapping methods "for free" (__contains__, keys, etc.).

    abc.ABCMeta defines __new__, meaning it overrides how ABC types should be constructed.
    This __new__ is not called on protobuf's container types, which is, IMO, a bug.

    It looks like the primary purpose of abc.ABCMeta is to add a register() method to the class, so that you can call MutableMapping.register(Foo), which will cause isinstance(Foo(), MutableMapping) to return true.

    We do not want that functionality in this case. We do not want people to be able to call ScalarMapContainer.register(Foo), because ScalarMapContainer is a concrete class, not an abstract class.

    I suspect that anyone who uses MutableMapping as a mixin is in the same boat as us. I would consider it a bug if a class becomes an ABC merely because it mixed in an ABC.

    But this seems to be what happens if you mix in an ABC in pure Python:

    from collections.abc import MutableMapping
    
    class MyMapping(MutableMapping):
        pass
    
    class OtherMapping:
        pass
    
    # This works -- MyMapping has become an ABC!
    MyMapping.register(OtherMapping)
    assert isinstance(OtherMapping(), MyMapping)

    The simplest fix would be to stop inheriting from MutableMapping. Maybe we could "manually" mix in the other methods without using inheritance:

    from collections.abc import MutableMapping
    
    class ScalarMapContainer:
        # ...
    
    MutableMapping.register(ScalarMapContainer)
    
    # Mixin the methods manually.
    ScalarMapContainer.__contains__ = MutableMapping.__contains__
    ScalarMapContainer.keys = MutableMapping.keys
    ScalarMapContainer.items = MutableMapping.items
    ScalarMapContainer.values = MutableMapping.values
    # ...
    Reacted by Gregory P. Smith and David Lechner
  15. Yhg1s commented on Jul 11, 2023

    @Yhg1s
    Yhg1s
    on Jul 11, 2023
    Member
    More actions

    Is there anything left to do here for 3.12?

  16. encukou commented on Jul 11, 2023

    @encukou
    encukou
    on Jul 11, 2023
    MemberAuthor
    More actions

    No, short of reverting the warning.

  17. encukou
    closed this as completedon Jul 11, 2023
  18. github-project-automation
    moved this from Todo to Done in Release and Deferred blockers 🚫on Jul 11, 2023
  19. encukou
    added a commit that references this issue on Jul 11, 2023

    gh-103968: What's New: Add porting hints for PyType_From with metacla…

    af5cf1e
  20. miss-islington
    added a commit that references this issue on Jul 11, 2023

    pythongh-103968: What's New: Add porting hints for PyType_From with m…

    d9b6921
  21. encukou
    added a commit that references this issue on Jul 11, 2023

    [3.12] gh-103968: What's New: Add porting hints for PyType_From with …

    2eb9fe9
  22. cdce8p commented on Aug 6, 2023

    @cdce8p
    cdce8p
    on Aug 6, 2023
    Contributor
    More actions

    Just saw the warning while testing 3.12.0b4. Is stack_level=1 correct for the DeprecationWarning
    This is my test output

    <frozen importlib._bootstrap>:400
    <frozen importlib._bootstrap>:400
      <frozen importlib._bootstrap>:400: DeprecationWarning: Using PyType_Spec with metaclasses that have custom tp_new is deprecated and will no longer be allowed in Python 3.14.
    

    After reading the discussion here, it could probably be Protobuf but no way to tell for the warning alone.

    Happy to open a new issue if this isn't the right place.

  23. gpshead commented on Aug 7, 2023

    @gpshead
    gpshead
    on Aug 7, 2023
    Member
    More actions

    After reading the discussion here, it could probably be Protobuf but no way to tell for the warning alone.

    Happy to open a new issue if this isn't the right place.

    @cdce8p - If you can reproduce this on 3.12.0rc1 please open a new issue with reproducer details (and ideally a link to the protobuf code in question).

    Reacted by Marc Mueller
  24. dlech
    added 3 commits that reference this issue on Aug 10, 2023

    no longer inherit from collections.abc

    06029d9

    no longer inherit from collections.abc

    793efbd

    no longer inherit from collections.abc

    6997690
  25. osandov commented on Nov 13, 2024

    @osandov
    osandov
    on Nov 13, 2024
    Contributor
    More actions

    Leaving a note here for others that may run into this issue with collections.abc. Another workaround is to define your desired extension class as a mixin type and then create the final type by inheriting from both your mixin type and the abstract base class. CPython's own decimal module does this:

    cpython/Modules/_decimal/_decimal.c

    Lines 6008 to 6013 in 3c99969

    /* Create SignalDict type */
    ASSIGN_PTR(state->PyDecSignalDict_Type,
    (PyTypeObject *)PyObject_CallFunction(
    (PyObject *)&PyType_Type, "s(OO){}",
    "SignalDict", state->PyDecSignalDictMixin_Type,
    MutableMapping));
    .

  26. haberman commented on Nov 18, 2024

    @haberman
    haberman
    on Nov 18, 2024
    More actions

    I can report that for Protobuf we ended up doing what I proposed above in #103968 (comment), which is to mix in the ABC without using inheritance. We explicitly register our class as a virtual subclass: protocolbuffers/protobuf#15999

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @encukou
    encukou

Labels

3.12only security fixesonly security fixesdeferred-blockerdocsDocumentation in the Doc dirDocumentation in the Doc dirtopic-C-APItype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Projects

  • Release and Deferred blockers 🚫
    Status
    Done
    Show more project fields

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.