Skip to content

Commit 49b4b3d

Browse files
authored
Don't add __match_args__ for dataclasses and named tuples with --python-version < 3.10 (#12503)
Fixes #12489
1 parent 1fedf2c commit 49b4b3d

File tree

7 files changed

+163
-6
lines changed

7 files changed

+163
-6
lines changed

mypy/plugins/dataclasses.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ def transform(self) -> bool:
230230
if (decorator_arguments['match_args'] and
231231
('__match_args__' not in info.names or
232232
info.names['__match_args__'].plugin_generated) and
233-
attributes):
233+
attributes and
234+
py_version >= (3, 10)):
234235
str_type = ctx.api.named_type("builtins.str")
235236
literals: List[Type] = [LiteralType(attr.name, str_type)
236237
for attr in attributes if attr.is_in_init]

mypy/semanal_namedtuple.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,8 @@ def add_field(var: Var, is_initialized_in_class: bool = False,
447447
add_field(Var('_source', strtype), is_initialized_in_class=True)
448448
add_field(Var('__annotations__', ordereddictype), is_initialized_in_class=True)
449449
add_field(Var('__doc__', strtype), is_initialized_in_class=True)
450-
add_field(Var('__match_args__', match_args_type), is_initialized_in_class=True)
450+
if self.options.python_version >= (3, 10):
451+
add_field(Var('__match_args__', match_args_type), is_initialized_in_class=True)
451452

452453
tvd = TypeVarType(SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME,
453454
-1, [], info.tuple_type)

mypy/test/testmerge.py

-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from mypy import build
88
from mypy.build import BuildResult
99
from mypy.modulefinder import BuildSource
10-
from mypy.defaults import PYTHON3_VERSION
1110
from mypy.errors import CompileError
1211
from mypy.nodes import (
1312
Node, MypyFile, SymbolTable, SymbolTableNode, TypeInfo, Expression, Var, TypeVarExpr,
@@ -107,7 +106,6 @@ def build(self, source: str, testcase: DataDrivenTestCase) -> Optional[BuildResu
107106
options.use_builtins_fixtures = True
108107
options.export_types = True
109108
options.show_traceback = True
110-
options.python_version = PYTHON3_VERSION
111109
main_path = os.path.join(test_temp_dir, 'main')
112110
with open(main_path, 'w', encoding='utf8') as f:
113111
f.write(source)

test-data/unit/check-dataclasses.test

+45
Original file line numberDiff line numberDiff line change
@@ -1790,3 +1790,48 @@ class MyDataclass:
17901790
class MyGeneric(Generic[T]): ...
17911791
class MyClass(MyGeneric[MyDataclass]): ...
17921792
[builtins fixtures/dataclasses.pyi]
1793+
1794+
[case testDataclassWithMatchArgs]
1795+
# flags: --python-version 3.10
1796+
from dataclasses import dataclass
1797+
@dataclass
1798+
class One:
1799+
bar: int
1800+
baz: str
1801+
o: One
1802+
reveal_type(o.__match_args__) # N: Revealed type is "Tuple[Literal['bar'], Literal['baz']]"
1803+
@dataclass(match_args=True)
1804+
class Two:
1805+
bar: int
1806+
t: Two
1807+
reveal_type(t.__match_args__) # N: Revealed type is "Tuple[Literal['bar']]"
1808+
[builtins fixtures/dataclasses.pyi]
1809+
1810+
[case testDataclassWithoutMatchArgs]
1811+
# flags: --python-version 3.10
1812+
from dataclasses import dataclass
1813+
@dataclass(match_args=False)
1814+
class One:
1815+
bar: int
1816+
baz: str
1817+
o: One
1818+
reveal_type(o.__match_args__) # E: "One" has no attribute "__match_args__" \
1819+
# N: Revealed type is "Any"
1820+
[builtins fixtures/dataclasses.pyi]
1821+
1822+
[case testDataclassWithMatchArgsOldVersion]
1823+
# flags: --python-version 3.9
1824+
from dataclasses import dataclass
1825+
@dataclass(match_args=True)
1826+
class One:
1827+
bar: int
1828+
o: One
1829+
reveal_type(o.__match_args__) # E: "One" has no attribute "__match_args__" \
1830+
# N: Revealed type is "Any"
1831+
@dataclass
1832+
class Two:
1833+
bar: int
1834+
t: Two
1835+
reveal_type(t.__match_args__) # E: "Two" has no attribute "__match_args__" \
1836+
# N: Revealed type is "Any"
1837+
[builtins fixtures/dataclasses.pyi]

test-data/unit/check-namedtuple.test

+23
Original file line numberDiff line numberDiff line change
@@ -1134,3 +1134,26 @@ def f(fields) -> None:
11341134
NT2 = namedtuple("bad", "x") # E: First argument to namedtuple() should be "NT2", not "bad"
11351135
nt2: NT2 = NT2(x=1)
11361136
[builtins fixtures/tuple.pyi]
1137+
1138+
[case testNamedTupleHasMatchArgs]
1139+
# flags: --python-version 3.10
1140+
from typing import NamedTuple
1141+
class One(NamedTuple):
1142+
bar: int
1143+
baz: str
1144+
o: One
1145+
reveal_type(o.__match_args__) # N: Revealed type is "Tuple[Literal['bar'], Literal['baz']]"
1146+
[builtins fixtures/tuple.pyi]
1147+
[typing fixtures/typing-namedtuple.pyi]
1148+
1149+
[case testNamedTupleHasNoMatchArgsOldVersion]
1150+
# flags: --python-version 3.9
1151+
from typing import NamedTuple
1152+
class One(NamedTuple):
1153+
bar: int
1154+
baz: str
1155+
o: One
1156+
reveal_type(o.__match_args__) # E: "One" has no attribute "__match_args__" \
1157+
# N: Revealed type is "Any"
1158+
[builtins fixtures/tuple.pyi]
1159+
[typing fixtures/typing-namedtuple.pyi]

test-data/unit/deps.test

+31-1
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,7 @@ class D(C):
14201420
<m.C> -> m, m.C, m.D
14211421
<m.D> -> m.D
14221422

1423-
[case testDataclassDeps]
1423+
[case testDataclassDepsOldVersion]
14241424
# flags: --python-version 3.7
14251425
from dataclasses import dataclass
14261426

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

1438+
[out]
1439+
<m.A.(abstract)> -> <m.B.__init__>, m
1440+
<m.A.__dataclass_fields__> -> <m.B.__dataclass_fields__>
1441+
<m.A.__init__> -> <m.B.__init__>, m.B.__init__
1442+
<m.A.__new__> -> <m.B.__new__>
1443+
<m.A.x> -> <m.B.x>
1444+
<m.A.y> -> <m.B.y>
1445+
<m.A> -> m, m.A, m.B
1446+
<m.A[wildcard]> -> m
1447+
<m.B.y> -> m
1448+
<m.B> -> m.B
1449+
<m.Z> -> m
1450+
<dataclasses.dataclass> -> m
1451+
<dataclasses> -> m
1452+
1453+
[case testDataclassDeps]
1454+
# flags: --python-version 3.10
1455+
from dataclasses import dataclass
1456+
1457+
Z = int
1458+
1459+
@dataclass
1460+
class A:
1461+
x: Z
1462+
1463+
@dataclass
1464+
class B(A):
1465+
y: int
1466+
[builtins fixtures/dataclasses.pyi]
1467+
14381468
[out]
14391469
<m.A.(abstract)> -> <m.B.__init__>, m
14401470
<m.A.__dataclass_fields__> -> <m.B.__dataclass_fields__>

test-data/unit/merge.test

+60-1
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ TypeInfo<2>(
646646
f<3>))
647647

648648
[case testNamedTuple_typeinfo]
649-
649+
# flags: --python-version 3.10
650650
import target
651651
[file target.py]
652652
from typing import NamedTuple
@@ -707,6 +707,65 @@ TypeInfo<2>(
707707
x<19> (target.A<0>)
708708
y<20> (target.A<0>)))
709709

710+
[case testNamedTupleOldVersion_typeinfo]
711+
import target
712+
[file target.py]
713+
from typing import NamedTuple
714+
class A: pass
715+
N = NamedTuple('N', [('x', A)])
716+
[file target.py.next]
717+
from typing import NamedTuple
718+
class A: pass
719+
N = NamedTuple('N', [('x', A), ('y', A)])
720+
[builtins fixtures/tuple.pyi]
721+
[out]
722+
TypeInfo<0>(
723+
Name(target.A)
724+
Bases(builtins.object<1>)
725+
Mro(target.A<0>, builtins.object<1>)
726+
Names())
727+
TypeInfo<2>(
728+
Name(target.N)
729+
Bases(builtins.tuple[target.A<0>, ...]<3>)
730+
Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>)
731+
Names(
732+
_NT<6>
733+
__annotations__<7> (builtins.object<1>)
734+
__doc__<8> (builtins.str<9>)
735+
__new__<10>
736+
_asdict<11>
737+
_field_defaults<12> (builtins.object<1>)
738+
_field_types<13> (builtins.object<1>)
739+
_fields<14> (Tuple[builtins.str<9>])
740+
_make<15>
741+
_replace<16>
742+
_source<17> (builtins.str<9>)
743+
x<18> (target.A<0>)))
744+
==>
745+
TypeInfo<0>(
746+
Name(target.A)
747+
Bases(builtins.object<1>)
748+
Mro(target.A<0>, builtins.object<1>)
749+
Names())
750+
TypeInfo<2>(
751+
Name(target.N)
752+
Bases(builtins.tuple[target.A<0>, ...]<3>)
753+
Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>)
754+
Names(
755+
_NT<6>
756+
__annotations__<7> (builtins.object<1>)
757+
__doc__<8> (builtins.str<9>)
758+
__new__<10>
759+
_asdict<11>
760+
_field_defaults<12> (builtins.object<1>)
761+
_field_types<13> (builtins.object<1>)
762+
_fields<14> (Tuple[builtins.str<9>, builtins.str<9>])
763+
_make<15>
764+
_replace<16>
765+
_source<17> (builtins.str<9>)
766+
x<18> (target.A<0>)
767+
y<19> (target.A<0>)))
768+
710769
[case testUnionType_types]
711770
import target
712771
[file target.py]

0 commit comments

Comments
 (0)