Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

PEP 737: gh-111696: Add type.__fully_qualified_name__ attribute#112133

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
vstinner wants to merge8 commits intopython:mainfromvstinner:type_fullyqualname

Conversation

vstinner
Copy link
Member

@vstinnervstinner commentedNov 15, 2023
edited by github-actionsbot
Loading

Add PyType_GetFullyQualName() function with documentation and tests.


📚 Documentation preview 📚:https://cpython-previews--112133.org.readthedocs.build/

@vstinner
Copy link
MemberAuthor

Existing logic to format a type name astype.__fullyqualname__ does.

I found a lot of code like:

  • name = "%s.%s" % (obj.__module__, obj.__qualname__)
  • __repr__() method:cls = self.__class__; return f"<{cls.__module__}.{cls.__qualname__} at ...}"

traceback: only code that I found which treats the__main__ module differently:

stype=self.exc_type.__qualname__smod=self.exc_type.__module__ifsmodnotin ("__main__","builtins"):ifnotisinstance(smod,str):smod="<unknown>"stype=smod+'.'+stype

_collections_abc:_type_repr() function

def_type_repr(obj):    ...ifisinstance(obj,type):ifobj.__module__=='builtins':returnobj.__qualname__returnf'{obj.__module__}.{obj.__qualname__}'    ...

inspect: omitbase_module if specified

def formatannotation(annotation, base_module=None):    ...    if isinstance(annotation, type):        if annotation.__module__ in ('builtins', base_module):            return annotation.__qualname__        return annotation.__module__+'.'+annotation.__qualname__    ...

unittest:

defstrclass(cls):return"%s.%s"% (cls.__module__,cls.__qualname__)

@vstinner
Copy link
MemberAuthor

I added a second commit using the newtype.__fullyqualname__ attribute in the stdlib to show how it can be used. Even if the attribute is not used to add new"%T" and"%#T" formats toPyUnicode_FromFormat(), this change is useful.

@@ -185,6 +185,13 @@ Type Objects

.. versionadded:: 3.11

.. c:function:: PyObject* PyType_GetFullyQualName(PyTypeObject *type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why can't it just be GetFullyQualifiedName?

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We already have aPyType_GetQualName() function which returnstype.__qualname__:https://docs.python.org/dev/c-api/type.html#c.PyType_GetQualName

I followed thePyType_GetQualName() name:PyType_GetFullyQualName() returnstype.__fullyqualname__.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I know that, but it still tickles my grammar bone. :-(

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Ok, I renamed the function toPyType_GetFullyQualifiedName().

I prefer to keep__fullyqualname__ for the attribute name. We already have__qualname__. And since it's commonly used, I prefer to make it short.

An alternative is to use FQN acronym :-D

  • type.__fqn__
  • PyType_GetFQN()

But I prefer "longer" names, so I don't need to check the doc to know what they mean ;-)

On the Internet, Domain Name Service (DNS) useFQDN: Fully Qualified Domain Name :-)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I share Guido's unease with "fullyqualname": it sounds wrong to have the abbreviated "qual" between two unabbreviated words.

For comparison:

  • Several dunders, including some of the most recently added ones, include an underscore in the word:__class_getitem__,__release_buffer__,__type_params__,__init_subclass__,__text_signature__
  • Other dunders include multiple words, often abbreviated, without underscores:__getnewargs__,__kwdefaults__,__isabstractmethod__

I would prefer__fully_qualified_name__. It's on the long side, but it matches the current name for the concept (mentioned inhttps://docs.python.org/3.12/glossary.html#term-qualified-name).__fqn__ seems too cryptic.

AlexWaygood reacted with thumbs up emoji
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I concur with Jelle.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Ok, I renamed the attribute to__fully_qualified_name__. Does it look better to you?

It's on the long side, but it matches the current name for the concept (mentioned inhttps://docs.python.org/3.12/glossary.html#term-qualified-name).fqn seems too cryptic.

I agree with you.

Add PyType_GetFullyQualifiedName() function with documentation andtests.
@gvanrossum
Copy link
Member

Naming is hard. Taking care of myself is harder. I have a lot going on at the moment and I really would prefer not to be responsible for this particular naming decision. Hopefully one or more of the other reviewers can help instead.

@encukou
Copy link
Member

IMO, this should use something more customizable than an attribute. Aformat() directive for example.

@@ -573,19 +573,19 @@ static PyObject *
test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *tp_name = PyType_GetName(&PyLong_Type);
assert(strcmp(PyUnicode_AsUTF8(tp_name), "int") == 0);
assert(PyUnicode_EqualToUTF8(tp_name, "int"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Even though it's still useful, this has nothing to do with the PR title and should go into a separate PR.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It's related, I changed the 3 tests which check the 3 C functions to get a "type name". I prefer to make the code consistent to make it easier to maintain.

This change also fix a bug: caller must check if PyUnicode_AsUTF8() is NULL. PyUnicode_EqualToUTF8() doesn't have this problem.

Lib/typing.py Outdated
if obj.__module__ == 'builtins':
return obj.__qualname__
return f'{obj.__module__}.{obj.__qualname__}'
return obj.__fullyqualname__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

You are changing the contract for the method here. This may result in breaking code relying on previous behavior.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think that you misunderstood the API of this attribute. Please check its documentation inDoc/library/stdtypes.rst, or just try my PR.

Copy link
Member

@malemburgmalemburg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Functional changes should not go into this PR.

rtn = PyUnicode_FromFormat("<class '%s'>", type->tp_name);

Py_XDECREF(mod);
PyObject *result = PyUnicode_FromFormat("<class '%U'>", name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Same comment as above: you are readding "builtins." to builtin types.

Copy link
MemberAuthor

@vstinnervstinnerNov 16, 2023
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The fully qualified name omits the module if the module is "builtins". There is no behavior change. This code has multiple tests. I'm not sure that I get your comment correctly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

As you can see from the code, the "builtins." part was deliberately omitted for builtin types.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm not sure of what you are talking about. You are commentingtype_repr() function. I didn't change the function output, it's the same:

>>> import builtins>>> print(repr(builtins.str))  # <=== HERE "builtins." is omitted<class 'str'>>>> builtins.str.__module__'builtins'>>> builtins.str.__qualname__'str'

repr() omits the module if it's "builtins". But it's added otherwise:

>>> import collections>>> print(repr(collections.OrderedDict))<class 'collections.OrderedDict'>>>> collections.OrderedDict.__module__'collections'>>> collections.OrderedDict.__qualname__'OrderedDict'

It's the same behavior than before.

@vstinner
Copy link
MemberAuthor

@gvanrossum:

Naming is hard. Taking care of myself is harder.

He he, I totally get it and it's perfectly fine. Take care.

@vstinner
Copy link
MemberAuthor

@encukou:

IMO, this should use something more customizable than an attribute. A format() directive for example.

This change is notexclusive with extendingtype.__format__() to get new formats. Moreover, if we add a format to get the fully qualified name of a type, I would prefer to have a more "regular" way to get it instead of having to go through formatting.

unittest example from this PR:

def strclass(cls): return "%s.%s" % (cls.__module__, cls.__qualname__)

is replaced with:

def strclass(cls): return cls.__fully_qualified_name__

I like the ability to get an attribute rather than having to build a f-string for that.


Adding new formats to format a type name in Python has been discussed in length. Most recent to oldest discussions:

Problems:

  • I'm not convinced that there is a strong need for formats other thantype.__name__ andtype.__fully_qualified_name__. I prefer to get an attribute easy to read and understand without having to check the documentation, rather than using a single letter format such as{type|T}
  • So far, I didn't see a clear consensus on an API for such formatting.

So my plan is now to addtype.__fully_qualified_name__ attribute, add%T (type.__name__) and%#T (type.__fully_qualified_name__) toPyUnicode_FromFormat() in C, use these new APIs, andthen see if more APIs should be added.

@encukou
Copy link
Member

Adding new formats to format a type name in Python has been discussed in length.

Yes. Did any of those discussions reach consensus on adding__fully_qualified_name__ with this implementation?

@vstinnervstinner changed the titlegh-111696: Add type.__fullyqualname__ attributegh-111696: Add type.__fully_qualified_name__ attributeNov 16, 2023
PyObject *
PyType_GetFullyQualifiedName(PyTypeObject *type)
{
return type_get_fullyqualname(type, NULL);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
returntype_get_fullyqualname(type,NULL);
returntype_fullyqualname(type,0);

No need to call the intermediate function

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I reorganized the calls. The special function withint is_repr parameter now gets a_impl suffix. The getter lostsget_ in its name to look alike type_name() and type_qualname() getters. It now calls PyType_GetFullyQualifiedName(). Does it look better to you?

@vstinnervstinner requested review froma team andvsajip ascode ownersNovember 17, 2023 21:35
@vstinner
Copy link
MemberAuthor

@JelleZijlstra: Please review the updated PR. I tried to address all comments of your latest review.

@rhettingerrhettinger removed their request for reviewNovember 23, 2023 19:44
@vstinner
Copy link
MemberAuthor

I wrotePEP 737 – Unify type name formatting for these changes: seethe PEP discussion.

AlexWaygood reacted with heart emoji

@AlexWaygood
Copy link
Member

I wrotePEP 737 – Unify type name formatting for these changes: seethe PEP discussion.

Thanks for taking the time to write a PEP. I think it's important that changes to builtin classes like this go through the PEP process :-)

@vstinnervstinner changed the titlegh-111696: Add type.__fully_qualified_name__ attributePEP 737: gh-111696: Add type.__fully_qualified_name__ attributeDec 1, 2023
@AlexWaygoodAlexWaygood removed their request for reviewDecember 13, 2023 12:52
@vstinner
Copy link
MemberAuthor

PEP 737 changed the API since this PR was created. I close this PR for now and will create a new one (or maybe reopen this PR) since PEP 737 will be approved.

@vstinnervstinner deleted the type_fullyqualname branchDecember 20, 2023 10:56
@vstinner
Copy link
MemberAuthor

The Steering Council rejected thetype.__fully_qualified_name__ attribute: seehttps://peps.python.org/pep-0737/#id1 for details. Thomas wrote: "I think the SC could be persuaded given some concrete use-cases."

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

@JelleZijlstraJelleZijlstraJelleZijlstra left review comments

@gvanrossumgvanrossumgvanrossum left review comments

@malemburgmalemburgmalemburg left review comments

@AlexWaygoodAlexWaygoodAlexWaygood left review comments

@markshannonmarkshannonAwaiting requested review from markshannonmarkshannon is a code owner

@brettcannonbrettcannonAwaiting requested review from brettcannonbrettcannon is a code owner

@ericsnowcurrentlyericsnowcurrentlyAwaiting requested review from ericsnowcurrentlyericsnowcurrently is a code owner

@ncoghlanncoghlanAwaiting requested review from ncoghlanncoghlan is a code owner

@warsawwarsawAwaiting requested review from warsawwarsaw is a code owner

@iritkatrieliritkatrielAwaiting requested review from iritkatriel

@1st11st1Awaiting requested review from 1st11st1 is a code owner

@vsajipvsajipAwaiting requested review from vsajipvsajip is a code owner

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

6 participants
@vstinner@gvanrossum@encukou@AlexWaygood@JelleZijlstra@malemburg

[8]ページ先頭

©2009-2025 Movatter.jp