Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bb75c58

Browse files
More attributes cleanup (#464)
1 parent 13c38df commit bb75c58

4 files changed

Lines changed: 16 additions & 244 deletions

File tree

pycroscope/attributes.py

Lines changed: 14 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@
103103
replace_fallback,
104104
set_self,
105105
shield_nested_self_typevars,
106-
stringify_object,
107106
unite_values,
108107
)
109108

@@ -162,11 +161,6 @@ def resolve_name_from_typeshed(self, module: str, name: str) -> Value:
162161
def get_attribute_from_typeshed(self, typ: type, *, on_class: bool) -> Value:
163162
raise NotImplementedError
164163

165-
def get_attribute_from_typeshed_recursively(
166-
self, fq_name: str, *, on_class: bool
167-
) -> tuple[Value, type | str]:
168-
raise NotImplementedError
169-
170164
def should_ignore_none_attributes(self) -> bool:
171165
raise NotImplementedError
172166

@@ -320,7 +314,7 @@ def get_attribute(ctx: AttrContext) -> Value:
320314
synthetic_name = root_value.typ.typ
321315
else:
322316
attribute_value = _get_attribute_from_subclass(
323-
root_value.typ.typ, root_value.typ, ctx
317+
root_value.typ.typ, root_value, ctx
324318
)
325319
elif isinstance(root_value.typ, TypeVarValue):
326320
if root_value.typ.typevar_param.bound is not None:
@@ -362,16 +356,9 @@ def get_attribute(ctx: AttrContext) -> Value:
362356
elif isinstance(root_value, SyntheticClassObjectValue):
363357
if isinstance(root_value.class_type, TypedDictValue):
364358
attribute_value = _get_attribute_from_subclass(dict, root_value, ctx)
365-
elif isinstance(root_value.class_type.typ, str):
366-
attribute_value = _get_attribute_from_synthetic_class(
367-
root_value.class_type.typ, root_value, ctx
368-
)
369359
else:
370360
attribute_value = _get_attribute_from_synthetic_class(
371-
stringify_object(root_value.class_type.typ),
372-
root_value,
373-
ctx,
374-
runtime_type=root_value.class_type.typ,
361+
root_value.class_type.typ, root_value, ctx
375362
)
376363
else:
377364
assert_never(root_value)
@@ -596,29 +583,8 @@ def _get_attribute_from_subclass(
596583
) -> Value:
597584
ctx.record_attr_read(typ)
598585

599-
if isinstance(self_value, SubclassValue) and isinstance(
600-
self_value.typ, TypeVarValue
601-
):
602-
can_assign_ctx = ctx.get_can_assign_context()
603-
type_object = can_assign_ctx.make_type_object(typ)
604-
symbol = type_object.get_declared_symbol_from_mro(ctx.attr, can_assign_ctx)
605-
if symbol is not None:
606-
uses_self = (
607-
symbol.annotation is not None
608-
and _contains_self_typevar(symbol.annotation)
609-
) or (
610-
symbol.initializer is not None
611-
and _contains_self_typevar(symbol.initializer)
612-
)
613-
if uses_self or symbol.is_classmethod:
614-
attribute = _get_type_object_attribute(
615-
type_object, ctx.attr, ctx, on_class=True, receiver_value=self_value
616-
)
617-
if attribute is not None:
618-
ctx.record_usage(typ, attribute.value)
619-
return attribute.value
620-
621586
# First check values that are special in Python
587+
# TODO: remove these eventually, they should be handled by TypeObject.get_attribute
622588
if ctx.attr == "__class__":
623589
return KnownValue(type(typ))
624590
elif ctx.attr == "__dict__":
@@ -641,23 +607,8 @@ def _get_attribute_from_subclass(
641607
)
642608
if attribute is None:
643609
return UNINITIALIZED_VALUE
644-
# TODO: If we unconditionally use attribute.value here, some tests fail:
645-
# pycroscope/test_name_check_visitor.py::TestImportFailureHandlingCodeSamples
646-
# pycroscope/test_operations.py::TestBinOps::test_enum_flag_binop
647-
if _should_use_resolved_class_attribute(attribute):
648-
ctx.record_usage(typ, attribute.value)
649-
return attribute.value
650-
result, provider, should_unwrap = _get_attribute_from_mro(typ, ctx, on_class=True)
651-
if result is UNINITIALIZED_VALUE:
652-
return result
653-
if should_unwrap:
654-
result = _unwrap_value_from_subclass(result, ctx)
655-
if isinstance(self_value, GenericValue):
656-
result = _substitute_typevars(typ, self_value.args, result, provider, ctx)
657-
assert safe_isinstance(provider, type)
658-
result = set_self(result, self_value, provider)
659-
ctx.record_usage(typ, result)
660-
return result
610+
ctx.record_usage(typ, attribute.value)
611+
return attribute.value
661612

662613

663614
_TCAA = Callable[[object], bool]
@@ -763,8 +714,6 @@ def _get_attribute_from_synthetic_typed_value(
763714
root_value: TypedValue, ctx: AttrContext
764715
) -> Value:
765716
"""Resolve a synthetic instance attribute via ``TypeObject.get_attribute()``."""
766-
if not isinstance(root_value.typ, str):
767-
return UNINITIALIZED_VALUE
768717
can_assign_ctx = ctx.get_can_assign_context()
769718
type_object = can_assign_ctx.make_type_object(root_value.typ)
770719
attribute = _get_type_object_attribute(
@@ -795,8 +744,9 @@ def _get_instance_lookup_receiver(ctx: AttrContext) -> Value | None:
795744

796745

797746
def _get_attribute_from_synthetic_class(
798-
fq_name: str, self_value: Value, ctx: AttrContext, runtime_type: type | None = None
747+
class_key: type | str, self_value: Value, ctx: AttrContext
799748
) -> Value:
749+
# TODO: shouldn't be needed, should be handled by TypeObject.get_attribute
800750
# First check values that are special in Python.
801751
if ctx.attr == "__class__":
802752
return KnownValue(type)
@@ -805,63 +755,15 @@ def _get_attribute_from_synthetic_class(
805755
assert isinstance(self_value, SyntheticClassObjectValue)
806756
can_assign_ctx = ctx.get_can_assign_context()
807757
attribute = _get_type_object_attribute(
808-
can_assign_ctx.make_type_object(fq_name),
758+
can_assign_ctx.make_type_object(class_key),
809759
ctx.attr,
810760
ctx,
811761
on_class=True,
812762
receiver_value=self_value,
813763
)
814764
if attribute is None:
815765
return UNINITIALIZED_VALUE
816-
# If we always use attribute.value these tests fail:
817-
# pycroscope/test_enum.py::TestEnum::test_enum_value_literals_on_class_and_instance
818-
# pycroscope/test_typeshed.py::TestConstructors::test_init_new
819-
# TODO: figure it out
820-
if _should_use_resolved_class_attribute(attribute):
821-
return attribute.value
822-
result = _get_attribute_from_synthetic_class_inner(
823-
fq_name, self_value, ctx, seen={id(self_value)}
824-
)
825-
if result is UNINITIALIZED_VALUE:
826-
tobj = ctx.get_can_assign_context().make_type_object(fq_name)
827-
if tobj.has_any_base():
828-
return AnyValue(AnySource.from_another)
829-
return result
830-
return set_self(result, self_value.class_type)
831-
832-
833-
def _get_attribute_from_synthetic_class_inner(
834-
fq_name: str,
835-
self_value: SyntheticClassObjectValue,
836-
ctx: AttrContext,
837-
*,
838-
seen: set[int],
839-
) -> Value:
840-
direct = _get_direct_attribute_from_synthetic_class(self_value, ctx.attr, ctx)
841-
if direct is not UNINITIALIZED_VALUE:
842-
direct = dataclass_helpers.maybe_resolve_synthetic_descriptor_attribute(
843-
self_value,
844-
ctx.attr,
845-
direct,
846-
ctx,
847-
on_class=True,
848-
descriptor_get_type=_synthetic_descriptor_get_type,
849-
)
850-
return direct
851-
if _is_instance_only_enum_attr(self_value.class_type, ctx.attr):
852-
return UNINITIALIZED_VALUE
853-
854-
tobj = ctx.get_can_assign_context().make_type_object(self_value.class_type.typ)
855-
if not tobj.has_stubs():
856-
for base in tobj.get_direct_bases():
857-
result = _get_attribute_from_synthetic_base(
858-
base, self_value, ctx, seen=seen
859-
)
860-
if result is not UNINITIALIZED_VALUE:
861-
return result
862-
863-
result, _ = ctx.get_attribute_from_typeshed_recursively(fq_name, on_class=True)
864-
return result
766+
return attribute.value
865767

866768

867769
def _get_direct_attribute_from_synthetic_class(
@@ -936,17 +838,6 @@ def _should_use_resolved_instance_attribute(attribute: TypeObjectAttribute) -> b
936838
return attribute.value != attribute.declared_value
937839

938840

939-
def _should_use_resolved_class_attribute(attribute: TypeObjectAttribute) -> bool:
940-
symbol = attribute.symbol
941-
return (
942-
attribute.is_metaclass_owner
943-
or attribute.is_property
944-
or symbol.is_classmethod
945-
or symbol.annotation is not None
946-
or (not symbol.is_method and not attribute.owner.is_enum())
947-
)
948-
949-
950841
def _maybe_use_resolved_typed_instance_attribute(
951842
attribute: TypeObjectAttribute,
952843
*,
@@ -974,6 +865,10 @@ def _maybe_use_resolved_typed_instance_attribute(
974865
and not symbol.is_initvar
975866
and not symbol.is_method
976867
):
868+
# Need this because of:
869+
# pycroscope/test_namedtuple.py::TestNamedTuple
870+
# ::test_specialized_namedtuple_base_after_import_failure
871+
# TODO: something wrong here with generic namedtuples?
977872
if _contains_typevar(attribute.value):
978873
return None
979874
if (
@@ -1048,6 +943,7 @@ def _synthetic_descriptor_method_match(
1048943
return selected, 0
1049944
# Synthetic dunder methods are often exposed unbound; retry with the
1050945
# descriptor value as an explicit first argument.
946+
# TODO: this is a hack, fix it at the source instead.
1051947
selected = _select_matching_synthetic_signature(signature, [descriptor, *args], ctx)
1052948
if selected is None:
1053949
return None
@@ -1183,15 +1079,6 @@ def _normalize_synthetic_class_attribute(
11831079
)
11841080

11851081

1186-
def _is_instance_only_enum_attr(value: Value, attr_name: str) -> bool:
1187-
class_type = replace_fallback(value)
1188-
if not isinstance(class_type, TypedValue) or not isinstance(class_type.typ, type):
1189-
return False
1190-
if not safe_issubclass(class_type.typ, Enum):
1191-
return False
1192-
return isinstance(Enum.__dict__.get(attr_name), _ENUM_INSTANCE_DESCRIPTOR_TYPES)
1193-
1194-
11951082
def _should_deliteralize_synthetic_enum_attr(
11961083
self_value: SyntheticClassObjectValue, attr_name: str, ctx: AttrContext
11971084
) -> bool:
@@ -1245,107 +1132,6 @@ def _deliteralize_simple_value(value: SimpleType) -> Value:
12451132
assert_never(value)
12461133

12471134

1248-
def _get_attribute_from_synthetic_base(
1249-
base: Value,
1250-
self_value: SyntheticClassObjectValue,
1251-
ctx: AttrContext,
1252-
*,
1253-
seen: set[int],
1254-
) -> Value:
1255-
if (
1256-
isinstance(base, PartialValue)
1257-
and base.operation is PartialValueOperation.SUBSCRIPT
1258-
):
1259-
runtime_value = replace_fallback(base.runtime_value)
1260-
if isinstance(runtime_value, GenericValue):
1261-
base = runtime_value
1262-
else:
1263-
root = replace_fallback(base.root)
1264-
members = tuple(base.members)
1265-
if isinstance(root, SyntheticClassObjectValue):
1266-
class_type = root.class_type
1267-
base = GenericValue(class_type.typ, members)
1268-
elif isinstance(root, KnownValue) and isinstance(root.val, type):
1269-
base = GenericValue(root.val, members)
1270-
elif isinstance(root, TypedValue):
1271-
base = GenericValue(root.typ, members)
1272-
1273-
base = replace_fallback(base)
1274-
1275-
if isinstance(base, GenericValue):
1276-
if isinstance(base.typ, str):
1277-
synthetic_base = ctx.get_synthetic_class(base.typ)
1278-
if synthetic_base is not None:
1279-
base_id = id(synthetic_base)
1280-
if base_id not in seen:
1281-
seen_with_base = {*seen, base_id}
1282-
result = _get_attribute_from_synthetic_class_inner(
1283-
base.typ, synthetic_base, ctx, seen=seen_with_base
1284-
)
1285-
if result is not UNINITIALIZED_VALUE:
1286-
return _substitute_typevars(
1287-
base.typ, base.args, result, base.typ, ctx
1288-
)
1289-
result, provider = ctx.get_attribute_from_typeshed_recursively(
1290-
base.typ, on_class=True
1291-
)
1292-
if result is not UNINITIALIZED_VALUE:
1293-
return _substitute_typevars(base.typ, base.args, result, provider, ctx)
1294-
return UNINITIALIZED_VALUE
1295-
elif isinstance(base.typ, type):
1296-
result = _get_attribute_from_subclass(base.typ, self_value.class_type, ctx)
1297-
if result is not UNINITIALIZED_VALUE:
1298-
return _substitute_typevars(base.typ, base.args, result, base.typ, ctx)
1299-
return result
1300-
else:
1301-
assert_never(base.typ)
1302-
1303-
if isinstance(base, SyntheticClassObjectValue):
1304-
base_id = id(base)
1305-
if base_id in seen:
1306-
return UNINITIALIZED_VALUE
1307-
seen_with_base = {*seen, base_id}
1308-
if isinstance(base.class_type, TypedDictValue):
1309-
return _get_attribute_from_subclass(dict, self_value.class_type, ctx)
1310-
if isinstance(base.class_type.typ, str):
1311-
return _get_attribute_from_synthetic_class_inner(
1312-
base.class_type.typ, base, ctx, seen=seen_with_base
1313-
)
1314-
return _get_attribute_from_subclass(
1315-
base.class_type.typ, self_value.class_type, ctx
1316-
)
1317-
1318-
if isinstance(base, KnownValue):
1319-
if isinstance(base.val, type):
1320-
return _get_attribute_from_subclass(base.val, self_value.class_type, ctx)
1321-
origin = get_origin(base.val)
1322-
if isinstance(origin, type):
1323-
return _get_attribute_from_subclass(origin, self_value.class_type, ctx)
1324-
1325-
if isinstance(base, TypedValue):
1326-
if isinstance(base.typ, str):
1327-
synthetic_base = ctx.get_synthetic_class(base.typ)
1328-
if synthetic_base is not None:
1329-
base_id = id(synthetic_base)
1330-
if base_id not in seen:
1331-
seen_with_base = {*seen, base_id}
1332-
result = _get_attribute_from_synthetic_class_inner(
1333-
base.typ, synthetic_base, ctx, seen=seen_with_base
1334-
)
1335-
if result is not UNINITIALIZED_VALUE:
1336-
return result
1337-
result, _ = ctx.get_attribute_from_typeshed_recursively(
1338-
base.typ, on_class=True
1339-
)
1340-
return result
1341-
return _get_attribute_from_subclass(base.typ, self_value.class_type, ctx)
1342-
1343-
if isinstance(base, AnyValue):
1344-
return AnyValue(AnySource.from_another)
1345-
1346-
return UNINITIALIZED_VALUE
1347-
1348-
13491135
def _contains_self_typevar(value: Value) -> bool:
13501136
if isinstance(value, KnownValueWithTypeVars) and any(
13511137
type_param.is_self for type_param, _ in value.typevars.iter_typevars()

pycroscope/checker.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2848,13 +2848,6 @@ def resolve_name_from_typeshed(self, module: str, name: str) -> Value:
28482848
def get_attribute_from_typeshed(self, typ: type, *, on_class: bool) -> Value:
28492849
return self.checker.ts_finder.get_attribute(typ, self.attr, on_class=on_class)
28502850

2851-
def get_attribute_from_typeshed_recursively(
2852-
self, fq_name: str, *, on_class: bool
2853-
) -> tuple[Value, type | str]:
2854-
return self.checker.ts_finder.get_attribute_recursively(
2855-
fq_name, self.attr, on_class=on_class
2856-
)
2857-
28582851
def should_ignore_none_attributes(self) -> bool:
28592852
return False
28602853

pycroscope/type_object.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,6 @@ class TypeObject:
531531
_resolving_synthetic_namedtuple_class: bool
532532
_is_universally_assignable: bool | None
533533
_protocol_positive_cache: dict[tuple[Value, Value], BoundsMap]
534-
_has_stubs: bool | None
535534
_metaclass: MroValue | None
536535

537536
def __init__(self, checker: "pycroscope.checker.Checker", typ: type | str) -> None:
@@ -560,14 +559,8 @@ def __init__(self, checker: "pycroscope.checker.Checker", typ: type | str) -> No
560559
self._computing_namedtuple_data = False
561560
self._resolving_synthetic_namedtuple_class = False
562561
self._is_universally_assignable = None
563-
self._has_stubs = None
564562
self._metaclass = None
565563

566-
def has_stubs(self) -> bool:
567-
if self._has_stubs is None:
568-
self._has_stubs = self._checker.ts_finder.has_stubs(self.typ)
569-
return self._has_stubs
570-
571564
def has_any_base(self) -> bool:
572565
return any(entry.is_any for entry in self.get_mro())
573566

@@ -1338,7 +1331,7 @@ def is_enum(self) -> bool:
13381331
return self.is_assignable_to_type(enum.Enum)
13391332

13401333
def get_enum_value_type(self) -> Value | None:
1341-
if not self.is_assignable_to_type(enum.Enum):
1334+
if not self.is_enum():
13421335
return None
13431336

13441337
values: list[Value] = []

0 commit comments

Comments
 (0)