|
52 | 52 | from .stacked_scopes import Composite |
53 | 53 | from .type_object import ( |
54 | 54 | AttributePolicy, |
55 | | - MroValue, |
56 | 55 | TypeObject, |
57 | 56 | TypeObjectAttribute, |
58 | 57 | _class_key_from_value, |
59 | | - _get_attribute_value_from_symbol, |
60 | 58 | _get_cached_property_return_type, |
61 | | - _is_property_marker_value, |
62 | | - _specialize_symbol_for_owner, |
63 | | - class_keys_match, |
64 | 59 | normalize_synthetic_descriptor_attribute, |
65 | 60 | ) |
66 | 61 | from .value import ( |
@@ -476,69 +471,26 @@ def _super_thisclass_key(value: Value) -> type | str | None: |
476 | 471 | return None |
477 | 472 |
|
478 | 473 |
|
479 | | -def _super_mro_values( |
480 | | - receiver_value: TypedValue, ctx: CanAssignContext |
481 | | -) -> Sequence[MroValue]: |
482 | | - # TODO: switch to just using the MRO; that currently doesn't work because it gets set too late |
483 | | - if isinstance(receiver_value.typ, type): |
484 | | - return [TypedValue(base) for base in receiver_value.typ.__mro__] |
485 | | - return [ |
486 | | - entry.get_mro_value() for entry in receiver_value.get_type_object(ctx).get_mro() |
487 | | - ] |
488 | | - |
489 | | - |
490 | | -# TODO: in principle this should be doable with TypeObject.get_attribute if we add a flag |
491 | | -# that says to skip MRO elements up to a certain point. |
492 | 474 | def _get_attribute_from_super_value(super_value: SuperValue, ctx: AttrContext) -> Value: |
493 | 475 | if super_value.selfobj is None: |
494 | 476 | return AnyValue(AnySource.inference) |
495 | 477 | receiver_value, is_class_access = _super_receiver_type_value(super_value.selfobj) |
496 | | - policy = AttributePolicy( |
497 | | - receiver=receiver_value or AnyValue(AnySource.inference), |
498 | | - on_class=is_class_access, |
499 | | - ) |
500 | 478 | thisclass_key = _super_thisclass_key(super_value.thisclass) |
501 | | - can_assign_ctx = ctx.get_can_assign_context() |
502 | 479 | if receiver_value is None or thisclass_key is None: |
503 | 480 | return AnyValue(AnySource.inference) |
504 | 481 |
|
505 | | - receiver_tobj = receiver_value.get_type_object(can_assign_ctx) |
506 | | - saw_thisclass = False |
507 | | - for mro_value in _super_mro_values(receiver_value, can_assign_ctx): |
508 | | - if isinstance(mro_value, AnyValue): |
509 | | - continue |
510 | | - owner_key = _class_key_from_value(mro_value) |
511 | | - if owner_key is None: |
512 | | - continue |
513 | | - if not saw_thisclass: |
514 | | - if class_keys_match(owner_key, thisclass_key): |
515 | | - saw_thisclass = True |
516 | | - continue |
517 | | - owner_tobj = mro_value.get_type_object(can_assign_ctx) |
518 | | - symbol = owner_tobj.get_declared_symbol(ctx.attr) |
519 | | - if symbol is not None: |
520 | | - symbol = _specialize_symbol_for_owner( |
521 | | - receiver_tobj, owner_tobj, symbol, can_assign_ctx, policy |
522 | | - ) |
523 | | - result = _get_attribute_value_from_symbol( |
524 | | - symbol, |
525 | | - can_assign_ctx, |
526 | | - on_class=is_class_access and not symbol.is_method, |
527 | | - receiver_value=receiver_value, |
528 | | - ) |
529 | | - if ( |
530 | | - is_class_access |
531 | | - and symbol.property_info is not None |
532 | | - and ( |
533 | | - result is UNINITIALIZED_VALUE |
534 | | - or not _is_property_marker_value(result) |
535 | | - ) |
536 | | - ): |
537 | | - result = TypedValue(property) |
538 | | - result = set_self(result, receiver_value, owner_tobj.typ) |
539 | | - ctx.record_usage(super, result) |
540 | | - return result |
541 | | - return UNINITIALIZED_VALUE |
| 482 | + receiver_tobj = receiver_value.get_type_object(ctx.get_can_assign_context()) |
| 483 | + policy = AttributePolicy( |
| 484 | + receiver=receiver_value, |
| 485 | + on_class=is_class_access, |
| 486 | + anchor=thisclass_key, |
| 487 | + # TODO: Maybe shouldn't be necessary, but without this some methods get inferred wrong. |
| 488 | + prefer_symbolic=True, |
| 489 | + ) |
| 490 | + attr = receiver_tobj.get_attribute(ctx.attr, policy) |
| 491 | + if attr is None: |
| 492 | + return UNINITIALIZED_VALUE |
| 493 | + return attr.value |
542 | 494 |
|
543 | 495 |
|
544 | 496 | def _get_attribute_from_type_alias(value: TypeAliasValue, ctx: AttrContext) -> Value: |
@@ -736,13 +688,6 @@ def _get_typed_instance_lookup_receiver(ctx: AttrContext) -> Value | None: |
736 | 688 | return None |
737 | 689 |
|
738 | 690 |
|
739 | | -def _get_instance_lookup_receiver(ctx: AttrContext) -> Value | None: |
740 | | - self_value = ctx.get_self_value() |
741 | | - if _contains_self_typevar(self_value): |
742 | | - return self_value |
743 | | - return _get_typed_instance_lookup_receiver(ctx) |
744 | | - |
745 | | - |
746 | 691 | def _get_attribute_from_synthetic_class( |
747 | 692 | class_key: type | str, self_value: Value, ctx: AttrContext |
748 | 693 | ) -> Value: |
@@ -1192,29 +1137,29 @@ def _get_attribute_from_typed( |
1192 | 1137 | types.BuiltinFunctionType, |
1193 | 1138 | }: |
1194 | 1139 | return GenericValue(dict, [TypedValue(str), AnyValue(AnySource.explicit)]) |
1195 | | - receiver_value = _get_instance_lookup_receiver(ctx) |
1196 | | - if receiver_value is not None: |
1197 | | - can_assign_ctx = ctx.get_can_assign_context() |
1198 | | - attribute = _get_type_object_attribute( |
1199 | | - can_assign_ctx.make_type_object(typ), |
1200 | | - ctx.attr, |
1201 | | - ctx, |
1202 | | - on_class=False, |
1203 | | - receiver_value=receiver_value, |
| 1140 | + can_assign_ctx = ctx.get_can_assign_context() |
| 1141 | + attribute = _get_type_object_attribute( |
| 1142 | + can_assign_ctx.make_type_object(typ), |
| 1143 | + ctx.attr, |
| 1144 | + ctx, |
| 1145 | + on_class=False, |
| 1146 | + receiver_value=ctx.root_composite.value, |
| 1147 | + ) |
| 1148 | + # Adding "if attribute is None: return UNINITIALIZED_VALUE" here breaks two tests: |
| 1149 | + # pycroscope/test_attributes.py::TestAttributes::test_attrs |
| 1150 | + # (missing attrs support in type_object.py?) |
| 1151 | + # TestImportFailureHandling::test_explicit_type_alias_uses_runtime_attribute_semantics |
| 1152 | + # (some weirdness about how we represent type aliases?) |
| 1153 | + if attribute is not None: |
| 1154 | + resolved_instance = _maybe_use_resolved_typed_instance_attribute( |
| 1155 | + attribute, resolved_value=attribute.value, typ=typ, ctx=ctx |
1204 | 1156 | ) |
1205 | | - if attribute is not None: |
1206 | | - resolved_value = _substitute_typevars( |
1207 | | - typ, generic_args, attribute.value, typ, ctx |
1208 | | - ) |
1209 | | - resolved_instance = _maybe_use_resolved_typed_instance_attribute( |
1210 | | - attribute, resolved_value=resolved_value, typ=typ, ctx=ctx |
1211 | | - ) |
1212 | | - if resolved_instance is not None: |
1213 | | - return resolved_instance |
| 1157 | + if resolved_instance is not None: |
| 1158 | + return resolved_instance |
1214 | 1159 | synthetic_class = ctx.get_synthetic_class(typ) |
1215 | 1160 | if synthetic_class is not None and _contains_self_typevar(ctx.get_self_value()): |
1216 | 1161 | synthetic_result = _get_direct_attribute_from_synthetic_instance( |
1217 | | - synthetic_class, ctx.attr, ctx, receiver_value=receiver_value |
| 1162 | + synthetic_class, ctx.attr, ctx, receiver_value=ctx.root_composite.value |
1218 | 1163 | ) |
1219 | 1164 | if synthetic_result is not UNINITIALIZED_VALUE: |
1220 | 1165 | synthetic_result = ( |
@@ -1425,31 +1370,43 @@ def _unwrap_value_from_typed(result: Value, typ: type, ctx: AttrContext) -> Valu |
1425 | 1370 | if ctx.attr == "__new__": |
1426 | 1371 | # __new__ is implicitly a staticmethod |
1427 | 1372 | return result |
1428 | | - return UnboundMethodValue(ctx.attr, ctx.root_composite, typevars=typevars) |
| 1373 | + return UnboundMethodValue( |
| 1374 | + ctx.attr, ctx.root_composite, typevars=typevars, owner=typ |
| 1375 | + ) |
1429 | 1376 | if isinstance(descriptor, staticmethod) or ctx.attr == "__new__": |
1430 | 1377 | return result |
1431 | 1378 | else: |
1432 | | - return UnboundMethodValue(ctx.attr, ctx.root_composite, typevars=typevars) |
| 1379 | + return UnboundMethodValue( |
| 1380 | + ctx.attr, ctx.root_composite, typevars=typevars, owner=typ |
| 1381 | + ) |
1433 | 1382 | elif isinstance(cls_val, (types.MethodType, MethodDescriptorType, SlotWrapperType)): |
1434 | 1383 | # built-in method; e.g. scope_lib.tests.SimpleDatabox.get |
1435 | | - return UnboundMethodValue(ctx.attr, ctx.root_composite, typevars=typevars) |
| 1384 | + return UnboundMethodValue( |
| 1385 | + ctx.attr, ctx.root_composite, typevars=typevars, owner=typ |
| 1386 | + ) |
1436 | 1387 | elif _static_hasattr(cls_val, "binder_cls") and _static_hasattr(cls_val, "fn"): |
1437 | 1388 | # qcore/asynq-style decorators expose a binder type on the descriptor but |
1438 | 1389 | # still behave like methods when accessed through instances. |
1439 | | - return UnboundMethodValue(ctx.attr, ctx.root_composite, typevars=typevars) |
| 1390 | + return UnboundMethodValue( |
| 1391 | + ctx.attr, ctx.root_composite, typevars=typevars, owner=typ |
| 1392 | + ) |
1440 | 1393 | elif ( |
1441 | 1394 | _static_hasattr(cls_val, "decorator") |
1442 | 1395 | and _static_hasattr(cls_val, "instance") |
1443 | 1396 | and not isinstance(cls_val.instance, type) |
1444 | 1397 | ): |
1445 | 1398 | # non-static method |
1446 | | - return UnboundMethodValue(ctx.attr, ctx.root_composite, typevars=typevars) |
| 1399 | + return UnboundMethodValue( |
| 1400 | + ctx.attr, ctx.root_composite, typevars=typevars, owner=typ |
| 1401 | + ) |
1447 | 1402 | elif is_async_fn(cls_val): |
1448 | 1403 | # static or class method |
1449 | 1404 | return result |
1450 | 1405 | elif _static_hasattr(cls_val, "func_code"): |
1451 | 1406 | # Cython function probably |
1452 | | - return UnboundMethodValue(ctx.attr, ctx.root_composite, typevars=typevars) |
| 1407 | + return UnboundMethodValue( |
| 1408 | + ctx.attr, ctx.root_composite, typevars=typevars, owner=typ |
| 1409 | + ) |
1453 | 1410 | transformed = ClassAttributeTransformer.transform_attribute(cls_val, ctx.options) |
1454 | 1411 | if transformed is not None: |
1455 | 1412 | return transformed |
@@ -1602,7 +1559,10 @@ def _get_attribute_from_unbound( |
1602 | 1559 | except AttributeError: |
1603 | 1560 | return UNINITIALIZED_VALUE |
1604 | 1561 | result = UnboundMethodValue( |
1605 | | - root_value.attr_name, root_value.composite, secondary_attr_name=ctx.attr |
| 1562 | + root_value.attr_name, |
| 1563 | + root_value.composite, |
| 1564 | + secondary_attr_name=ctx.attr, |
| 1565 | + owner=root_value.owner, |
1606 | 1566 | ) |
1607 | 1567 | ctx.record_usage(type(method), result) |
1608 | 1568 | return result |
|
0 commit comments