def _autoconvertible_to_cdata(tp: Type, api: 'mypy.plugin.CheckerPluginInterface') -> Type: """Get a type that is compatible with all types that can be implicitly converted to the given CData type. Examples: * c_int -> Union[c_int, int] * c_char_p -> Union[c_char_p, bytes, int, NoneType] * MyStructure -> MyStructure """ allowed_types = [] # If tp is a union, we allow all types that are convertible to at least one of the union # items. This is not quite correct - strictly speaking, only types convertible to *all* of the # union items should be allowed. This may be worth changing in the future, but the more # correct algorithm could be too strict to be useful. for t in union_items(tp): # Every type can be converted from itself (obviously). allowed_types.append(t) if isinstance(t, Instance): unboxed = _find_simplecdata_base_arg(t, api) if unboxed is not None: # If _SimpleCData appears in tp's (direct or indirect) bases, its type argument # specifies the type's "unboxed" version, which can always be converted back to # the original "boxed" type. allowed_types.append(unboxed) if t.type.has_base('ctypes._PointerLike'): # Pointer-like _SimpleCData subclasses can also be converted from # an int or None. allowed_types.append(api.named_generic_type('builtins.int', [])) allowed_types.append(NoneTyp()) return UnionType.make_simplified_union(allowed_types)
def make_optional_type(t: Type) -> Type: """Return the type corresponding to Optional[t]. Note that we can't use normal union simplification, since this function is called during semantic analysis and simplification only works during type checking. """ if isinstance(t, NoneTyp): return t elif isinstance(t, UnionType): items = [item for item in union_items(t) if not isinstance(item, NoneTyp)] return UnionType(items + [NoneTyp()], t.line, t.column) else: return UnionType([t, NoneTyp()], t.line, t.column)
def make_optional_type(t: Type) -> Type: """Return the type corresponding to Optional[t]. Note that we can't use normal union simplification, since this function is called during semantic analysis and simplification only works during type checking. """ if isinstance(t, NoneTyp): return t elif isinstance(t, UnionType): items = [ item for item in union_items(t) if not isinstance(item, NoneTyp) ] return UnionType(items + [NoneTyp()], t.line, t.column) else: return UnionType([t, NoneTyp()], t.line, t.column)
def array_raw_callback(ctx: 'mypy.plugin.AttributeContext') -> Type: """Callback to provide an accurate type for ctypes.Array.raw.""" et = _get_array_element_type(ctx.type) if et is not None: types = [] # type: List[Type] for tp in union_items(et): if (isinstance(tp, AnyType) or isinstance(tp, Instance) and tp.type.fullname == 'ctypes.c_char'): types.append(_get_bytes_type(ctx.api)) else: ctx.api.msg.fail( 'Array attribute "raw" is only available' ' with element type "c_char", not {}'.format( format_type(et)), ctx.context) return make_simplified_union(types) return ctx.default_attr_type
def array_raw_callback(ctx: 'mypy.plugin.AttributeContext') -> Type: """Callback to provide an accurate type for ctypes.Array.raw.""" et = _get_array_element_type(ctx.type) if et is not None: types = [] # type: List[Type] for tp in union_items(et): if (isinstance(tp, AnyType) or isinstance(tp, Instance) and tp.type.fullname() == 'ctypes.c_char'): types.append(_get_bytes_type(ctx.api)) else: ctx.api.msg.fail( 'ctypes.Array attribute "raw" is only available' ' with element type c_char, not "{}"' .format(et), ctx.context) return UnionType.make_simplified_union(types) return ctx.default_attr_type
def array_value_callback(ctx: 'mypy.plugin.AttributeContext') -> Type: """Callback to provide an accurate type for ctypes.Array.value.""" et = _get_array_element_type(ctx.type) if et is not None: types: List[Type] = [] for tp in union_items(et): if isinstance(tp, AnyType): types.append(AnyType(TypeOfAny.from_another_any, source_any=tp)) elif isinstance(tp, Instance) and tp.type.fullname == 'ctypes.c_char': types.append(_get_bytes_type(ctx.api)) elif isinstance(tp, Instance) and tp.type.fullname == 'ctypes.c_wchar': types.append(_get_text_type(ctx.api)) else: ctx.api.msg.fail( 'Array attribute "value" is only available' ' with element type "c_char" or "c_wchar", not {}' .format(format_type(et)), ctx.context) return make_simplified_union(types) return ctx.default_attr_type
def __init__( self, associated_type: MypyType, instance_type: MypyType, ctx: MethodContext, ) -> None: """ Smart constructor for the metadata injector. It is smart, because it handles ``instance_type`` properly. It supports ``Instance`` and ``Union`` types. """ self._associated_type = associated_type self._instance_types = union_items(instance_type) self._ctx = ctx # Why do we store added types in a mutable global state? # Because, these types are hard to replicate without the proper context. # So, we just keep them here. Based on usage, it is fine. self._added_types: List[Instance] = []