Example #1
0
def transform_type_info(context: mypy.plugin.ClassDefContext,
                        proto_type_node: TypeInfo,
                        attribute_type_node: TypeInfo, init: bool) -> TypeInfo:

    transformed_info: TypeInfo = context.cls.info

    # Get the list of proto_type class members that are not dunders or private
    names = [
        name for name in proto_type_node.names if not name.startswith('_')
    ]

    transformedNames = []

    for name in names:
        proto_node = proto_type_node.names[name]  # SymbolTableNode

        if isinstance(proto_node.node, FuncDef):
            # Ignore methods
            continue

        transformedNames.append(name)
        copied_node = proto_node.copy()  # SymbolTableNode
        copied_node.node = copy.copy(proto_node.node)  # Var

        copied_node.node._fullname = "{}.{}".format(transformed_info.fullname,
                                                    copied_node.node.name)

        copied_node.plugin_generated = True

        try:
            nestedTypeInfo = typeInfoByProtoTypeName.get(
                proto_node.node.type.type.fullname, None)
        except AttributeError:
            nestedTypeInfo = None
            if isinstance(proto_node.node.type, mypy.types.AnyType):
                # AnyType is not a transformable class anyway.
                pass
            else:
                print("Warning: Failed to check fullname of {}: {}".format(
                    name, proto_node.node.type))

        if nestedTypeInfo is not None:
            # This member's type has been transformed.
            copied_node.node.type = \
                mypy.types.Instance(nestedTypeInfo, [])
        else:
            if attribute_type_node.is_generic():
                typeArgs = [proto_node.node.type]
            else:
                typeArgs = []

            copied_node.node.type = \
                mypy.types.Instance(attribute_type_node, typeArgs)

        transformed_info.names[name] = copied_node

    protoTypeInstance = mypy.types.Instance(proto_type_node, [])

    if init:
        argument = Argument(
            Var(proto_type_node.name.lower(), protoTypeInstance),
            protoTypeInstance, None, ARG_POS)

        add_method_to_class(context.api, context.cls, "__init__", [
            argument,
        ], mypy.types.NoneType())

    add_method_to_class(context.api, context.cls, "GetProtoType", [],
                        protoTypeInstance)

    # Now that the class is built, update the info
    for name in transformedNames:
        transformed_info.names[name].node.info = transformed_info

    return transformed_info