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

gh-89828: Do not relay the __class__ attribute in GenericAlias #93754

Merged
merged 2 commits into from Jun 18, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/dataclasses.py
Expand Up @@ -230,7 +230,7 @@ def __init__(self, type):
self.type = type

def __repr__(self):
if isinstance(self.type, type) and not isinstance(self.type, GenericAlias):
if isinstance(self.type, type):
type_name = self.type.__name__
else:
# typing objects, e.g. List[int]
Expand Down Expand Up @@ -1248,7 +1248,7 @@ def _is_dataclass_instance(obj):
def is_dataclass(obj):
"""Returns True if obj is a dataclass or an instance of a
dataclass."""
cls = obj if isinstance(obj, type) and not isinstance(obj, GenericAlias) else type(obj)
cls = obj if isinstance(obj, type) else type(obj)
return hasattr(cls, _FIELDS)


Expand Down
5 changes: 2 additions & 3 deletions Lib/functools.py
Expand Up @@ -843,12 +843,11 @@ def _is_union_type(cls):
return get_origin(cls) in {Union, types.UnionType}

def _is_valid_dispatch_type(cls):
if isinstance(cls, type) and not isinstance(cls, GenericAlias):
if isinstance(cls, type):
return True
from typing import get_args
return (_is_union_type(cls) and
all(isinstance(arg, type) and not isinstance(arg, GenericAlias)
for arg in get_args(cls)))
all(isinstance(arg, type) for arg in get_args(cls)))

def register(cls, func=None):
"""generic_func.register(cls, func) -> func
Expand Down
22 changes: 9 additions & 13 deletions Lib/pydoc.py
Expand Up @@ -70,7 +70,6 @@ class or function within a module or module in a package. If the
import sysconfig
import time
import tokenize
import types
import urllib.parse
import warnings
from collections import deque
Expand All @@ -92,24 +91,21 @@ def pathdirs():
normdirs.append(normdir)
return dirs

def _isclass(object):
return inspect.isclass(object) and not isinstance(object, types.GenericAlias)

def _findclass(func):
cls = sys.modules.get(func.__module__)
if cls is None:
return None
for name in func.__qualname__.split('.')[:-1]:
cls = getattr(cls, name)
if not _isclass(cls):
if not inspect.isclass(cls):
return None
return cls

def _finddoc(obj):
if inspect.ismethod(obj):
name = obj.__func__.__name__
self = obj.__self__
if (_isclass(self) and
if (inspect.isclass(self) and
getattr(getattr(self, name, None), '__func__') is obj.__func__):
# classmethod
cls = self
Expand All @@ -123,7 +119,7 @@ def _finddoc(obj):
elif inspect.isbuiltin(obj):
name = obj.__name__
self = obj.__self__
if (_isclass(self) and
if (inspect.isclass(self) and
self.__qualname__ + '.' + name == obj.__qualname__):
# classmethod
cls = self
Expand Down Expand Up @@ -210,7 +206,7 @@ def classname(object, modname):

def isdata(object):
"""Check if an object is of a type that probably means it's data."""
return not (inspect.ismodule(object) or _isclass(object) or
return not (inspect.ismodule(object) or inspect.isclass(object) or
inspect.isroutine(object) or inspect.isframe(object) or
inspect.istraceback(object) or inspect.iscode(object))

Expand Down Expand Up @@ -481,7 +477,7 @@ def document(self, object, name=None, *args):
# by lacking a __name__ attribute) and an instance.
try:
if inspect.ismodule(object): return self.docmodule(*args)
if _isclass(object): return self.docclass(*args)
if inspect.isclass(object): return self.docclass(*args)
if inspect.isroutine(object): return self.docroutine(*args)
except AttributeError:
pass
Expand Down Expand Up @@ -783,7 +779,7 @@ def docmodule(self, object, name=None, mod=None, *ignored):
modules = inspect.getmembers(object, inspect.ismodule)

classes, cdict = [], {}
for key, value in inspect.getmembers(object, _isclass):
for key, value in inspect.getmembers(object, inspect.isclass):
# if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or
(inspect.getmodule(value) or object) is object):
Expand Down Expand Up @@ -1223,7 +1219,7 @@ def docmodule(self, object, name=None, mod=None):
result = result + self.section('DESCRIPTION', desc)

classes = []
for key, value in inspect.getmembers(object, _isclass):
for key, value in inspect.getmembers(object, inspect.isclass):
# if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None
or (inspect.getmodule(value) or object) is object):
Expand Down Expand Up @@ -1707,7 +1703,7 @@ def describe(thing):
return 'member descriptor %s.%s.%s' % (
thing.__objclass__.__module__, thing.__objclass__.__name__,
thing.__name__)
if _isclass(thing):
if inspect.isclass(thing):
return 'class ' + thing.__name__
if inspect.isfunction(thing):
return 'function ' + thing.__name__
Expand Down Expand Up @@ -1768,7 +1764,7 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
desc += ' in module ' + module.__name__

if not (inspect.ismodule(object) or
_isclass(object) or
inspect.isclass(object) or
inspect.isroutine(object) or
inspect.isdatadescriptor(object) or
_getdoc(object)):
Expand Down
2 changes: 1 addition & 1 deletion Lib/types.py
Expand Up @@ -80,7 +80,7 @@ def resolve_bases(bases):
updated = False
shift = 0
for i, base in enumerate(bases):
if isinstance(base, type) and not isinstance(base, GenericAlias):
if isinstance(base, type):
continue
if not hasattr(base, "__mro_entries__"):
continue
Expand Down
2 changes: 1 addition & 1 deletion Lib/typing.py
Expand Up @@ -1079,7 +1079,7 @@ def __typing_prepare_subst__(self, alias, args):
var_tuple_index = None
fillarg = None
for k, arg in enumerate(args):
if not (isinstance(arg, type) and not isinstance(arg, GenericAlias)):
if not isinstance(arg, type):
subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
if subargs and len(subargs) == 2 and subargs[-1] is ...:
if var_tuple_index is not None:
Expand Down
@@ -0,0 +1 @@
:class:`types.GenericAlias` no longer relay the ``__class__`` attribute.
serhiy-storchaka marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions Objects/genericaliasobject.c
Expand Up @@ -583,6 +583,7 @@ ga_vectorcall(PyObject *self, PyObject *const *args,
}

static const char* const attr_exceptions[] = {
"__class__",
"__origin__",
"__args__",
"__unpacked__",
Expand Down