Skip to content

Commit

Permalink
Don't add __match_args__ for dataclasses and named tuples with --pyth…
Browse files Browse the repository at this point in the history
…on-version < 3.10 (#12503)

Fixes #12489
  • Loading branch information
stkrizh authored Jul 8, 2022
1 parent 1fedf2c commit 49b4b3d
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 6 deletions.
3 changes: 2 additions & 1 deletion mypy/plugins/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ def transform(self) -> bool:
if (decorator_arguments['match_args'] and
('__match_args__' not in info.names or
info.names['__match_args__'].plugin_generated) and
attributes):
attributes and
py_version >= (3, 10)):
str_type = ctx.api.named_type("builtins.str")
literals: List[Type] = [LiteralType(attr.name, str_type)
for attr in attributes if attr.is_in_init]
Expand Down
3 changes: 2 additions & 1 deletion mypy/semanal_namedtuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,8 @@ def add_field(var: Var, is_initialized_in_class: bool = False,
add_field(Var('_source', strtype), is_initialized_in_class=True)
add_field(Var('__annotations__', ordereddictype), is_initialized_in_class=True)
add_field(Var('__doc__', strtype), is_initialized_in_class=True)
add_field(Var('__match_args__', match_args_type), is_initialized_in_class=True)
if self.options.python_version >= (3, 10):
add_field(Var('__match_args__', match_args_type), is_initialized_in_class=True)

tvd = TypeVarType(SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME,
-1, [], info.tuple_type)
Expand Down
2 changes: 0 additions & 2 deletions mypy/test/testmerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from mypy import build
from mypy.build import BuildResult
from mypy.modulefinder import BuildSource
from mypy.defaults import PYTHON3_VERSION
from mypy.errors import CompileError
from mypy.nodes import (
Node, MypyFile, SymbolTable, SymbolTableNode, TypeInfo, Expression, Var, TypeVarExpr,
Expand Down Expand Up @@ -107,7 +106,6 @@ def build(self, source: str, testcase: DataDrivenTestCase) -> Optional[BuildResu
options.use_builtins_fixtures = True
options.export_types = True
options.show_traceback = True
options.python_version = PYTHON3_VERSION
main_path = os.path.join(test_temp_dir, 'main')
with open(main_path, 'w', encoding='utf8') as f:
f.write(source)
Expand Down
45 changes: 45 additions & 0 deletions test-data/unit/check-dataclasses.test
Original file line number Diff line number Diff line change
Expand Up @@ -1790,3 +1790,48 @@ class MyDataclass:
class MyGeneric(Generic[T]): ...
class MyClass(MyGeneric[MyDataclass]): ...
[builtins fixtures/dataclasses.pyi]

[case testDataclassWithMatchArgs]
# flags: --python-version 3.10
from dataclasses import dataclass
@dataclass
class One:
bar: int
baz: str
o: One
reveal_type(o.__match_args__) # N: Revealed type is "Tuple[Literal['bar'], Literal['baz']]"
@dataclass(match_args=True)
class Two:
bar: int
t: Two
reveal_type(t.__match_args__) # N: Revealed type is "Tuple[Literal['bar']]"
[builtins fixtures/dataclasses.pyi]

[case testDataclassWithoutMatchArgs]
# flags: --python-version 3.10
from dataclasses import dataclass
@dataclass(match_args=False)
class One:
bar: int
baz: str
o: One
reveal_type(o.__match_args__) # E: "One" has no attribute "__match_args__" \
# N: Revealed type is "Any"
[builtins fixtures/dataclasses.pyi]

[case testDataclassWithMatchArgsOldVersion]
# flags: --python-version 3.9
from dataclasses import dataclass
@dataclass(match_args=True)
class One:
bar: int
o: One
reveal_type(o.__match_args__) # E: "One" has no attribute "__match_args__" \
# N: Revealed type is "Any"
@dataclass
class Two:
bar: int
t: Two
reveal_type(t.__match_args__) # E: "Two" has no attribute "__match_args__" \
# N: Revealed type is "Any"
[builtins fixtures/dataclasses.pyi]
23 changes: 23 additions & 0 deletions test-data/unit/check-namedtuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -1134,3 +1134,26 @@ def f(fields) -> None:
NT2 = namedtuple("bad", "x") # E: First argument to namedtuple() should be "NT2", not "bad"
nt2: NT2 = NT2(x=1)
[builtins fixtures/tuple.pyi]

[case testNamedTupleHasMatchArgs]
# flags: --python-version 3.10
from typing import NamedTuple
class One(NamedTuple):
bar: int
baz: str
o: One
reveal_type(o.__match_args__) # N: Revealed type is "Tuple[Literal['bar'], Literal['baz']]"
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-namedtuple.pyi]

[case testNamedTupleHasNoMatchArgsOldVersion]
# flags: --python-version 3.9
from typing import NamedTuple
class One(NamedTuple):
bar: int
baz: str
o: One
reveal_type(o.__match_args__) # E: "One" has no attribute "__match_args__" \
# N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-namedtuple.pyi]
32 changes: 31 additions & 1 deletion test-data/unit/deps.test
Original file line number Diff line number Diff line change
Expand Up @@ -1420,7 +1420,7 @@ class D(C):
<m.C> -> m, m.C, m.D
<m.D> -> m.D

[case testDataclassDeps]
[case testDataclassDepsOldVersion]
# flags: --python-version 3.7
from dataclasses import dataclass

Expand All @@ -1435,6 +1435,36 @@ class B(A):
y: int
[builtins fixtures/dataclasses.pyi]

[out]
<m.A.(abstract)> -> <m.B.__init__>, m
<m.A.__dataclass_fields__> -> <m.B.__dataclass_fields__>
<m.A.__init__> -> <m.B.__init__>, m.B.__init__
<m.A.__new__> -> <m.B.__new__>
<m.A.x> -> <m.B.x>
<m.A.y> -> <m.B.y>
<m.A> -> m, m.A, m.B
<m.A[wildcard]> -> m
<m.B.y> -> m
<m.B> -> m.B
<m.Z> -> m
<dataclasses.dataclass> -> m
<dataclasses> -> m

[case testDataclassDeps]
# flags: --python-version 3.10
from dataclasses import dataclass

Z = int

@dataclass
class A:
x: Z

@dataclass
class B(A):
y: int
[builtins fixtures/dataclasses.pyi]

[out]
<m.A.(abstract)> -> <m.B.__init__>, m
<m.A.__dataclass_fields__> -> <m.B.__dataclass_fields__>
Expand Down
61 changes: 60 additions & 1 deletion test-data/unit/merge.test
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ TypeInfo<2>(
f<3>))

[case testNamedTuple_typeinfo]

# flags: --python-version 3.10
import target
[file target.py]
from typing import NamedTuple
Expand Down Expand Up @@ -707,6 +707,65 @@ TypeInfo<2>(
x<19> (target.A<0>)
y<20> (target.A<0>)))

[case testNamedTupleOldVersion_typeinfo]
import target
[file target.py]
from typing import NamedTuple
class A: pass
N = NamedTuple('N', [('x', A)])
[file target.py.next]
from typing import NamedTuple
class A: pass
N = NamedTuple('N', [('x', A), ('y', A)])
[builtins fixtures/tuple.pyi]
[out]
TypeInfo<0>(
Name(target.A)
Bases(builtins.object<1>)
Mro(target.A<0>, builtins.object<1>)
Names())
TypeInfo<2>(
Name(target.N)
Bases(builtins.tuple[target.A<0>, ...]<3>)
Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>)
Names(
_NT<6>
__annotations__<7> (builtins.object<1>)
__doc__<8> (builtins.str<9>)
__new__<10>
_asdict<11>
_field_defaults<12> (builtins.object<1>)
_field_types<13> (builtins.object<1>)
_fields<14> (Tuple[builtins.str<9>])
_make<15>
_replace<16>
_source<17> (builtins.str<9>)
x<18> (target.A<0>)))
==>
TypeInfo<0>(
Name(target.A)
Bases(builtins.object<1>)
Mro(target.A<0>, builtins.object<1>)
Names())
TypeInfo<2>(
Name(target.N)
Bases(builtins.tuple[target.A<0>, ...]<3>)
Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>)
Names(
_NT<6>
__annotations__<7> (builtins.object<1>)
__doc__<8> (builtins.str<9>)
__new__<10>
_asdict<11>
_field_defaults<12> (builtins.object<1>)
_field_types<13> (builtins.object<1>)
_fields<14> (Tuple[builtins.str<9>, builtins.str<9>])
_make<15>
_replace<16>
_source<17> (builtins.str<9>)
x<18> (target.A<0>)
y<19> (target.A<0>)))

[case testUnionType_types]
import target
[file target.py]
Expand Down

0 comments on commit 49b4b3d

Please sign in to comment.