Skip to content

Commit 27410c5

Browse files
committed
Move attrs PEP 695 variance test to check-python312.test
Tests in check-python312.test get python_version=(3,12) automatically via testfile_pyversion(), which matches the filename. The test relied on # flags: --python-version 3.12 in check-plugin-attrs.test, but that path has a subtle interaction with mypyc-compiled mypy on Python 3.10 that causes the version flag to be silently ignored, yielding a syntax error instead of the expected type errors. Moving the test to check-python312.test (alongside the equivalent frozen- dataclass test) resolves the failure without changing test semantics. Assistant-Model: Claude Code
1 parent c8516ff commit 27410c5

2 files changed

Lines changed: 36 additions & 38 deletions

File tree

test-data/unit/check-plugin-attrs.test

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2512,41 +2512,3 @@ Parent(run_type = None)
25122512
c = Child(run_type = None)
25132513
reveal_type(c.run_type) # N: Revealed type is "builtins.int | None"
25142514
[builtins fixtures/plugin_attrs.pyi]
2515-
2516-
[case testAttrsPEP695InferVariance]
2517-
# flags: --python-version 3.12
2518-
import attrs
2519-
2520-
# attrs synthesizes ordering dunders (__lt__/__le__/__gt__/__ge__) whose
2521-
# ``other`` parameter is typed as the class's own ``Self[T]``. Those methods are
2522-
# plugin-generated and must not drag T into a contravariant position during
2523-
# PEP 695 variance inference. A frozen class using T only covariantly should be
2524-
# inferred covariant.
2525-
@attrs.frozen
2526-
class Covariant[T]:
2527-
x: T
2528-
def get(self) -> T:
2529-
return self.x
2530-
2531-
cov1: Covariant[object] = Covariant[int](1)
2532-
cov2: Covariant[int] = Covariant[object](1) # E: Incompatible types in assignment (expression has type "Covariant[object]", variable has type "Covariant[int]")
2533-
2534-
# A mutable attribute still makes the class invariant: plugin-generated *fields*
2535-
# must continue to be considered.
2536-
@attrs.define
2537-
class Invariant[T]:
2538-
x: T
2539-
2540-
inv1: Invariant[object] = Invariant[int](1) # E: Incompatible types in assignment (expression has type "Invariant[int]", variable has type "Invariant[object]")
2541-
inv2: Invariant[int] = Invariant[object](1) # E: Incompatible types in assignment (expression has type "Invariant[object]", variable has type "Invariant[int]")
2542-
2543-
# A user-written method with T in a parameter must still be honored: only
2544-
# plugin-generated methods are skipped, so this class stays contravariant.
2545-
@attrs.frozen
2546-
class Contravariant[T]:
2547-
def feed(self, x: T) -> None: ...
2548-
2549-
con1: Contravariant[int] = Contravariant[object]()
2550-
con2: Contravariant[object] = Contravariant[int]() # E: Incompatible types in assignment (expression has type "Contravariant[int]", variable has type "Contravariant[object]")
2551-
[builtins fixtures/plugin_attrs.pyi]
2552-
[typing fixtures/typing-full.pyi]

test-data/unit/check-python312.test

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,42 @@ cov2: Covariant[int] = Covariant[float](1) # E: Incompatible types in assignmen
265265
[builtins fixtures/tuple.pyi]
266266
[typing fixtures/typing-full.pyi]
267267

268+
[case testPEP695InferVarianceWithAttrsFrozen]
269+
import attrs
270+
271+
# attrs synthesizes ordering dunders (__lt__/__le__/__gt__/__ge__) whose
272+
# ``other`` parameter is typed as the class's own ``Self[T]``. Those methods
273+
# are plugin-generated and must not drag T into a contravariant position
274+
# during PEP 695 variance inference. A frozen class using T only covariantly
275+
# should be inferred covariant.
276+
@attrs.frozen
277+
class Covariant[T]:
278+
x: T
279+
def get(self) -> T:
280+
return self.x
281+
282+
cov1: Covariant[object] = Covariant[int](1)
283+
cov2: Covariant[int] = Covariant[object](1) # E: Incompatible types in assignment (expression has type "Covariant[object]", variable has type "Covariant[int]")
284+
285+
# A mutable attribute still makes the class invariant.
286+
@attrs.define
287+
class Invariant[T]:
288+
x: T
289+
290+
inv1: Invariant[object] = Invariant[int](1) # E: Incompatible types in assignment (expression has type "Invariant[int]", variable has type "Invariant[object]")
291+
inv2: Invariant[int] = Invariant[object](1) # E: Incompatible types in assignment (expression has type "Invariant[object]", variable has type "Invariant[int]")
292+
293+
# A user-written method with T in a parameter must still be honored: only
294+
# plugin-generated methods are skipped, so this class stays contravariant.
295+
@attrs.frozen
296+
class Contravariant[T]:
297+
def feed(self, x: T) -> None: ...
298+
299+
con1: Contravariant[int] = Contravariant[object]()
300+
con2: Contravariant[object] = Contravariant[int]() # E: Incompatible types in assignment (expression has type "Contravariant[int]", variable has type "Contravariant[object]")
301+
[builtins fixtures/plugin_attrs.pyi]
302+
[typing fixtures/typing-full.pyi]
303+
268304
[case testPEP695InferVarianceCalculateOnDemand]
269305
class Covariant[T]:
270306
def __init__(self) -> None:

0 commit comments

Comments
 (0)