Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyType_FromSpec should take metaclass as an argument #60074

Closed
abalkin opened this issue Sep 6, 2012 · 65 comments
Closed

PyType_FromSpec should take metaclass as an argument #60074

abalkin opened this issue Sep 6, 2012 · 65 comments
Assignees
Labels
3.11 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement

Comments

@abalkin
Copy link
Member

abalkin commented Sep 6, 2012

BPO 15870
Nosy @loewis, @jcea, @amauryfa, @abalkin, @pitrou, @encukou, @lekma, @mattip, @zooba, @seberg, @ctismer
Files
  • typeobject.diff
  • typeobject.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/abalkin'
    closed_at = None
    created_at = <Date 2012-09-06.15:49:25.705>
    labels = ['interpreter-core', 'type-feature', '3.11']
    title = 'PyType_FromSpec should take metaclass as an argument'
    updated_at = <Date 2021-10-12.13:28:38.470>
    user = 'https://github.com/abalkin'

    bugs.python.org fields:

    activity = <Date 2021-10-12.13:28:38.470>
    actor = 'petr.viktorin'
    assignee = 'belopolsky'
    closed = False
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2012-09-06.15:49:25.705>
    creator = 'belopolsky'
    dependencies = []
    files = ['27137', '50285']
    hgrepos = []
    issue_num = 15870
    keywords = ['patch', 'needs review']
    message_count = 40.0
    messages = ['169925', '169928', '169929', '169940', '169942', '169943', '169944', '169951', '169955', '169972', '169977', '398430', '398435', '398751', '398776', '401642', '401651', '401781', '402105', '402511', '402517', '402520', '402521', '402522', '402527', '402551', '402729', '402733', '402734', '402735', '402737', '402738', '402751', '402753', '402793', '402800', '402806', '403231', '403257', '403730']
    nosy_count = 16.0
    nosy_names = ['loewis', 'jcea', 'amaury.forgeotdarc', 'belopolsky', 'pitrou', 'Arfrever', 'petr.viktorin', 'lekma', 'Alexander.Belopolsky', 'mattip', 'Robin.Schreiber', 'steve.dower', 'seberg', 'Christian.Tismer', 'jhaberman', 'haberman2']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue15870'
    versions = ['Python 3.11']

    @abalkin
    Copy link
    Member Author

    abalkin commented Sep 6, 2012

    PyType_FromSpec() is a convenient function to create types dynamically in C extension modules, but its usefulness is limited by the fact that it creates new types using the default metaclass.

    I suggest adding a new C API function

    PyObject *PyType_FromSpecEx(PyObject *meta, PyType_Spec *spec)

    and redefine PyType_FromSpec() as

    PyType_FromSpecEx((PyObject *)&PyType_Type, spec)

    This functionality cannot be implemented by user because PyType_FromSpec requires access to private slotoffsets table.

    A (trivial) patch attached.

    @abalkin abalkin added the type-feature A feature request or enhancement label Sep 6, 2012
    @abalkin abalkin self-assigned this Sep 6, 2012
    @abalkin abalkin added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Sep 6, 2012
    @amauryfa
    Copy link
    Member

    amauryfa commented Sep 6, 2012

    The patch is a bit light: see how type_new also computes the metaclass from the base classes.

    @AlexanderBelopolsky
    Copy link
    Mannequin

    AlexanderBelopolsky mannequin commented Sep 6, 2012

    On Thu, Sep 6, 2012 at 12:44 PM, Amaury Forgeot d'Arc
    <report@bugs.python.org> wrote:

    The patch is a bit light: see how type_new also computes the metaclass from the base classes.

    This was intentional. I was looking for a lightweight facility to
    create heap types. I know metaclass when I call PyType_FromSpec. If
    i wanted to invoke the "metaclass from the base classes" logic, I
    would just specify an appropriate base class in the spec. This would
    still leave an open problem of specifying the metatype for the most
    basic class. This is the problem I am trying to solve.

    @abalkin
    Copy link
    Member Author

    abalkin commented Sep 6, 2012

    see how type_new also computes the metaclass from the base classes.

    As you can see from my first message, I originally considered PyType_FromSpecEx(PyObject *meta, PyType_Spec *spec) without bases. (In fact I was unaware of the recent addition of PyType_FromSpecWithBases.) Maybe the original signature makes more sense than the one in the patch. Explicitly setting a metaclass is most useful for the most basic type. On the other hand, a fully general function may eventually replace both PyType_FromSpec and PyType_FromSpecWithBases for most uses.

    @loewis
    Copy link
    Mannequin

    loewis mannequin commented Sep 6, 2012

    What is your use case for this API?

    @AlexanderBelopolsky
    Copy link
    Mannequin

    AlexanderBelopolsky mannequin commented Sep 6, 2012

    On Sep 6, 2012, at 5:10 PM, Martin v. Löwis <report@bugs.python.org> wrote:

    What is your use case for this API?

    I can describe my use case, but it is somewhat similar to ctypes. I searched the tracker for a PEP-3121 refactoring applied to ctypes and could not find any. I'll try to come up with a PEP-3121 patch for ctypes using the proposed API.

    @loewis
    Copy link
    Mannequin

    loewis mannequin commented Sep 6, 2012

    If it's very special, I'm -0 on this addition. This sounds like this is something very few people would ever need, and they can learn to write more complicated code to achieve the same effect. Convenience API exists to make the common case convenient.

    I'm -1 on calling it PyType_FromSpecEx.

    @AlexanderBelopolsky
    Copy link
    Mannequin

    AlexanderBelopolsky mannequin commented Sep 6, 2012

    On Sep 6, 2012, at 6:25 PM, Martin v. Löwis <report@bugs.python.org> wrote:

    I'm -1 on calling it PyType_FromSpecEx.

    I find it encouraging that you commented on the choice of name. :-) I can live with PyType_FromMetatypeAndSpec and leave out bases. PyType_FromTypeAndSpec is fine too.

    On the substance, I don't think this API is just convenience. In my application I have to replace meta type after my type is created with PyType_FromSpec. This is fragile and works only for very simple metatypes.

    Let's get back to this discussion once I have a ctypes patch. I there will be a work-around for ctypes it will probably work for my case. (My case is a little bit more complicated because I extend the size of my type objects to store custom metadata. Ctypes fudge this issue by hiding extra data in a custom tp_dict. )

    @pitrou
    Copy link
    Member

    pitrou commented Sep 6, 2012

    This API may make it easier to declare ABCs in C.

    @loewis
    Copy link
    Mannequin

    loewis mannequin commented Sep 7, 2012

    As for declaring ABCs: I don't think the API is necessary, or even helps. An ABC is best created by *calling* ABCMeta, with the appropriate name, a possibly-empty bases tuple, and a dict. What FromSpec could do is to fill out slots with custom functions, which won't be necessary or desirable for ABCs. The really tedious part may be to put all the abstract methods into the ABC, for which having a TypeSpec doesn't help at all. (But I would certainly agree that simplifying creation of ABCs in extension modules is a worthwhile reason for an API addition)

    For the case that Alexander apparently envisions, i.e. metaclasses where the resulting type objects extend the layout of heap types: it should be possible for an extension module to fill out the entire type "from scratch". This will require knowledge of the layout of heap types, so it can't use just the stable ABI - however, doing this through the stable ABI won't be possible, anyway, since the extended layout needs to know how large a HeapType structure is.

    If filling out a type with all slots one-by-one is considered too tedious, and patching ob_type too hacky - here is another approach: Use FromSpec to create a type with all slots filled out, then call the metatype to create a subtype of that. I.e. the type which is based on a metatype would actually be a derived class of the type which has the slots defined.

    @pitrou
    Copy link
    Member

    pitrou commented Sep 7, 2012

    If filling out a type with all slots one-by-one is considered too
    tedious, and patching ob_type too hacky - here is another approach:
    Use FromSpec to create a type with all slots filled out, then call the
    metatype to create a subtype of that. I.e. the type which is based on
    a metatype would actually be a derived class of the type which has the
    slots defined.

    As a matter of fact, this is what the io module is doing (except that
    the derived type is written in Python). It does feel like pointless
    complication, though.

    @abalkin abalkin closed this as completed Jun 29, 2014
    @jhaberman
    Copy link
    Mannequin

    jhaberman mannequin commented Jul 28, 2021

    I know this is quite an old bug that was closed almost 10 years ago. But I am wishing this had been accepted; it would have been quite useful for my case.

    I'm working on a new iteration of the protobuf extension for Python. At runtime we create types dynamically, one for each message defined in a .proto file, eg. from "message Foo" we dynamically construct a "class Foo".

    I need to support class variables like Foo.BAR_FIELD_NUMBER, but I don't want to put all these class variables into tp_dict because there are a lot of them and they are rarely used. So I want to implement __getattr__ for the class, which requires having a metaclass. This is where the proposed PyType_FromSpecEx() would have come in very handy.

    The existing protobuf extension gets around this by directly calling PyType_Type.tp_new() to create a type with a given metaclass:

    https://github.com/protocolbuffers/protobuf/blob/53365065d9b8549a5c7b7ef1e7e0fd22926dbd07/python/google/protobuf/pyext/message.cc#L278-L279

    It's unclear to me if PyType_Type.tp_new() is intended to be a supported/public API. But in any case, it's not available in the limited API, and I am trying to restrict myself to the limited API. (I also can't use PyType_GetSlot(PyType_Type, Py_tp_new) because PyType_Type is not a heap type.)

    Put more succinctly, I do not see any way to use a metaclass from the limited C API.

    Possible solutions I see:

    1. Add PyType_FromSpecEx() (or similar with a better name) to allow a metaclass to be specified. But I want to support back to at least Python 3.6, so even if this were merged today it wouldn't be viable for a while.

    2. Use eval from C to create the class with a metaclass, eg.
      class Foo(metaclass=MessageMeta)

    3. Manually set FooType->ob_type = &MetaType, as recommended here: https://stackoverflow.com/a/52957978/77070 . Since PyObject.ob_type is part of the limited API, I think this might be possible!

    @abalkin
    Copy link
    Member Author

    abalkin commented Jul 28, 2021

    I'll reopen this issue to resume the discussion. The motivating case - PEP-3121 refactoring of the ctypes module - is still open. See bpo-15884.

    @abalkin abalkin added the 3.11 only security fixes label Jul 28, 2021
    @abalkin abalkin reopened this Jul 28, 2021
    @encukou
    Copy link
    Member

    encukou commented Aug 2, 2021

    1. Use eval from C to create the class with a metaclass, eg.
      class Foo(metaclass=MessageMeta)

    You can also call (PyObject_Call*) the metaclass with (name, bases, namespace); this should produce a class. Or not:

        >>> class Foo(metaclass=print):
        ...     def foo(self): pass
        ... 
        Foo () {'__module__': '__main__', '__qualname__': 'Foo', 'foo': <function Foo.foo at 0x7f6e9ddd9e50>}

    PyType_FromSpecEx will surely need to limit the metaclass to subtypes of type. What other limitations are there? How closely can we approach the behavior of the class statement in Python?

    1. Manually set FooType->ob_type = &MetaType

    I wouldn't recommend doing that after PyType_Ready is called. Including indirectly, which the type-creation functions in the stable ABI do.

    @jhaberman
    Copy link
    Mannequin

    jhaberman mannequin commented Aug 2, 2021

    You can also call (PyObject_Call*) the metaclass with (name, bases, namespace);

    But won't that just call my metaclass's tp_new? I'm trying to do this from my metaclass's tp_new, so I can customize the class creation process. Then Python code can use my metaclass to construct classes normally.

    I wouldn't recommend [setting ob_type] after PyType_Ready is called.

    Why not? What bad things will happen? It seems to be working so far.

    Setting ob_type directly actually solves another problem that I had been having with the limited API. I want to implement tp_getattro on the metaclass, but I want to first delegate to PyType.tp_getattro to return any entry that may be present in the type's tp_dict. With the full API I could call self->ob_type->tp_base->tp_getattro() do to the equivalent of super(), but with the limited API I can't access type->tp_getattro (and PyType_GetSlot() can't be used on non-heap types).

    I find that this does what I want:

      PyTypeObject *saved_type = self->ob_type;
      self->ob_type = &PyType_Type;
      PyObject *ret = PyObject_GetAttr(self, name);
      self->ob_type = saved_type;

    Previously I had tried:

       PyObject *super = PyObject_CallFunction((PyObject *)&PySuper_Type, "OO",
                                               self->ob_type, self);
       PyObject *ret = PyObject_GetAttr(super, name);
       Py_DECREF(super);

    But for some reason this didn't work.

    @mattip
    Copy link
    Contributor

    mattip commented Sep 11, 2021

    > I wouldn't recommend [setting ob_type] after PyType_Ready is called.

    Why not? What bad things will happen? It seems to be working so far.

    It breaks the unwritten contract that "once PyType_Ready is called, the C struct will not be modified". This is implemented in PyPy, since calling PyType_Ready creates the PyPy object in the interpreter based on the C structure. Any further changes will not be reflected in the PyPy interpreter object, so now the python-level and c-level objects do not agree what type(obj) is.

    We have discussed this in the PyPy team, and would like to propose relaxing the contract to state that "if the c-level contents of an object are modified, PyType_Modified must be called to re-synce the python level and c-level objects"

    @ctismer
    Copy link
    Contributor

    ctismer commented Sep 11, 2021

    Since PyPy does not use the Limited API, PySide can quite easily work around the limitations by directly working with the type object.

    But the usage of PyType_Modified() would make very much sense for PySide‘s new switchable features. That would work immediately without any change, because we already use that function to invalidate Python 3.10‘s type cache.

    @haberman2
    Copy link
    Mannequin

    haberman2 mannequin commented Sep 14, 2021

    I found a way to use metaclasses with the limited API.

    I found that I can access PyType_Type.tp_new by creating a heap type derived from PyType_Type:

    static PyType_Slot dummy_slots[] = {
    {0, NULL}
    };

    static PyType_Spec dummy_spec = {
    "module.DummyClass", 0, 0, Py_TPFLAGS_DEFAULT, dummy_slots,
    };

      PyObject *bases = Py_BuildValue("(O)", &PyType_Type);
      PyObject *type = PyType_FromSpecWithBases(&dummy_spec, bases);
      Py_DECREF(bases);
    
      type_new = PyType_GetSlot((PyTypeObject*)type, Py_tp_new);
      Py_DECREF(type);
    
      #ifndef Py_LIMITED_API
        assert(type_new == PyType_Type.tp_new);
      #endif
    
      // Creates a type using a metaclass.
      PyObject *uses_metaclass = type_new(metaclass, args, NULL);

    PyType_GetSlot() can't be used on PyType_Type directly, since it is not a heap type. But a heap type derived from PyType_Type will inherit tp_new, and we can call PyType_GetSlot() on that.

    Once we have PyType_Type.tp_new, we can use it to create a new type using a metaclass. This avoids any of the class-switching tricks I was trying before. We can also get other slots of PyType_Type like tp_getattro to do the equivalent of super().

    The PyType_FromSpecEx() function proposed in this bug would still be a nicer solution to my problem. Calling type_new() doesn't let you specify object size or slots. To work around this, I derive from a type I created with PyType_FromSpec(), relying on the fact that the size and slots will be inherited. This works, but it introduces an extra class into the hierarchy that ideally could be avoided.

    But I do have a workaround that appears to work, and avoids the problems associated with setting ob_type directly (like PyPy incompatibility).

    @stephaniegilbert944 stephaniegilbert944 mannequin added build The build process and cross-build stdlib Python modules in the Lib dir docs Documentation in the Doc dir extension-modules C modules in the Modules dir topic-IDLE topic-installation labels Sep 15, 2021
    wjakob added a commit to wjakob/cpython that referenced this issue May 24, 2022
    Added a new stable API function ``PyType_FromMetaclass``, which mirrors
    the behavior of ``PyType_FromModuleAndSpec`` except that it takes an
    additional metaclass argument. This is, e.g., useful for language
    binding tools that need to store additional information in the type
    object.
    encukou pushed a commit that referenced this issue May 27, 2022
    Added a new stable API function ``PyType_FromMetaclass``, which mirrors
    the behavior of ``PyType_FromModuleAndSpec`` except that it takes an
    additional metaclass argument. This is, e.g., useful for language
    binding tools that need to store additional information in the type
    object.
    @erlend-aasland
    Copy link
    Contributor

    erlend-aasland commented Jun 7, 2022

    I think we can close this now that #93012 landed. @encukou?

    @erlend-aasland erlend-aasland added the pending The issue will be closed if no feedback is provided label Jun 7, 2022
    @encukou
    Copy link
    Member

    encukou commented Jun 8, 2022

    Yes, with a note that #89546 follows up on this.
    Thanks for the ping!

    @encukou encukou closed this as completed Jun 8, 2022
    @AA-Turner AA-Turner removed the pending The issue will be closed if no feedback is provided label Jun 9, 2022
    @ctismer
    Copy link
    Contributor

    ctismer commented Feb 14, 2023

    Hi @wjakob I am contacting you as a PySide developer:

    Since I tried Python 3.12.0a4 on PySide6 today, we can no longer build PySide.
    Reason: The Message

    Metaclasses with custom tp_new are not supported.

    We use the PyType_FromSpec function extensively in PySide to pass our own tp_new function to the metaclass.
    Why is this no longer supported?
    Is there maybe an easy workaround?

    All the best -- Chris

    @mattip
    Copy link
    Contributor

    mattip commented Feb 14, 2023

    @ctismer I think you should be using PyType_FromMetaclass on 3.12

    @mattip
    Copy link
    Contributor

    mattip commented Feb 14, 2023

    here is the work-around in nanobind for versions before 3.12

    @ctismer
    Copy link
    Contributor

    ctismer commented Feb 14, 2023

    @mattip Versions before 3.12 are no problem. And whatever I do gets redirected to PyType_FromMetaclass in 3.12, which then forbids tp_new.
    I was never stuck, but now I am. Why is tp_new changing not allowed?

    @seberg
    Copy link
    Contributor

    seberg commented Feb 14, 2023

    There was more discussion on the newer PR I think, but also here: gh-89546. The issue is that the super().__new__() cannot be called and Petr at that time suggested a second function may be necessary, but I think later it was thought/hoped that just wouldn't be needed.

    @ctismer
    Copy link
    Contributor

    ctismer commented Feb 15, 2023

    @seberg Thanks a lot, now I understand the problem better. And as I read all the discussions, the tp_new problem was not solved in the end, although there was a plan.

    On first glance I was happy that this hackery around PyType_* would come to an end, but with the redirections leading always into PyType_FromMetaclass, there is effectively a new restriction that was not present before.
    I need to test if some hacking aftter the fact can work around that.

    @encukou
    Copy link
    Member

    encukou commented Feb 15, 2023

    If there is a tp_new, what should PyType_FromMetaclass (or any type creation function that doesn't take *args, **kwargs) do?

    @ctismer
    Copy link
    Contributor

    ctismer commented Feb 15, 2023

    It should simply do nothing but accept it as-is.

    Before the new function existed, we supplied the metatype after type crestion.
    That should simply work as before. We do not supply the metatype to PyType_From*, but some helper function now grabs the likely metatype from the bases, adds it and then complains about our tp_ new.
    We don‘t have a chance to patch it ourselves any more.
    I don‘t complain about the new function, this may be ok for the use cases. But it should not be greedy and leave my patching alone. This is not an addition to the API but it removes functionality without replacement.

    @seberg
    Copy link
    Contributor

    seberg commented Feb 15, 2023

    Before the new function existed PySide worked by pure luck because Python always allocated one slot extra which happened to be enough for its use-case. (It worked for PySide, but not really anyone else, took me weeks to fully understand probably at the time.)

    In NumPy I currently also have a tp_new, all it does is reject creation, though. IIRC there was a point that it should be OK to do without/remove (I don't remember the actual point, but trusted it at the time). (NumPy's hacks are deep enough they should keep working in 3.12 for the time being.)

    So, I agree we need to find a solution. But we should also ask the question if you actually need the tp_new, and whether the right approach is not to allow it but to add a way to write a "C new" function for metaclasses.

    @encukou
    Copy link
    Member

    encukou commented Feb 15, 2023

    It should simply do nothing but accept it as-is.

    That means it would create an object without calling its C-level initialization function. That sounds pretty dangerous -- most tp_new set up some invariant you should then be able to rely on.
    I don't understand the use case here. Why do you have a tp_new that should not be called at instance creation?

    add a way to write a "C new" function for metaclasses

    But does that “C new” need to be a slot? It probably needs a custom signature -- if you can fit in *args, **kwargs you should be able to use tp_new, and call the metatype to create subclasses. And if that's the case, there's not much point in letting Python or other extensions know about it -- it can just be a C function you export.

    @seberg
    Copy link
    Contributor

    seberg commented Feb 15, 2023

    But does that “C new” need to be a slot?

    No, of course not. In the old issue you had brought up a PyType_ApplySpec as a raw interface to creating a new class instance. Having such a function would then allow me in NumPy for example to have a C-API function:

    DTypeMeta
    PyArray_CreateNewDTypeFromSpec(DTypeMeta_Spec *spec)
    {
        newtype = alloc_metatype();
        PyType_ApplySpec(newtype, some_spec);
        /* Do more initialization stuff */
        return newtype;
    }
    

    Now, I am not convinced we need this, because all I currently need in NumPy is rejecting creation in Python. And if I would want more, I would just create a factory function anyway, probably:

    @create_dtype
    class SomeClass:
        ...
    

    which is more than enough probably.

    @encukou
    Copy link
    Member

    encukou commented Feb 15, 2023

    all I currently need in NumPy is rejecting creation in Python

    Is doing that in tp_init not enough?
    I guess there is a way to bypass tp_init from Python...

    In the old issue you had brought up a PyType_ApplySpec as a raw interface to creating a new class instance.

    A good first step would be PyType_SetSlot, initially with a small subset of settable slots (for some slots, setting them after creation is tricky). (BTW, that would bring us closer to Mark's sketch of a perfect API, while keeping current C signatures.)

    @ctismer
    Copy link
    Contributor

    ctismer commented Feb 15, 2023

    @seberg

    So, I agree we need to find a solution. But we should also ask the question if you actually need the tp_new, and whether the right approach is not to allow it but to add a way to write a "C new" function for metaclasses.

    PySide has a meta type Shiboken.ObjectType which is used in all PySide classes.
    When a wrapper type is initialized, its type is created this way.
    This code existed long before my time in PySide1. When I moved to Qt5 (2015) and then limited API (2017),
    the trouble began. 😉

    Basically, we add some extra attributes to the meta type. But in 2021, supporting PyPy forced me to
    put these extras into a shadow structure, anyway. So it might be possible to add them later when the type
    creation is over. I'm currently investigating that.

    This is done. The much simpler solution is below:

    @ctismer
    Copy link
    Contributor

    ctismer commented Feb 15, 2023

    @seberg I have a crude fix:
    Before calling PyType_FromSpecWithBases or PyType_FromMetaclass, I patch an eventually
    existing tp_new away and restore it right afterwards. This gives the same behavior as before.
    It does not hurt (but the brain) , because only the type slot is temporarily changed, but the __new__
    function is still in the already initialized meta type.

    As soon as a proper "C new" function is available, I will remove that hack. But it serves me well,
    for heaven's sake. You could do the same BTW. to your NumPy tp_new.

    Hoping for a wise decision on this weird issue 😄

    So long -- Chris

    @encukou
    Copy link
    Member

    encukou commented Mar 22, 2023

    Sorry for dropping the ball here.

    The behavior change is backwards incompatible. If refusing to create classes with __new__ is better than silently skipping it (as I think it is), there should at least be a deprecation warning period, at least in the pre-existing functions.
    I'll do that for 3.12.

    I assume this won't really help you since PySide will want to avoid deprecation warnings, though...
    As hacky as it is, patching tp_new away at least says I don't want tp_new called and I know what I'm doing explicitly.

    @ctismer
    Copy link
    Contributor

    ctismer commented Apr 27, 2023

    @encukou Whatever the outcome, it's fine with me. The most important thing is a stable status that will not change for the time being.
    All the best -- Chris

    @encukou
    Copy link
    Member

    encukou commented Jun 5, 2023

    More discussion is in #103968.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.11 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests