Skip to content

Commit 177c8ee

Browse files
authored
Fix strict optional handling in attrs plugin (#17451)
Fixes #13794 Fix is trivial (but unlike for dataclasses, the calls to type ops are scattered, so I simply put the whole hook inside a single `with`).
1 parent e4de4e3 commit 177c8ee

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

mypy/plugins/attrs.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
deserialize_and_fixup_type,
5656
)
5757
from mypy.server.trigger import make_wildcard_trigger
58+
from mypy.state import state
5859
from mypy.typeops import get_type_vars, make_simplified_union, map_type_from_supertype
5960
from mypy.types import (
6061
AnyType,
@@ -317,9 +318,23 @@ def attr_class_maker_callback(
317318
318319
See https://www.attrs.org/en/stable/how-does-it-work.html for information on how attrs works.
319320
320-
If this returns False, some required metadata was not ready yet and we need another
321+
If this returns False, some required metadata was not ready yet, and we need another
321322
pass.
322323
"""
324+
with state.strict_optional_set(ctx.api.options.strict_optional):
325+
# This hook is called during semantic analysis, but it uses a bunch of
326+
# type-checking ops, so it needs the strict optional set properly.
327+
return attr_class_maker_callback_impl(
328+
ctx, auto_attribs_default, frozen_default, slots_default
329+
)
330+
331+
332+
def attr_class_maker_callback_impl(
333+
ctx: mypy.plugin.ClassDefContext,
334+
auto_attribs_default: bool | None,
335+
frozen_default: bool,
336+
slots_default: bool,
337+
) -> bool:
323338
info = ctx.cls.info
324339

325340
init = _get_decorator_bool_argument(ctx, "init", True)

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2475,3 +2475,23 @@ class B:
24752475
reveal_type(B.__hash__) # N: Revealed type is "None"
24762476

24772477
[builtins fixtures/plugin_attrs.pyi]
2478+
2479+
[case testAttrsStrictOptionalSetProperly]
2480+
from typing import Generic, Optional, TypeVar
2481+
2482+
import attr
2483+
2484+
T = TypeVar("T")
2485+
2486+
@attr.mutable()
2487+
class Parent(Generic[T]):
2488+
run_type: Optional[int] = None
2489+
2490+
@attr.mutable()
2491+
class Child(Parent[float]):
2492+
pass
2493+
2494+
Parent(run_type = None)
2495+
c = Child(run_type = None)
2496+
reveal_type(c.run_type) # N: Revealed type is "Union[builtins.int, None]"
2497+
[builtins fixtures/plugin_attrs.pyi]

0 commit comments

Comments
 (0)