classification
Title: [C API] PyType_GetSlot cannot get tp_name
Type: enhancement Stage: resolved
Components: C API Versions:
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: corona10, fancitron, petr.viktorin, shihai1991, vstinner
Priority: normal Keywords: patch

Created on 2020-10-14 13:52 by fancitron, last changed 2021-08-17 15:33 by petr.viktorin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 23903 merged shihai1991, 2020-12-23 05:03
PR 27551 merged shihai1991, 2021-08-02 13:00
PR 27649 merged shihai1991, 2021-08-07 01:59
Messages (22)
msg378616 - (view) Author: (fancitron) Date: 2020-10-14 13:52
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?
msg379102 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-10-20 08:20
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.
msg379109 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-10-20 09:10
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.
msg379291 - (view) Author: (fancitron) Date: 2020-10-22 13:22
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!
msg379416 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-10-23 08:54
Yes, for some cases the ship has sailed. I don't think we can add unions now -- the stable ABI needs to be stable.
msg383070 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-12-15 15:40
I'll be happy to review adding a PyType_GetName function.
msg385274 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-01-19 16:43
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?
msg385281 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-01-19 17:34
New C API functions must not return borrowed references, but strong references.
msg385282 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-01-19 17:36
A type has different names:

* short name: "name"
* qualified name: "module.name"

Which one should be returned by PyType_GetName()? Is there a warranty that it's always short or always qualified?
msg385390 - (view) Author: Hai Shi (shihai1991) * (Python triager) Date: 2021-01-21 05:02
> New C API functions must not return borrowed references, but strong references.

Thanks petr, victor for your suggestion. It's more friendly to users.

> Which one should be returned by PyType_GetName()? Is there a warranty that it's always short or always qualified?

Returning short or qualified name depends on how to define the tp_name in PyType_Spec or type object. IMHO, PyType_GetName() return the original defined type name is fine to users.
msg385433 - (view) Author: Hai Shi (shihai1991) * (Python triager) Date: 2021-01-21 16:22
Wait. petr mentioned `_PyType_Name` in PR 23903 which use the short name. So I am not sure which way is better. Lol~
msg386080 - (view) Author: Hai Shi (shihai1991) * (Python triager) Date: 2021-02-01 16:06
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?
msg398292 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-07-27 11:44
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.
msg398311 - (view) Author: Hai Shi (shihai1991) * (Python triager) Date: 2021-07-27 17:51
> - there is still no way to get t.tp_name
  Can we create PyType_GetDataSlot function to return the data pointer?

> If we go this way, why not add PyType_GetQualName as well?
  +1. I will create another PR after PR-23903 merged.
msg398466 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-07-29 07:56
> Can we create PyType_GetDataSlot function to return the data pointer?

No, see the borrowed pointer issues above.

> I will create another PR after PR-23903 merged.

Great, thank you!
msg398468 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-07-29 07:57
New changeset a390ebea17a96d1c93fc5f75b1e19916090a4561 by Hai Shi in branch 'main':
bpo-42035: Add a PyType_GetName() to get type's short name. (GH-23903)
https://github.com/python/cpython/commit/a390ebea17a96d1c93fc5f75b1e19916090a4561
msg398766 - (view) Author: Hai Shi (shihai1991) * (Python triager) Date: 2021-08-02 13:33
> - for the qualified name you can use `PyObject_GetAttrString(t, "__qualname__")`

After PR-27551 merged, we can use PyType_GetQualName() to get type's `__qualname__`.
msg399261 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-08-09 12:30
PyType_GetName() is a nice addition, thanks.
msg399749 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-08-17 13:39
New changeset 3e2c643ae0b21f9e596bfd9c8ec99ca546ea8d0f by Hai Shi in branch 'main':
bpo-42035: Add PyType_GetQualName() to get a type's qualified name. (GH-27551)
https://github.com/python/cpython/commit/3e2c643ae0b21f9e596bfd9c8ec99ca546ea8d0f
msg399755 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-08-17 14:50
New changeset fcd651d16fc5ac3d07dd3f57f1001a861a2e7d23 by Hai Shi in branch 'main':
bpo-42035: Enhance test_get_type_name() of _testcapi (GH-27649)
https://github.com/python/cpython/commit/fcd651d16fc5ac3d07dd3f57f1001a861a2e7d23
msg399757 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-08-17 14:52
Now, I wonder if we should also introduce PyType_GetModuleName for __module__, or stop and close this as fixed.
msg399760 - (view) Author: Hai Shi (shihai1991) * (Python triager) Date: 2021-08-17 14:59
> Now, I wonder if we should also introduce PyType_GetModuleName for __module__, or stop and close this as fixed.

IMO, I suggest to close this bpo. We can get the `tp_name` by the C API now. If there have user want get `__module__`, we can open a new bpo to discuss :)
History
Date User Action Args
2021-08-17 15:33:17petr.viktorinsetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2021-08-17 14:59:23shihai1991setmessages: + msg399760
2021-08-17 14:52:23petr.viktorinsetmessages: + msg399757
2021-08-17 14:50:41petr.viktorinsetmessages: + msg399755
2021-08-17 13:39:44petr.viktorinsetmessages: + msg399749
2021-08-09 12:30:52vstinnersetmessages: + msg399261
2021-08-07 01:59:10shihai1991setpull_requests: + pull_request26143
2021-08-02 13:33:47shihai1991setmessages: + msg398766
2021-08-02 13:00:56shihai1991setpull_requests: + pull_request26057
2021-07-29 07:57:13petr.viktorinsetmessages: + msg398468
2021-07-29 07:56:49petr.viktorinsetmessages: + msg398466
2021-07-27 17:51:43shihai1991setmessages: + msg398311
2021-07-27 11:44:53petr.viktorinsetmessages: + msg398292
2021-02-01 16:06:13shihai1991setmessages: + msg386080
2021-01-21 16:22:44shihai1991setmessages: + msg385433
2021-01-21 05:02:39shihai1991setmessages: + msg385390
2021-01-19 17:36:42vstinnersetmessages: + msg385282
2021-01-19 17:34:28vstinnersetmessages: + msg385281
2021-01-19 16:43:23petr.viktorinsetmessages: + msg385274
2021-01-07 08:54:20vstinnersetnosy: + vstinner
2020-12-23 05:03:52shihai1991setkeywords: + patch
stage: patch review
pull_requests: + pull_request22757
2020-12-15 15:40:49petr.viktorinsetmessages: + msg383070
2020-11-03 14:24:54shihai1991setnosy: + shihai1991
2020-10-23 08:54:41petr.viktorinsetmessages: + msg379416
2020-10-22 13:22:12fancitronsetmessages: + msg379291
2020-10-20 09:10:50petr.viktorinsetmessages: + msg379109
2020-10-20 08:20:20petr.viktorinsetmessages: + msg379102
2020-10-14 13:55:04vstinnersetnosy: + petr.viktorin, corona10

title: PyType_GetSlot cannot get tp_name -> [C API] PyType_GetSlot cannot get tp_name
2020-10-14 13:52:05fancitroncreate