You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the Limited API (where PyTypeObject is opaque), there is no way to retrieve the tp_name of a type object. The PyType_GetSlot() function doesn’t define a slot ID Py_tp_name. This makes it inconvenient to port existing code to the Limited API. Is this intentional? How to work around this?
The slots are originally intended for defining types (PyType_FromSpec); PyType_GetSlot is not as useful as it could be.
tp_name can be exposed, but it needs to also be handled properly PyType_FromSpec -- e.g. raise an error.
Ah, scratch that: PyType_GetSlot returns a function pointer.
To be correct, we should to expose a new function like PyType_GetName.
It's true that CPython currently doesn't always honor the distinction between data and function pointers, but the C standard says they're distinct, so it might bite us in the future.
fancitron commented on Oct 22, 2020
fancitronmannequin
MannequinAuthor
More actions
True enough. Btw, PyType_FromSpec accepts Py_tp_doc (char *), Py_tp_base (PyTypeObject *), etc ... so to be strictly standard compliant, a union would be necessary.
PyType_GetName() sounds great.
One "proper" workaround at the moment is PyObject_GetAttrString(Py_TYPE(x), "__name__") and then process the result. This is somewhat "heavy" and strips the module name. "Py_tp_name" provides a convenient, exception safe, and backward compatible way to access tp_name.
What I actually do right now is to access the (opaque) PyTypeObject::tp_name by pointer offset. This certain defies the purpose of stable ABI!
Now that I see the implementation (and now that I'm spending a lot of time trying to formalize what is good stable API), I see a problem with PyType_GetName: it effectively returns a borrowed reference.
The proposed docs say:
Callers can hold [the retuned] pointer until the type has been deallocated.
This is not friendly to alternate Python implementations. For example, if tp_name is stored as UTF-32, it would need to generate the char* data -- and then retain it until the class is deallocated.
I guess the "correct" way would be to return a Py_buffer, which would (in CPython) reference the class.
Sorry for the delay; getting 652 into Python 3.10 took up most of my time.
So, in the current proposal:
PyType_GetName(t) is equivalent to PyObject_GetAttrString(t, "__name__")
for the qualified name you can use PyObject_GetAttrString(t, "__qualname__")
there is still no way to get t.tp_name
The advantage of PyType_GetName over a regular getattr is that it's fast for heap types (there's no dict lookup, and the string object is cached as ht_name). For static types, it's a bit slower (a string object needs to be built, but still there's no dict lookup).
If we go this way, why not add PyType_GetQualName as well?
(Is the speed, compared to getattr, worth adding two new functions? I guess it is, barely.)
----
The OP specifically requested a way to get tp_name, which the current PR does not do. I don't think it should, either:
there's no way to assure that char* tp_name is not deallocated before the caller is done with it (especially considering that other Python implementations should be able to implement the stable ABI, and those shouldn't need store tp_name as char*).
there is already name and qualname (and module); tp_name is a weird mix that I, personally, won't miss if it goes away. I think it's OK to only use it for creation (as PyType_Spec.name), and then expose the name/module derived from it. It's not how CPython works, but that's OK for the limited API.
Activity
fancitron commentedon Oct 14, 2020
In the Limited API (where PyTypeObject is opaque), there is no way to retrieve the tp_name of a type object. The PyType_GetSlot() function doesn’t define a slot ID Py_tp_name. This makes it inconvenient to port existing code to the Limited API. Is this intentional? How to work around this?
[-]PyType_GetSlot cannot get tp_name[/-][+][C API] PyType_GetSlot cannot get tp_name[/+][-]PyType_GetSlot cannot get tp_name[/-][+][C API] PyType_GetSlot cannot get tp_name[/+]encukou commentedon Oct 20, 2020
The slots are originally intended for defining types (PyType_FromSpec); PyType_GetSlot is not as useful as it could be.
tp_name can be exposed, but it needs to also be handled properly PyType_FromSpec -- e.g. raise an error.
encukou commentedon Oct 20, 2020
Ah, scratch that: PyType_GetSlot returns a function pointer.
To be correct, we should to expose a new function like PyType_GetName.
It's true that CPython currently doesn't always honor the distinction between data and function pointers, but the C standard says they're distinct, so it might bite us in the future.
fancitron commentedon Oct 22, 2020
True enough. Btw, PyType_FromSpec accepts Py_tp_doc (char *), Py_tp_base (PyTypeObject *), etc ... so to be strictly standard compliant, a union would be necessary.
PyType_GetName() sounds great.
One "proper" workaround at the moment is PyObject_GetAttrString(Py_TYPE(x), "__name__") and then process the result. This is somewhat "heavy" and strips the module name. "Py_tp_name" provides a convenient, exception safe, and backward compatible way to access tp_name.
What I actually do right now is to access the (opaque) PyTypeObject::tp_name by pointer offset. This certain defies the purpose of stable ABI!
encukou commentedon Oct 23, 2020
Yes, for some cases the ship has sailed. I don't think we can add unions now -- the stable ABI needs to be stable.
encukou commentedon Dec 15, 2020
I'll be happy to review adding a PyType_GetName function.
encukou commentedon Jan 19, 2021
Now that I see the implementation (and now that I'm spending a lot of time trying to formalize what is good stable API), I see a problem with PyType_GetName: it effectively returns a borrowed reference.
The proposed docs say:
Callers can hold [the retuned] pointer until the type has been deallocated.
This is not friendly to alternate Python implementations. For example, if tp_name is stored as UTF-32, it would need to generate the char* data -- and then retain it until the class is deallocated.
I guess the "correct" way would be to return a Py_buffer, which would (in CPython) reference the class.
Victor, what do you think?
vstinner commentedon Jan 19, 2021
New C API functions must not return borrowed references, but strong references.
vstinner commentedon Jan 19, 2021
A type has different names:
Which one should be returned by PyType_GetName()? Is there a warranty that it's always short or always qualified?
1 remaining item
shihai1991 commentedon Jan 21, 2021
Wait. petr mentioned
_PyType_Namein PR 23903 which use the short name. So I am not sure which way is better. Lol~shihai1991 commentedon Feb 1, 2021
I found
type.__name__has the implementation details in https://github.com/python/cpython/blob/master/Objects/typeobject.c#L486.IMHO, keep the consistency in
PyType_GetName()is OK.Victor, Petr. Do you think it make senses?
encukou commentedon Jul 27, 2021
Sorry for the delay; getting 652 into Python 3.10 took up most of my time.
So, in the current proposal:
PyType_GetName(t)is equivalent toPyObject_GetAttrString(t, "__name__")PyObject_GetAttrString(t, "__qualname__")The advantage of PyType_GetName over a regular getattr is that it's fast for heap types (there's no dict lookup, and the string object is cached as ht_name). For static types, it's a bit slower (a string object needs to be built, but still there's no dict lookup).
If we go this way, why not add PyType_GetQualName as well?
(Is the speed, compared to getattr, worth adding two new functions? I guess it is, barely.)
----
The OP specifically requested a way to get tp_name, which the current PR does not do. I don't think it should, either:
char* tp_nameis not deallocated before the caller is done with it (especially considering that other Python implementations should be able to implement the stable ABI, and those shouldn't need store tp_name as char*).shihai1991 commentedon Jul 27, 2021
encukou commentedon Jul 29, 2021
No, see the borrowed pointer issues above.
Great, thank you!
encukou commentedon Jul 29, 2021
New changeset a390ebe by Hai Shi in branch 'main':
bpo-42035: Add a PyType_GetName() to get type's short name. (GH-23903)
a390ebe
shihai1991 commentedon Aug 2, 2021
After PR-27551 merged, we can use PyType_GetQualName() to get type's
__qualname__.vstinner commentedon Aug 9, 2021
PyType_GetName() is a nice addition, thanks.
encukou commentedon Aug 17, 2021
New changeset 3e2c643 by Hai Shi in branch 'main':
bpo-42035: Add PyType_GetQualName() to get a type's qualified name. (GH-27551)
3e2c643
encukou commentedon Aug 17, 2021
New changeset fcd651d by Hai Shi in branch 'main':
bpo-42035: Enhance test_get_type_name() of _testcapi (GH-27649)
fcd651d
encukou commentedon Aug 17, 2021
Now, I wonder if we should also introduce PyType_GetModuleName for __module__, or stop and close this as fixed.
shihai1991 commentedon Aug 17, 2021
IMO, I suggest to close this bpo. We can get the
tp_nameby the C API now. If there have user want get__module__, we can open a new bpo to discuss :)