mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-128184: Fix display of signatures with ForwardRefs (#130815)
Co-authored-by: sobolevn <mail@sobolevn.me>
This commit is contained in:
parent
80e6d3ec49
commit
1d251b8339
5 changed files with 46 additions and 2 deletions
|
@ -1163,7 +1163,10 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
|
||||||
try:
|
try:
|
||||||
# In some cases fetching a signature is not possible.
|
# In some cases fetching a signature is not possible.
|
||||||
# But, we surely should not fail in this case.
|
# But, we surely should not fail in this case.
|
||||||
text_sig = str(inspect.signature(cls)).replace(' -> None', '')
|
text_sig = str(inspect.signature(
|
||||||
|
cls,
|
||||||
|
annotation_format=annotationlib.Format.FORWARDREF,
|
||||||
|
)).replace(' -> None', '')
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
text_sig = ''
|
text_sig = ''
|
||||||
cls.__doc__ = (cls.__name__ + text_sig)
|
cls.__doc__ = (cls.__name__ + text_sig)
|
||||||
|
|
|
@ -143,7 +143,7 @@ __all__ = [
|
||||||
|
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
from annotationlib import Format
|
from annotationlib import Format, ForwardRef
|
||||||
from annotationlib import get_annotations # re-exported
|
from annotationlib import get_annotations # re-exported
|
||||||
import ast
|
import ast
|
||||||
import dis
|
import dis
|
||||||
|
@ -1342,6 +1342,8 @@ def formatannotation(annotation, base_module=None, *, quote_annotation_strings=T
|
||||||
if annotation.__module__ in ('builtins', base_module):
|
if annotation.__module__ in ('builtins', base_module):
|
||||||
return annotation.__qualname__
|
return annotation.__qualname__
|
||||||
return annotation.__module__+'.'+annotation.__qualname__
|
return annotation.__module__+'.'+annotation.__qualname__
|
||||||
|
if isinstance(annotation, ForwardRef):
|
||||||
|
return annotation.__forward_arg__
|
||||||
return repr(annotation)
|
return repr(annotation)
|
||||||
|
|
||||||
def formatannotationrelativeto(object):
|
def formatannotationrelativeto(object):
|
||||||
|
|
|
@ -12,6 +12,7 @@ import builtins
|
||||||
import types
|
import types
|
||||||
import weakref
|
import weakref
|
||||||
import traceback
|
import traceback
|
||||||
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict
|
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict
|
||||||
|
@ -2343,6 +2344,31 @@ class TestDocString(unittest.TestCase):
|
||||||
|
|
||||||
self.assertDocStrEqual(C.__doc__, "C(x:collections.deque=<factory>)")
|
self.assertDocStrEqual(C.__doc__, "C(x:collections.deque=<factory>)")
|
||||||
|
|
||||||
|
def test_docstring_undefined_name(self):
|
||||||
|
@dataclass
|
||||||
|
class C:
|
||||||
|
x: undef
|
||||||
|
|
||||||
|
self.assertDocStrEqual(C.__doc__, "C(x:undef)")
|
||||||
|
|
||||||
|
def test_docstring_with_unsolvable_forward_ref_in_init(self):
|
||||||
|
# See: https://github.com/python/cpython/issues/128184
|
||||||
|
ns = {}
|
||||||
|
exec(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class C:
|
||||||
|
def __init__(self, x: X, num: int) -> None: ...
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
ns,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertDocStrEqual(ns['C'].__doc__, "C(x:X,num:int)")
|
||||||
|
|
||||||
def test_docstring_with_no_signature(self):
|
def test_docstring_with_no_signature(self):
|
||||||
# See https://github.com/python/cpython/issues/103449
|
# See https://github.com/python/cpython/issues/103449
|
||||||
class Meta(type):
|
class Meta(type):
|
||||||
|
|
|
@ -1753,6 +1753,10 @@ class TestFormatAnnotation(unittest.TestCase):
|
||||||
self.assertEqual(inspect.formatannotation(ann), 'Union[List[str], int]')
|
self.assertEqual(inspect.formatannotation(ann), 'Union[List[str], int]')
|
||||||
self.assertEqual(inspect.formatannotation(ann1), 'Union[List[testModule.typing.A], int]')
|
self.assertEqual(inspect.formatannotation(ann1), 'Union[List[testModule.typing.A], int]')
|
||||||
|
|
||||||
|
def test_forwardref(self):
|
||||||
|
fwdref = ForwardRef('fwdref')
|
||||||
|
self.assertEqual(inspect.formatannotation(fwdref), 'fwdref')
|
||||||
|
|
||||||
|
|
||||||
class TestIsMethodDescriptor(unittest.TestCase):
|
class TestIsMethodDescriptor(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -4587,6 +4591,11 @@ class TestSignatureObject(unittest.TestCase):
|
||||||
self.assertEqual(str(inspect.signature(foo)),
|
self.assertEqual(str(inspect.signature(foo)),
|
||||||
inspect.signature(foo).format())
|
inspect.signature(foo).format())
|
||||||
|
|
||||||
|
def foo(x: undef):
|
||||||
|
pass
|
||||||
|
sig = inspect.signature(foo, annotation_format=Format.FORWARDREF)
|
||||||
|
self.assertEqual(str(sig), '(x: undef)')
|
||||||
|
|
||||||
def test_signature_str_positional_only(self):
|
def test_signature_str_positional_only(self):
|
||||||
P = inspect.Parameter
|
P = inspect.Parameter
|
||||||
S = inspect.Signature
|
S = inspect.Signature
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Improve display of :class:`annotationlib.ForwardRef` object
|
||||||
|
within :class:`inspect.Signature` representations.
|
||||||
|
This also fixes a :exc:`NameError` that was raised when using
|
||||||
|
:func:`dataclasses.dataclass` on classes with unresolvable forward references.
|
Loading…
Add table
Add a link
Reference in a new issue