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 — [C API] Add PyType_Lookup() function · Issue #139847 · python/cpython

[C API] Add PyType_Lookup() function #139847

New issue
Copy link
New issue
Copy link
Closed
Closed
[C API] Add PyType_Lookup() function#139847
Copy link
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-C-APItype-featureA feature request or enhancementA feature request or enhancement

Description

@vstinner
vstinner
opened on Oct 9, 2025
Issue body actions

Feature or enhancement

There is a private _PyType_Lookup() function which is used by 27 projects of the PyPI top 15,000 projects:

  • Nuitka (2.7.16)
  • ansys_pythonnet-3.1.0rc6
  • casadi (3.7.2)
  • catboost (1.2.8)
  • cvxpy (1.7.2)
  • cvxpy_base (1.7.2)
  • cython (3.1.4)
  • extensionclass (6.0)
  • gamsapi (51.1.0)
  • gdal (3.11.4)
  • gevent (25.9.1)
  • htseq (2.0.9)
  • ihm (2.7)
  • m2crypto (0.45.1)
  • mecab-ko (1.0.1)
  • mecab_python3 (1.0.10)
  • msgspec (0.19.0)
  • mupdf (1.21.1.20230112.1504)
  • mypy (1.18.2)
  • pybind11 (3.0.1)
  • pycuda (2025.1.2)
  • pygdal (3.6.4.11)
  • pygraphviz (1.14)
  • python_crfsuite (0.9.11)
  • pythonnet (3.0.5)
  • sentencepiece (0.2.1)
  • yappi (1.6.10)

I propose to make the function public.

Linked PRs

  • gh-139847: Add PyType_Lookup() function #139848
Reacted by Mark Shannon

Activity

  1. vstinner
    added
    type-featureA feature request or enhancementA feature request or enhancement
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    topic-C-API
    on Oct 9, 2025
  2. vstinner
    added 2 commits that reference this issue on Oct 9, 2025

    pythongh-139847: Add PyType_Lookup() function

    fb1523b

    pythongh-139847: Add PyType_Lookup() function

    480faa6
  3. markshannon commented on Oct 10, 2025

    @markshannon
    markshannon
    on Oct 10, 2025
    Member
    More actions

    This does seem to be filling a gap in the C API.

    Reacted by msmojtabafar
  4. encukou commented on Oct 10, 2025

    @encukou
    encukou
    on Oct 10, 2025
    Member
    More actions

    To me, _PyType_Lookup sounds like a special case -- a useful special case, but it might be good to consider in together with more variations. Off the top of my head, things that you might want to enable/disable are:

    • (not) looking in the instance, direct class, superclasses, metaclass
    • (not) invoking descriptors
    • (not) binding methods with Py_TPFLAGS_METHOD_DESCRIPTOR

    Also: when we walk the MRO we should return the class the attribute is on (the defining class).

  5. encukou commented on Oct 10, 2025

    @encukou
    encukou
    on Oct 10, 2025
    Member
    More actions

    I had some notes lying around; so I collected them here: https://discuss.python.org/t/api-for-special-attribute-lookup/104288

  6. encukou commented on Oct 20, 2025

    @encukou
    encukou
    on Oct 20, 2025
    Member
    More actions

    I guess the most important thing about this lookup is not the exact behaviour (though it's important to document that), but the fact that Python uses it to find (and cache) special methods.

    Should we expose this, or _PyObject_LookupSpecial or _PyObject_LookupSpecialMethod?
    Do we know how many uses those functions have, and how many of the _PyType_Lookup users resolve descriptors after the _PyType_Lookup call?

  7. vstinner commented on Dec 3, 2025

    @vstinner
    vstinner
    on Dec 3, 2025
    MemberAuthor
    More actions

    I looked at some projects to see how _PyType_Lookup() is used.

    mypyc: C code emitted by mypyc:

    PyObject *del_str = PyUnicode_FromString("__del__");
    PyObject *del_method = (del_str == NULL) ? NULL : _PyType_Lookup(Py_TYPE(self), del_str);
    PyErr_WriteUnraisable(del_method);
    Py_XDECREF(del_method);
    Py_XDECREF(del_str);

    msgspec:

            PyObject *descr = _PyType_Lookup(type, name);
            if (descr != NULL) {
                descrgetfunc get = Py_TYPE(descr)->tp_descr_get;
                descrsetfunc set = Py_TYPE(descr)->tp_descr_set;
                if (get != NULL && set != NULL) {
                    Py_INCREF(descr);
                    val = get(descr, iter->obj, (PyObject *)type);
                    Py_DECREF(descr);
                    if (val != NULL) goto found_val;
                    PyErr_Clear();
                }
            }

    pythonnet (src/runtime/Types/MetaType.cs):

            public static int tp_setattro(BorrowedReference tp, BorrowedReference name, BorrowedReference value)
            {
                BorrowedReference descr = Runtime._PyType_Lookup(tp, name);
    
                if (descr != null)
                {
                    BorrowedReference dt = Runtime.PyObject_TYPE(descr);
    
                    if (dt == Runtime.PyWrapperDescriptorType
                        || dt == Runtime.PyMethodType
                        || typeof(ExtensionType).IsInstanceOfType(GetManagedObject(descr))
                    )
                    {
                        IntPtr fp = Util.ReadIntPtr(dt, TypeOffset.tp_descr_set);
                        if (fp != IntPtr.Zero)
                        {
                            return NativeCall.Int_Call_3(fp, descr, name, value);
                        }
                        Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only");
                        return -1;
                    }
                }
    
                int res = Runtime.PyObject_GenericSetAttr(tp, name, value);
                Runtime.PyType_Modified(tp);
    
                return res;
            }

    sentencepiece: code generated by SWIG.

    #ifdef SWIGPYTHON_BUILTIN
    SWIGRUNTIME int
    SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) {
      ...
      descr = _PyType_Lookup(tp, name);
      f = NULL;
      if (descr != NULL)
        f = descr->ob_type->tp_descr_set;
      if (!f) {
        if (PyString_Check(name)) {
          encoded_name = name;
          SWIG_Py_INCREF(name);
        } else {
          encoded_name = PyUnicode_AsUTF8String(name);
          if (!encoded_name)
            goto done;
        }
        PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name
        SWIG_Py_DECREF(encoded_name);
      } else {
        res = f(descr, obj, value);
      }

    yappi:

                    // get name from type+name
                    mo = _PyType_Lookup((PyTypeObject *)obj_type, name);
                    Py_XINCREF(mo);
                    ...
                    if (mo != NULL) {
                        pit->name = PyObject_Repr(mo);
                        Py_DECREF(mo);
                        return pit;
                    }
  8. vstinner commented on Feb 10, 2026

    @vstinner
    vstinner
    on Feb 10, 2026
    MemberAuthor
    More actions

    The C API Working Group decided to not add int PyType_Lookup(PyTypeObject *type, PyObject *name, PyObject **attr) API: capi-workgroup/decisions#83. So I close the issue. For now, the status quo is to keep the private _PyType_Lookup() function.

  9. vstinner
    closed this as completedon Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-C-APItype-featureA feature request or enhancementA feature request or enhancement

    Projects

    No projects

      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.