Skip to content

Commit 3bf9fdc

Browse files
committed
Revert "Add support for attrs.fields (#15021)"
This reverts commit 391ed85. The use of a Union item type for `attr.Attribute` would likely be more useful to callsites of `attr.fields` - otherwise this currently results in inferring `builtins.object` in many cases where we treat the fields as a variable-length tuple, rather than a fixed-length one. Applications of the fixed-length tuple seem limited since you would need to access it by index. @Tinche as the original author of the commit.
1 parent 2ab8849 commit 3bf9fdc

File tree

5 files changed

+3
-109
lines changed

5 files changed

+3
-109
lines changed

mypy/plugins/attrs.py

+3-49
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969
TupleType,
7070
Type,
7171
TypeOfAny,
72-
TypeType,
7372
TypeVarType,
7473
UninhabitedType,
7574
UnionType,
@@ -945,7 +944,7 @@ def add_method(
945944

946945
def _get_attrs_init_type(typ: Instance) -> CallableType | None:
947946
"""
948-
If `typ` refers to an attrs class, get the type of its initializer method.
947+
If `typ` refers to an attrs class, gets the type of its initializer method.
949948
"""
950949
magic_attr = typ.type.get(MAGIC_ATTR_NAME)
951950
if magic_attr is None or not magic_attr.plugin_generated:
@@ -1019,7 +1018,7 @@ def _get_expanded_attr_types(
10191018

10201019
def _meet_fields(types: list[Mapping[str, Type]]) -> Mapping[str, Type]:
10211020
"""
1022-
"Meet" the fields of a list of attrs classes, i.e. for each field, its new type will be the lower bound.
1021+
"Meets" the fields of a list of attrs classes, i.e. for each field, its new type will be the lower bound.
10231022
"""
10241023
field_to_types = defaultdict(list)
10251024
for fields in types:
@@ -1036,7 +1035,7 @@ def _meet_fields(types: list[Mapping[str, Type]]) -> Mapping[str, Type]:
10361035

10371036
def evolve_function_sig_callback(ctx: mypy.plugin.FunctionSigContext) -> CallableType:
10381037
"""
1039-
Generate a signature for the 'attr.evolve' function that's specific to the call site
1038+
Generates a signature for the 'attr.evolve' function that's specific to the call site
10401039
and dependent on the type of the first argument.
10411040
"""
10421041
if len(ctx.args) != 2:
@@ -1070,48 +1069,3 @@ def evolve_function_sig_callback(ctx: mypy.plugin.FunctionSigContext) -> Callabl
10701069
fallback=ctx.default_signature.fallback,
10711070
name=f"{ctx.default_signature.name} of {inst_type_str}",
10721071
)
1073-
1074-
1075-
def fields_function_sig_callback(ctx: mypy.plugin.FunctionSigContext) -> CallableType:
1076-
"""Provide the signature for `attrs.fields`."""
1077-
if not ctx.args or len(ctx.args) != 1 or not ctx.args[0] or not ctx.args[0][0]:
1078-
return ctx.default_signature
1079-
1080-
# <hack>
1081-
assert isinstance(ctx.api, TypeChecker)
1082-
inst_type = ctx.api.expr_checker.accept(ctx.args[0][0])
1083-
# </hack>
1084-
proper_type = get_proper_type(inst_type)
1085-
1086-
# fields(Any) -> Any, fields(type[Any]) -> Any
1087-
if (
1088-
isinstance(proper_type, AnyType)
1089-
or isinstance(proper_type, TypeType)
1090-
and isinstance(proper_type.item, AnyType)
1091-
):
1092-
return ctx.default_signature
1093-
1094-
cls = None
1095-
arg_types = ctx.default_signature.arg_types
1096-
1097-
if isinstance(proper_type, TypeVarType):
1098-
inner = get_proper_type(proper_type.upper_bound)
1099-
if isinstance(inner, Instance):
1100-
# We need to work arg_types to compensate for the attrs stubs.
1101-
arg_types = [inst_type]
1102-
cls = inner.type
1103-
elif isinstance(proper_type, CallableType):
1104-
cls = proper_type.type_object()
1105-
1106-
if cls is not None and MAGIC_ATTR_NAME in cls.names:
1107-
# This is a proper attrs class.
1108-
ret_type = cls.names[MAGIC_ATTR_NAME].type
1109-
assert ret_type is not None
1110-
return ctx.default_signature.copy_modified(arg_types=arg_types, ret_type=ret_type)
1111-
1112-
ctx.api.fail(
1113-
f'Argument 1 to "fields" has incompatible type "{format_type_bare(proper_type, ctx.api.options)}"; expected an attrs class',
1114-
ctx.context,
1115-
)
1116-
1117-
return ctx.default_signature

mypy/plugins/default.py

-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ def get_function_hook(self, fullname: str) -> Callable[[FunctionContext], Type]
4545
return ctypes.array_constructor_callback
4646
elif fullname == "functools.singledispatch":
4747
return singledispatch.create_singledispatch_function_callback
48-
4948
return None
5049

5150
def get_function_signature_hook(
@@ -55,8 +54,6 @@ def get_function_signature_hook(
5554

5655
if fullname in ("attr.evolve", "attrs.evolve", "attr.assoc", "attrs.assoc"):
5756
return attrs.evolve_function_sig_callback
58-
elif fullname in ("attr.fields", "attrs.fields"):
59-
return attrs.fields_function_sig_callback
6057
return None
6158

6259
def get_method_signature_hook(

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

-53
Original file line numberDiff line numberDiff line change
@@ -1553,59 +1553,6 @@ takes_attrs_cls(A(1, "")) # E: Argument 1 to "takes_attrs_cls" has incompatible
15531553
takes_attrs_instance(A) # E: Argument 1 to "takes_attrs_instance" has incompatible type "Type[A]"; expected "AttrsInstance" # N: ClassVar protocol member AttrsInstance.__attrs_attrs__ can never be matched by a class object
15541554
[builtins fixtures/plugin_attrs.pyi]
15551555

1556-
[case testAttrsFields]
1557-
import attr
1558-
from attrs import fields as f # Common usage.
1559-
1560-
@attr.define
1561-
class A:
1562-
b: int
1563-
c: str
1564-
1565-
reveal_type(f(A)) # N: Revealed type is "Tuple[attr.Attribute[builtins.int], attr.Attribute[builtins.str], fallback=__main__.A.____main___A_AttrsAttributes__]"
1566-
reveal_type(f(A)[0]) # N: Revealed type is "attr.Attribute[builtins.int]"
1567-
reveal_type(f(A).b) # N: Revealed type is "attr.Attribute[builtins.int]"
1568-
f(A).x # E: "____main___A_AttrsAttributes__" has no attribute "x"
1569-
1570-
[builtins fixtures/plugin_attrs.pyi]
1571-
1572-
[case testAttrsGenericFields]
1573-
from typing import TypeVar
1574-
1575-
import attr
1576-
from attrs import fields
1577-
1578-
@attr.define
1579-
class A:
1580-
b: int
1581-
c: str
1582-
1583-
TA = TypeVar('TA', bound=A)
1584-
1585-
def f(t: TA) -> None:
1586-
reveal_type(fields(t)) # N: Revealed type is "Tuple[attr.Attribute[builtins.int], attr.Attribute[builtins.str], fallback=__main__.A.____main___A_AttrsAttributes__]"
1587-
reveal_type(fields(t)[0]) # N: Revealed type is "attr.Attribute[builtins.int]"
1588-
reveal_type(fields(t).b) # N: Revealed type is "attr.Attribute[builtins.int]"
1589-
fields(t).x # E: "____main___A_AttrsAttributes__" has no attribute "x"
1590-
1591-
1592-
[builtins fixtures/plugin_attrs.pyi]
1593-
1594-
[case testNonattrsFields]
1595-
from typing import Any, cast, Type
1596-
from attrs import fields
1597-
1598-
class A:
1599-
b: int
1600-
c: str
1601-
1602-
fields(A) # E: Argument 1 to "fields" has incompatible type "Type[A]"; expected an attrs class
1603-
fields(None) # E: Argument 1 to "fields" has incompatible type "None"; expected an attrs class
1604-
fields(cast(Any, 42))
1605-
fields(cast(Type[Any], 43))
1606-
1607-
[builtins fixtures/plugin_attrs.pyi]
1608-
16091556
[case testAttrsInitMethodAlwaysGenerates]
16101557
from typing import Tuple
16111558
import attr

test-data/unit/lib-stub/attr/__init__.pyi

-2
Original file line numberDiff line numberDiff line change
@@ -247,5 +247,3 @@ def field(
247247

248248
def evolve(inst: _T, **changes: Any) -> _T: ...
249249
def assoc(inst: _T, **changes: Any) -> _T: ...
250-
251-
def fields(cls: type) -> Any: ...

test-data/unit/lib-stub/attrs/__init__.pyi

-2
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,3 @@ def field(
131131

132132
def evolve(inst: _T, **changes: Any) -> _T: ...
133133
def assoc(inst: _T, **changes: Any) -> _T: ...
134-
135-
def fields(cls: type) -> Any: ...

0 commit comments

Comments
 (0)