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

types.MappingProxyType.__qualname__ isn't correct #106165

Closed
jamesbraza opened this issue Jun 28, 2023 · 4 comments
Closed

types.MappingProxyType.__qualname__ isn't correct #106165

jamesbraza opened this issue Jun 28, 2023 · 4 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@jamesbraza
Copy link

Bug report

from types import MappingProxyType

# This assertion fails because the qualname is just 'mappingproxy'
assert MappingProxyType.__qualname__ == "types.MappingProxyType"

Your environment

  • CPython versions tested on: 3.10.9
  • Operating system and architecture: macOS Monterey version 12.6
@jamesbraza jamesbraza added the type-bug An unexpected behavior, bug, or error label Jun 28, 2023
@JelleZijlstra
Copy link
Member

First, you have the wrong expectation about __qualname__. The "qualified" part means that it includes the name of outer classes or functions; it does not include the module name. You can see this with other Python classes defined in the standard library:

>>> import types
>>> types.DynamicClassAttribute.__qualname__
'DynamicClassAttribute'

The difference between __name__ and __qualname__ shows up if an object is nested within another, such as with a method, where the qualname includes the class:

>>> types.DynamicClassAttribute.getter.__qualname__
'DynamicClassAttribute.getter'

The module is stored only in the __module__ attribute, so to get a fully qualified name you generally need to combine .__module__ and .__qualname__.

But that doesn't answer the second part of your complaint, which is that types.MappingProxyType claims that its __qualname__ is mappingproxy, not MappingProxyType. Similarly, its __module__ is builtins, not types. This is probably for historical reasons: the type was created before it was exposed in the types module, and it was mostly conceived as an internal helper.

However, more recently added objects in the types module do take care that their __module__ and __name__ match their public location:

>>> types.UnionType.__module__
'types'
>>> types.UnionType.__qualname__
'UnionType'

It would be nice for consistency if other types that are currently in the types module were changed to make their name/module/qualname consistent with their location too, but there may be some compatibility concerns.

This affects several other types, not just MappingProxyType:

>>> types.FunctionType.__module__
'builtins'
>>> types.FunctionType.__qualname__
'function'
>>> types.ModuleType.__qualname__
'module'

@jamesbraza
Copy link
Author

Yes, sorry for the half-sloppy original post, seems like you've understood what I was getting at though.

On my end, I am doing deserialization like this:

def extract_fully_qualified_name(cls: type) -> str:
    if cls.__module__ == "builtins":
        return cls.__qualname__
    return f"{cls.__module__}.{cls.__qualname__}"

And MappingProxyType being one off-y in two regards is causing issues:

  • Reports itself from builtins and not types
  • Doesn't report its __qualname__ as MappingProxyType

I agree with your opinion on fixing the multiple nonstandard members of types. What do you think is a next step?

@sunmy2019
Copy link
Member

FunctionType = type(_f)
LambdaType = type(lambda: None)         # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = type(sys.implementation)

They are just variables. Variables don't deserve their own __name__. Any modification on them directly acts on the RHS.

Changing the __qualname__ of RHS is too much, and they do have a lot of backward compatibility issues.

"-1" on the change.

@JelleZijlstra
Copy link
Member

@sunmy2019 regardless of how they are created, these are the canonical names at which these types are exposed.

However, closing this as a duplicate of #100129.

@JelleZijlstra JelleZijlstra closed this as not planned Won't fix, can't repro, duplicate, stale Jun 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants