diff --git a/jedi/plugins/stdlib.py b/jedi/plugins/stdlib.py index e1004ec8..f864a3f5 100644 --- a/jedi/plugins/stdlib.py +++ b/jedi/plugins/stdlib.py @@ -798,6 +798,12 @@ _implemented = { # runtime_checkable doesn't really change anything and is just # adding logs for infering stuff, so we can safely ignore it. 'runtime_checkable': lambda value, arguments, callback: NO_VALUES, + # Python 3.11+ + 'dataclass_transform': _dataclass, + }, + 'typing_extensions': { + # Python <3.11 + 'dataclass_transform': _dataclass, }, 'dataclasses': { # For now this works at least better than Jedi trying to understand it. diff --git a/setup.py b/setup.py index 54b5b0a1..6ed5110a 100755 --- a/setup.py +++ b/setup.py @@ -46,6 +46,7 @@ setup(name='jedi', 'colorama', 'Django', 'attrs', + 'typing_extensions', ], 'qa': [ # latest version supporting Python 3.6 diff --git a/test/test_inference/test_signature.py b/test/test_inference/test_signature.py index 4a1fcb62..cdfbe60e 100644 --- a/test/test_inference/test_signature.py +++ b/test/test_inference/test_signature.py @@ -354,6 +354,80 @@ def test_dataclass_signature(Script, skip_pre_python37, start, start_params): assert price.name == 'float' +@pytest.mark.parametrize( + 'start, start_params', [ + ['@dataclass_transform\nclass X:', []], + ['@dataclass_transform(eq=True)\nclass X:', []], + [dedent(''' + class Y(): + y: int + @dataclass_transform + class X(Y):'''), []], + [dedent(''' + @dataclass_transform + class Y(): + y: int + z = 5 + @dataclass_transform + class X(Y):'''), ['y']], + ] +) +def test_extensions_dataclass_transform_signature(Script, skip_pre_python37, start, start_params): + code = dedent(''' + name: str + foo = 3 + price: float + quantity: int = 0.0 + + X(''') + + code = 'from typing_extensions import dataclass_transform\n' + start + code + + sig, = Script(code).get_signatures() + assert [p.name for p in sig.params] == start_params + ['name', 'price', 'quantity'] + quantity, = sig.params[-1].infer() + assert quantity.name == 'int' + price, = sig.params[-2].infer() + assert price.name == 'float' + + +@pytest.mark.parametrize( + 'start, start_params', [ + ['@dataclass_transform\nclass X:', []], + ['@dataclass_transform(eq=True)\nclass X:', []], + [dedent(''' + class Y(): + y: int + @dataclass_transform + class X(Y):'''), []], + [dedent(''' + @dataclass_transform + class Y(): + y: int + z = 5 + @dataclass_transform + class X(Y):'''), ['y']], + ] +) +def test_dataclass_transform_signature(Script, skip_pre_python311, start, start_params): + code = dedent(''' + name: str + foo = 3 + price: float + quantity: int = 0.0 + + X(''') + + code = 'from typing import dataclass_transform\n' + start + code + + sig, = Script(code).get_signatures() + assert [p.name for p in sig.params] == start_params + ['name', 'price', 'quantity'] + quantity, = sig.params[-1].infer() + assert quantity.name == 'int' + price, = sig.params[-2].infer() + assert price.name == 'float' + + @pytest.mark.parametrize( 'start, start_params', [ ['@define\nclass X:', []],