| [case testSignaturesBasic] | |
| def f1(): pass | |
| def f2(x): pass | |
| def f3(x, /): pass | |
| def f4(*, x): pass | |
| def f5(*x): pass | |
| def f6(**x): pass | |
| def f7(x=None): pass | |
| def f8(x=None, /): pass | |
| def f9(*, x=None): pass | |
| def f10(a, /, b, c=None, *args, d=None, **h): pass | |
| [file driver.py] | |
| import inspect | |
| from native import * | |
| assert str(inspect.signature(f1)) == "()" | |
| assert str(inspect.signature(f2)) == "(x)" | |
| assert str(inspect.signature(f3)) == "(x, /)" | |
| assert str(inspect.signature(f4)) == "(*, x)" | |
| assert str(inspect.signature(f5)) == "(*x)" | |
| assert str(inspect.signature(f6)) == "(**x)" | |
| assert str(inspect.signature(f7)) == "(x=None)" | |
| assert str(inspect.signature(f8)) == "(x=None, /)" | |
| assert str(inspect.signature(f9)) == "(*, x=None)" | |
| assert str(inspect.signature(f10)) == "(a, /, b, c=None, *args, d=None, **h)" | |
| for fn in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10]: | |
| assert getattr(fn, "__doc__") is None | |
| [case testSignaturesValidDefaults] | |
| from typing import Final | |
| A: Final = 1 | |
| def default_int(x=1): pass | |
| def default_str(x="a"): pass | |
| def default_float(x=1.0): pass | |
| def default_true(x=True): pass | |
| def default_false(x=False): pass | |
| def default_none(x=None): pass | |
| def default_tuple_empty(x=()): pass | |
| def default_tuple_literals(x=(1, "a", 1.0, False, True, None, (), (1,2,(3,4)))): pass | |
| def default_tuple_singleton(x=(1,)): pass | |
| def default_named_constant(x=A): pass | |
| [file driver.py] | |
| import inspect | |
| from native import * | |
| assert str(inspect.signature(default_int)) == "(x=1)" | |
| assert str(inspect.signature(default_str)) == "(x='a')" | |
| assert str(inspect.signature(default_float)) == "(x=1.0)" | |
| assert str(inspect.signature(default_true)) == "(x=True)" | |
| assert str(inspect.signature(default_false)) == "(x=False)" | |
| assert str(inspect.signature(default_none)) == "(x=None)" | |
| assert str(inspect.signature(default_tuple_empty)) == "(x=())" | |
| assert str(inspect.signature(default_tuple_literals)) == "(x=(1, 'a', 1.0, False, True, None, (), (1, 2, (3, 4))))" | |
| assert str(inspect.signature(default_named_constant)) == "(x=1)" | |
| # Check __text_signature__ directly since inspect.signature produces | |
| # an incorrect signature for 1-tuple default arguments prior to | |
| # Python 3.12 (cpython#102379). | |
| # assert str(inspect.signature(default_tuple_singleton)) == "(x=(1,))" | |
| assert getattr(default_tuple_singleton, "__text_signature__") == "(x=(1,))" | |
| [case testSignaturesStringDefaults] | |
| def f1(x="'foo"): pass | |
| def f2(x='"foo'): pass | |
| def f3(x=""""Isn\'t," they said."""): pass | |
| def f4(x="\\ \a \b \f \n \r \t \v \x00"): pass | |
| def f5(x="\N{BANANA}sv"): pass | |
| [file driver.py] | |
| import inspect | |
| from native import * | |
| assert str(inspect.signature(f1)) == """(x="'foo")""" | |
| assert str(inspect.signature(f2)) == """(x='"foo')""" | |
| assert str(inspect.signature(f3)) == r"""(x='"Isn\'t," they said.')""" | |
| assert str(inspect.signature(f4)) == r"""(x='\\ \x07 \x08 \x0c \n \r \t \x0b \x00')""" | |
| assert str(inspect.signature(f5)) == """(x='\N{BANANA}sv')""" | |
| [case testSignaturesIrrepresentableDefaults] | |
| import enum | |
| class Color(enum.Enum): | |
| RED = 1 | |
| misc = object() | |
| # Default arguments that cannot be represented in a __text_signature__ | |
| def bad_object(x=misc): pass | |
| def bad_list_nonliteral(x=[misc]): pass | |
| def bad_dict_nonliteral(x={'a': misc}): pass | |
| def bad_set_nonliteral(x={misc}): pass | |
| def bad_set_empty(x=set()): pass # supported by ast.literal_eval, but not by inspect._signature_fromstr | |
| def bad_nan(x=float("nan")): pass | |
| def bad_enum(x=Color.RED): pass | |
| # TODO: Default arguments that could potentially be represented in a | |
| # __text_signature__, but which are not currently supported. | |
| # See 'inspect._signature_fromstr' for what default values are supported at runtime. | |
| def bad_complex(x=1+2j): pass | |
| def bad_list_empty(x=[]): pass | |
| def bad_list_literals(x=[1, 2, 3]): pass | |
| def bad_dict_empty(x={}): pass | |
| def bad_dict_literals(x={'a': 1}): pass | |
| def bad_set_literals(x={1, 2, 3}): pass | |
| def bad_tuple_literals(x=([1, 2, 3], {'a': 1}, {1, 2, 3})): pass | |
| def bad_ellipsis(x=...): pass | |
| def bad_literal_fold(x=1+2): pass | |
| [file driver.py] | |
| import inspect | |
| from testutil import assertRaises | |
| import native | |
| all_bad = [fn for name, fn in vars(native).items() if name.startswith("bad_")] | |
| assert all_bad | |
| for bad in all_bad: | |
| assert bad.__text_signature__ is None, f"{bad.__name__} has unexpected __text_signature__" | |
| with assertRaises(ValueError, "no signature found for builtin"): | |
| inspect.signature(bad) | |
| [case testSignaturesMethods] | |
| class Foo: | |
| def f1(self, x): pass | |
| @classmethod | |
| def f2(cls, x): pass | |
| @staticmethod | |
| def f3(x): pass | |
| def __eq__(self, x: object): pass | |
| [file driver.py] | |
| import inspect | |
| from native import * | |
| assert str(inspect.signature(Foo.f1)) == "(self, /, x)" | |
| assert str(inspect.signature(Foo().f1)) == "(x)" | |
| assert str(inspect.signature(Foo.f2)) == "(x)" | |
| assert str(inspect.signature(Foo().f2)) == "(x)" | |
| assert str(inspect.signature(Foo.f3)) == "(x)" | |
| assert str(inspect.signature(Foo().f3)) == "(x)" | |
| assert str(inspect.signature(Foo.__eq__)) == "(self, value, /)" | |
| assert str(inspect.signature(Foo().__eq__)) == "(value, /)" | |
| [case testSignaturesConstructors] | |
| class Empty: pass | |
| class HasInit: | |
| def __init__(self, x) -> None: pass | |
| class InheritedInit(HasInit): pass | |
| class HasInitBad: | |
| def __init__(self, x=[]) -> None: pass | |
| [file driver.py] | |
| import inspect | |
| from testutil import assertRaises | |
| from native import * | |
| assert str(inspect.signature(Empty)) == "()" | |
| assert str(inspect.signature(Empty.__init__)) == "(self, /, *args, **kwargs)" | |
| assert str(inspect.signature(HasInit)) == "(x)" | |
| assert str(inspect.signature(HasInit.__init__)) == "(self, /, *args, **kwargs)" | |
| assert str(inspect.signature(InheritedInit)) == "(x)" | |
| assert str(inspect.signature(InheritedInit.__init__)) == "(self, /, *args, **kwargs)" | |
| assert getattr(HasInitBad, "__text_signature__") is None | |
| with assertRaises(ValueError, "no signature found for builtin"): | |
| inspect.signature(HasInitBad) | |
| # CPython detail note: type objects whose tp_doc contains only a text signature behave | |
| # differently from method objects whose ml_doc contains only a test signature: type | |
| # objects will have __doc__="" whereas method objects will have __doc__=None. This | |
| # difference stems from the former using _PyType_GetDocFromInternalDoc(...) and the | |
| # latter using PyUnicode_FromString(_PyType_DocWithoutSignature(...)). | |
| for cls in [Empty, HasInit, InheritedInit]: | |
| assert getattr(cls, "__doc__") == "" | |
| assert getattr(HasInitBad, "__doc__") is None | |
| [case testSignaturesConstructorsNonExt] | |
| from mypy_extensions import mypyc_attr | |
| @mypyc_attr(native_class=False) | |
| class NonExt: | |
| def __init__(self, x) -> None: pass | |
| [file driver.py] | |
| import inspect | |
| from testutil import assertRaises | |
| from native import * | |
| # TODO: support constructor signatures for non-extension classes | |
| with assertRaises(ValueError, "no signature found for builtin"): | |
| inspect.signature(NonExt) | |
| [case testSignaturesHistoricalPositionalOnly] | |
| import inspect | |
| def f1(__x): pass | |
| def f2(__x, y): pass | |
| def f3(*, __y): pass | |
| def f4(x, *, __y): pass | |
| def f5(__x, *, __y): pass | |
| class A: | |
| def func(self, __x): pass | |
| def test_historical_positional_only() -> None: | |
| assert str(inspect.signature(f1)) == "(__x, /)" | |
| assert str(inspect.signature(f2)) == "(__x, /, y)" | |
| assert str(inspect.signature(f3)) == "(*, __y)" | |
| assert str(inspect.signature(f4)) == "(x, *, __y)" | |
| assert str(inspect.signature(f5)) == "(__x, /, *, __y)" | |
| assert str(inspect.signature(A.func)) == "(self, __x, /)" | |
| assert str(inspect.signature(A().func)) == "(__x, /)" |