MCPcopy
hub / github.com/python/mypy / analyze_descriptor_access

Function analyze_descriptor_access

mypy/checkmember.py:667–773  ·  view source on GitHub ↗

Type check descriptor access. Arguments: descriptor_type: The type of the descriptor attribute being accessed (the type of ``f`` in ``a.f`` when ``f`` is a descriptor). mx: The current member access context. Return: The return type of the appropriate ``__

(descriptor_type: Type, mx: MemberContext)

Source from the content-addressed store, hash-verified

665
666
667def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type:
668 """Type check descriptor access.
669
670 Arguments:
671 descriptor_type: The type of the descriptor attribute being accessed
672 (the type of ``f`` in ``a.f`` when ``f`` is a descriptor).
673 mx: The current member access context.
674 Return:
675 The return type of the appropriate ``__get__/__set__`` overload for the descriptor.
676 """
677 instance_type = get_proper_type(mx.self_type)
678 orig_descriptor_type = descriptor_type
679 descriptor_type = get_proper_type(descriptor_type)
680
681 if isinstance(descriptor_type, UnionType):
682 # Map the access over union types
683 return make_simplified_union(
684 [analyze_descriptor_access(typ, mx) for typ in descriptor_type.items]
685 )
686 elif not isinstance(descriptor_type, Instance):
687 return orig_descriptor_type
688
689 if not mx.is_lvalue and not descriptor_type.type.has_readable_member("__get__"):
690 return orig_descriptor_type
691
692 # We do this check first to accommodate for descriptors with only __set__ method.
693 # If there is no __set__, we type-check that the assigned value matches
694 # the return type of __get__. This doesn't match the python semantics,
695 # (which allow you to override the descriptor with any value), but preserves
696 # the type of accessing the attribute (even after the override).
697 if mx.is_lvalue and descriptor_type.type.has_readable_member("__set__"):
698 return analyze_descriptor_assign(descriptor_type, mx)
699
700 if mx.is_lvalue and not descriptor_type.type.has_readable_member("__get__"):
701 # This turned out to be not a descriptor after all.
702 return orig_descriptor_type
703
704 dunder_get = descriptor_type.type.get_method("__get__")
705 if dunder_get is None:
706 mx.fail(
707 message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(
708 descriptor_type.str_with_options(mx.msg.options)
709 )
710 )
711 return AnyType(TypeOfAny.from_error)
712
713 bound_method = analyze_decorator_or_funcbase_access(
714 defn=dunder_get,
715 itype=descriptor_type,
716 name="__get__",
717 mx=mx.copy_modified(self_type=descriptor_type),
718 )
719
720 typ = map_instance_to_supertype(descriptor_type, dunder_get.info)
721 dunder_get_type = expand_type_by_instance(bound_method, typ)
722
723 if isinstance(instance_type, FunctionLike) and instance_type.is_type_obj():
724 owner_type = instance_type.items[0].ret_type

Callers 2

analyze_varFunction · 0.85

Calls 15

get_proper_typeFunction · 0.90
make_simplified_unionFunction · 0.90
AnyTypeClass · 0.90
expand_type_by_instanceFunction · 0.90
NoneTypeClass · 0.90
TempNodeClass · 0.90
isinstanceFunction · 0.85
make_normalizedMethod · 0.80
has_readable_memberMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…