示例#1
0
def _astroid_bootstrapping():
    """astroid bootstrapping the builtins module"""
    # this boot strapping is necessary since we need the Const nodes to
    # inspect_build builtins, and then we can proxy Const
    builder = InspectBuilder()
    astroid_builtin = builder.inspect_build(builtins)

    # pylint: disable=redefined-outer-name
    for cls, node_cls in node_classes.CONST_CLS.items():
        if cls is TYPE_NONE:
            proxy = build_class("NoneType")
            proxy.parent = astroid_builtin
        elif cls is TYPE_NOTIMPLEMENTED:
            proxy = build_class("NotImplementedType")
            proxy.parent = astroid_builtin
        elif cls is TYPE_ELLIPSIS:
            proxy = build_class("Ellipsis")
            proxy.parent = astroid_builtin
        else:
            proxy = astroid_builtin.getattr(cls.__name__)[0]
        if cls in (dict, list, set, tuple):
            node_cls._proxied = proxy
        else:
            _CONST_PROXY[cls] = proxy

    # Set the builtin module as parent for some builtins.
    nodes.Const._proxied = property(_set_proxied)

    _GeneratorType = nodes.ClassDef(types.GeneratorType.__name__,
                                    types.GeneratorType.__doc__)
    _GeneratorType.parent = astroid_builtin
    bases.Generator._proxied = _GeneratorType
    builder.object_build(bases.Generator._proxied, types.GeneratorType)

    if hasattr(types, "AsyncGeneratorType"):
        # pylint: disable=no-member; AsyncGeneratorType
        _AsyncGeneratorType = nodes.ClassDef(types.AsyncGeneratorType.__name__,
                                             types.AsyncGeneratorType.__doc__)
        _AsyncGeneratorType.parent = astroid_builtin
        bases.AsyncGenerator._proxied = _AsyncGeneratorType
        builder.object_build(bases.AsyncGenerator._proxied,
                             types.AsyncGeneratorType)
    builtin_types = (
        types.GetSetDescriptorType,
        types.GeneratorType,
        types.MemberDescriptorType,
        TYPE_NONE,
        TYPE_NOTIMPLEMENTED,
        types.FunctionType,
        types.MethodType,
        types.BuiltinFunctionType,
        types.ModuleType,
        types.TracebackType,
    )
    for _type in builtin_types:
        if _type.__name__ not in astroid_builtin:
            cls = nodes.ClassDef(_type.__name__, _type.__doc__)
            cls.parent = astroid_builtin
            builder.object_build(cls, _type)
            astroid_builtin[_type.__name__] = cls
示例#2
0
def transform_model(cls) -> None:
    """
    Anything that uses the ModelMeta needs _meta and id.
    Also keep track of relationships and make them in the related model class.
    """
    if cls.name != 'Model':
        appname = 'models'
        for mcls in cls.get_children():
            if isinstance(mcls, ClassDef):
                for attr in mcls.get_children():
                    if isinstance(attr, Assign):
                        if attr.targets[0].name == 'app':
                            appname = attr.value.value

        mname = '{}.{}'.format(appname, cls.name)
        MODELS[mname] = cls

        for relname, relval in FUTURE_RELATIONS.get(mname, []):
            cls.locals[relname] = relval

        for attr in cls.get_children():
            if isinstance(attr, Assign):
                try:
                    attrname = attr.value.func.attrname
                except AttributeError:
                    pass
                else:
                    if attrname in ['ForeignKeyField', 'ManyToManyField']:
                        tomodel = attr.value.args[0].value
                        relname = ''
                        if attr.value.keywords:
                            for keyword in attr.value.keywords:
                                if keyword.arg == 'related_name':
                                    relname = keyword.value.value

                        if relname:
                            # Injected model attributes need to also have the relation manager
                            if attrname == 'ManyToManyField':
                                relval = [
                                    attr.value.func,
                                    MANAGER.ast_from_module_name('tortoise.fields')
                                    .lookup('ManyToManyRelationManager')[1][0]
                                ]
                            else:
                                relval = [
                                    attr.value.func,
                                    MANAGER.ast_from_module_name('tortoise.fields')
                                    .lookup('RelationQueryContainer')[1][0]
                                ]

                            if tomodel in MODELS:
                                MODELS[tomodel].locals[relname] = relval
                            else:
                                FUTURE_RELATIONS.setdefault(tomodel, []).append((relname, relval))

    cls.locals['_meta'] = [
        MANAGER.ast_from_module_name('tortoise.models').lookup('MetaInfo')[1][0].instantiate_class()
    ]
    if 'id' not in cls.locals:
        cls.locals['id'] = [nodes.ClassDef('id', None)]
示例#3
0
 def visit_classdef(self, node, parent, newstyle=True):
     """visit a ClassDef node to become astroid"""
     node, doc = self._get_doc(node)
     newnode = nodes.ClassDef(node.name, doc, node.lineno, node.col_offset,
                              parent)
     metaclass = None
     for keyword in node.keywords:
         if keyword.arg == "metaclass":
             metaclass = self.visit(keyword, newnode).value
             break
     if node.decorator_list:
         decorators = self.visit_decorators(node, newnode)
     else:
         decorators = None
     newnode.postinit(
         [self.visit(child, newnode) for child in node.bases],
         [self.visit(child, newnode) for child in node.body],
         decorators,
         newstyle,
         metaclass,
         [
             self.visit(kwd, newnode)
             for kwd in node.keywords if kwd.arg != "metaclass"
         ],
     )
     return newnode
示例#4
0
def build_class(name, basenames=(), doc=None):
    """create and initialize an astroid ClassDef node"""
    node = nodes.ClassDef(name, doc)
    for base in basenames:
        basenode = nodes.Name(name=base)
        node.bases.append(basenode)
        basenode.parent = node
    return node
def infer_func_form(node, base_type, context=None, enum=False):
    """Specific inference function for namedtuple or Python 3 enum. """
    # node is a Call node, class name as first argument and generated class
    # attributes as second argument

    # namedtuple or enums list of attributes can be a list of strings or a
    # whitespace-separate string
    try:
        name, names = _find_func_form_arguments(node, context)
        try:
            attributes = names.value.replace(',', ' ').split()
        except AttributeError:
            if not enum:
                attributes = [_infer_first(const, context).value
                              for const in names.elts]
            else:
                # Enums supports either iterator of (name, value) pairs
                # or mappings.
                # TODO: support only list, tuples and mappings.
                if hasattr(names, 'items') and isinstance(names.items, list):
                    attributes = [_infer_first(const[0], context).value
                                  for const in names.items
                                  if isinstance(const[0], nodes.Const)]
                elif hasattr(names, 'elts'):
                    # Enums can support either ["a", "b", "c"]
                    # or [("a", 1), ("b", 2), ...], but they can't
                    # be mixed.
                    if all(isinstance(const, nodes.Tuple)
                           for const in names.elts):
                        attributes = [_infer_first(const.elts[0], context).value
                                      for const in names.elts
                                      if isinstance(const, nodes.Tuple)]
                    else:
                        attributes = [_infer_first(const, context).value
                                      for const in names.elts]
                else:
                    raise AttributeError
                if not attributes:
                    raise AttributeError
    except (AttributeError, exceptions.InferenceError):
        raise UseInferenceDefault()

    # If we can't infer the name of the class, don't crash, up to this point
    # we know it is a namedtuple anyway.
    name = name or 'Uninferable'
    # we want to return a Class node instance with proper attributes set
    class_node = nodes.ClassDef(name, 'docstring')
    class_node.parent = node.parent
    # set base class=tuple
    class_node.bases.append(base_type)
    # XXX add __init__(*attributes) method
    for attr in attributes:
        fake_node = nodes.EmptyNode()
        fake_node.parent = class_node
        fake_node.attrname = attr
        class_node.instance_attrs[attr] = [fake_node]
    return class_node, name, attributes
示例#6
0
def infer_typing_alias(
    node: nodes.Call,
    ctx: context.InferenceContext = None
) -> typing.Optional[node_classes.NodeNG]:
    """
    Infers the call to _alias function

    :param node: call node
    :param context: inference context
    """
    if not isinstance(node, nodes.Call):
        return None
    res = next(node.args[0].infer(context=ctx))

    if res != astroid.Uninferable and isinstance(res, nodes.ClassDef):
        class_def = nodes.ClassDef(
            name=f"{res.name}_typing",
            lineno=0,
            col_offset=0,
            parent=res.parent,
        )
        class_def.postinit(
            bases=[res],
            body=res.body,
            decorators=res.decorators,
            metaclass=create_typing_metaclass(),
        )
        return class_def

    if len(node.args) == 2 and isinstance(node.args[0], nodes.Attribute):
        class_def = nodes.ClassDef(
            name=node.args[0].attrname,
            lineno=0,
            col_offset=0,
            parent=node.parent,
        )
        class_def.postinit(bases=[],
                           body=[],
                           decorators=None,
                           metaclass=create_typing_metaclass())
        return class_def

    return None
示例#7
0
def infer_typedDict(  # pylint: disable=invalid-name
    node: nodes.FunctionDef, ctx: context.InferenceContext = None
) -> typing.Iterator[nodes.ClassDef]:
    """Replace TypedDict FunctionDef with ClassDef."""
    class_def = nodes.ClassDef(
        name="TypedDict",
        lineno=node.lineno,
        col_offset=node.col_offset,
        parent=node.parent,
    )
    return iter([class_def])
示例#8
0
def infer_pattern_match(node: nodes.Call, ctx: context.InferenceContext = None):
    """Infer re.Pattern and re.Match as classes. For PY39+ add `__class_getitem__`."""
    class_def = nodes.ClassDef(
        name=node.parent.targets[0].name,
        lineno=node.lineno,
        col_offset=node.col_offset,
        parent=node.parent,
    )
    if PY39:
        func_to_add = astroid.extract_node(CLASS_GETITEM_TEMPLATE)
        class_def.locals["__class_getitem__"] = [func_to_add]
    return iter([class_def])
示例#9
0
def build_class(name: str,
                basenames: Iterable[str] = (),
                doc: str | None = None) -> nodes.ClassDef:
    """Create and initialize an astroid ClassDef node."""
    node = nodes.ClassDef(name)
    node.postinit(
        bases=[nodes.Name(name=base, parent=node) for base in basenames],
        body=[],
        decorators=None,
        doc_node=nodes.Const(value=doc) if doc else None,
    )
    return node
示例#10
0
def infer_typedDict(  # pylint: disable=invalid-name
    node: nodes.FunctionDef, ctx: context.InferenceContext = None
) -> None:
    """Replace TypedDict FunctionDef with ClassDef."""
    class_def = nodes.ClassDef(
        name="TypedDict",
        doc=node.doc,
        lineno=node.lineno,
        col_offset=node.col_offset,
        parent=node.parent,
    )
    class_def.postinit(bases=[], body=[], decorators=None)
    node.root().locals["TypedDict"] = [class_def]
示例#11
0
def infer_tuple_alias(
    node: nodes.Call, ctx: context.InferenceContext = None
) -> typing.Iterator[nodes.ClassDef]:
    """Infer call to tuple alias as new subscriptable class typing.Tuple."""
    res = next(node.args[0].infer(context=ctx))
    class_def = nodes.ClassDef(
        name="Tuple",
        parent=node.parent,
    )
    class_def.postinit(bases=[res], body=[], decorators=None)
    func_to_add = astroid.extract_node(CLASS_GETITEM_TEMPLATE)
    class_def.locals["__class_getitem__"] = [func_to_add]
    return iter([class_def])
示例#12
0
 def visit_classdef(self, node, parent, assign_ctx=None):
     """visit a Class node to become astroid"""
     newnode = new.ClassDef(node.name, None)
     _lineno_parent(node, newnode, parent)
     _init_set_doc(node, newnode)
     newnode.bases = [self.visit(child, newnode, assign_ctx)
                      for child in node.bases]
     newnode.body = [self.visit(child, newnode, assign_ctx)
                     for child in node.body]
     if node.decorator_list:
         newnode.decorators = self.visit_decorators(node, newnode, assign_ctx)
     newnode.parent.frame().set_local(newnode.name, newnode)
     return newnode
示例#13
0
def infer_namespace(node, context=None):
    callsite = arguments.CallSite.from_call(node, context=context)
    if not callsite.keyword_arguments:
        # Cannot make sense of it.
        raise UseInferenceDefault()

    class_node = nodes.ClassDef("Namespace", "docstring")
    class_node.parent = node.parent
    for attr in set(callsite.keyword_arguments):
        fake_node = nodes.EmptyNode()
        fake_node.parent = class_node
        fake_node.attrname = attr
        class_node.instance_attrs[attr] = [fake_node]
    return iter((class_node.instantiate_class(), ))
示例#14
0
def infer_typing_alias(
    node: nodes.Call, ctx: context.InferenceContext = None
) -> typing.Iterator[nodes.ClassDef]:
    """
    Infers the call to _alias function
    Insert ClassDef, with same name as aliased class,
    in mro to simulate _GenericAlias.

    :param node: call node
    :param context: inference context
    """
    if (
        not isinstance(node.parent, nodes.Assign)
        or not len(node.parent.targets) == 1
        or not isinstance(node.parent.targets[0], nodes.AssignName)
    ):
        return None
    res = next(node.args[0].infer(context=ctx))
    assign_name = node.parent.targets[0]

    class_def = nodes.ClassDef(
        name=assign_name.name,
        lineno=assign_name.lineno,
        col_offset=assign_name.col_offset,
        parent=node.parent,
    )
    if res != astroid.Uninferable and isinstance(res, nodes.ClassDef):
        # Only add `res` as base if it's a `ClassDef`
        # This isn't the case for `typing.Pattern` and `typing.Match`
        class_def.postinit(bases=[res], body=[], decorators=None)

    maybe_type_var = node.args[1]
    if (
        not PY39
        and not (
            isinstance(maybe_type_var, node_classes.Tuple) and not maybe_type_var.elts
        )
        or PY39
        and isinstance(maybe_type_var, nodes.Const)
        and maybe_type_var.value > 0
    ):
        # If typing alias is subscriptable, add `__class_getitem__` to ClassDef
        func_to_add = astroid.extract_node(CLASS_GETITEM_TEMPLATE)
        class_def.locals["__class_getitem__"] = [func_to_add]
    else:
        # If not, make sure that `__class_getitem__` access is forbidden.
        # This is an issue in cases where the aliased class implements it,
        # but the typing alias isn't subscriptable. E.g., `typing.ByteString` for PY39+
        _forbid_class_getitem_access(class_def)
    return iter([class_def])
示例#15
0
def create_typing_metaclass():
    #  Needs to mock the __getitem__ class method so that
    #  MutableSet[T] is acceptable
    func_to_add = extract_node(GET_ITEM_TEMPLATE)

    abc_meta = next(extract_node(ABC_METACLASS_TEMPLATE).infer())
    typing_meta = nodes.ClassDef(
        name="ABCMeta_typing",
        lineno=abc_meta.lineno,
        col_offset=abc_meta.col_offset,
        parent=abc_meta.parent,
    )
    typing_meta.postinit(
        bases=[extract_node(ABC_METACLASS_TEMPLATE)], body=[], decorators=None
    )
    typing_meta.locals["__getitem__"] = [func_to_add]
    return typing_meta
示例#16
0
def _astroid_bootstrapping():
    """astroid bootstrapping the builtins module"""
    # this boot strapping is necessary since we need the Const nodes to
    # inspect_build builtins, and then we can proxy Const
    builder = InspectBuilder()
    astroid_builtin = builder.inspect_build(builtins)

    for cls, node_cls in node_classes.CONST_CLS.items():
        if cls is TYPE_NONE:
            proxy = build_class("NoneType")
            proxy.parent = astroid_builtin
        elif cls is TYPE_NOTIMPLEMENTED:
            proxy = build_class("NotImplementedType")
            proxy.parent = astroid_builtin
        elif cls is TYPE_ELLIPSIS:
            proxy = build_class("Ellipsis")
            proxy.parent = astroid_builtin
        else:
            proxy = astroid_builtin.getattr(cls.__name__)[0]
            assert isinstance(proxy, nodes.ClassDef)
        if cls in (dict, list, set, tuple):
            node_cls._proxied = proxy
        else:
            _CONST_PROXY[cls] = proxy

    # Set the builtin module as parent for some builtins.
    nodes.Const._proxied = property(_set_proxied)

    _GeneratorType = nodes.ClassDef(types.GeneratorType.__name__)
    _GeneratorType.parent = astroid_builtin
    generator_doc_node = (nodes.Const(value=types.GeneratorType.__doc__)
                          if types.GeneratorType.__doc__ else None)
    _GeneratorType.postinit(
        bases=[],
        body=[],
        decorators=None,
        doc_node=generator_doc_node,
    )
    bases.Generator._proxied = _GeneratorType
    builder.object_build(bases.Generator._proxied, types.GeneratorType)

    if hasattr(types, "AsyncGeneratorType"):
        _AsyncGeneratorType = nodes.ClassDef(types.AsyncGeneratorType.__name__)
        _AsyncGeneratorType.parent = astroid_builtin
        async_generator_doc_node = (nodes.Const(
            value=types.AsyncGeneratorType.__doc__) if
                                    types.AsyncGeneratorType.__doc__ else None)
        _AsyncGeneratorType.postinit(
            bases=[],
            body=[],
            decorators=None,
            doc_node=async_generator_doc_node,
        )
        bases.AsyncGenerator._proxied = _AsyncGeneratorType
        builder.object_build(bases.AsyncGenerator._proxied,
                             types.AsyncGeneratorType)
    builtin_types = (
        types.GetSetDescriptorType,
        types.GeneratorType,
        types.MemberDescriptorType,
        TYPE_NONE,
        TYPE_NOTIMPLEMENTED,
        types.FunctionType,
        types.MethodType,
        types.BuiltinFunctionType,
        types.ModuleType,
        types.TracebackType,
    )
    for _type in builtin_types:
        if _type.__name__ not in astroid_builtin:
            klass = nodes.ClassDef(_type.__name__)
            klass.parent = astroid_builtin
            klass.postinit(
                bases=[],
                body=[],
                decorators=None,
                doc_node=nodes.Const(
                    value=_type.__doc__) if _type.__doc__ else None,
            )
            builder.object_build(klass, _type)
            astroid_builtin[_type.__name__] = klass
示例#17
0
            node_cls._proxied = proxy
        else:
            _CONST_PROXY[cls] = proxy


_astroid_bootstrapping()


# TODO : find a nicer way to handle this situation;
def _set_proxied(const):
    return _CONST_PROXY[const.value.__class__]


nodes.Const._proxied = property(_set_proxied)

_GeneratorType = nodes.ClassDef(types.GeneratorType.__name__,
                                types.GeneratorType.__doc__)
_GeneratorType.parent = MANAGER.astroid_cache[builtins.__name__]
bases.Generator._proxied = _GeneratorType
Astroid_BUILDER.object_build(bases.Generator._proxied, types.GeneratorType)

if hasattr(types, "AsyncGeneratorType"):
    # pylint: disable=no-member; AsyncGeneratorType
    _AsyncGeneratorType = nodes.ClassDef(types.AsyncGeneratorType.__name__,
                                         types.AsyncGeneratorType.__doc__)
    _AsyncGeneratorType.parent = MANAGER.astroid_cache[builtins.__name__]
    bases.AsyncGenerator._proxied = _AsyncGeneratorType
    Astroid_BUILDER.object_build(bases.AsyncGenerator._proxied,
                                 types.AsyncGeneratorType)
# pylint: enable=no-member

_builtins = MANAGER.astroid_cache[builtins.__name__]
示例#18
0
def infer_func_form(node, base_type, context=None, enum=False):
    """Specific inference function for namedtuple or Python 3 enum. """
    def infer_first(node):
        if node is util.Uninferable:
            raise UseInferenceDefault
        try:
            value = next(node.infer(context=context))
            if value is util.Uninferable:
                raise UseInferenceDefault()
            else:
                return value
        except StopIteration:
            raise InferenceError()

    # node is a Call node, class name as first argument and generated class
    # attributes as second argument
    if len(node.args) != 2:
        # something weird here, go back to class implementation
        raise UseInferenceDefault()
    # namedtuple or enums list of attributes can be a list of strings or a
    # whitespace-separate string
    try:
        name = infer_first(node.args[0]).value
        names = infer_first(node.args[1])
        try:
            attributes = names.value.replace(',', ' ').split()
        except AttributeError:
            if not enum:
                attributes = [infer_first(const).value for const in names.elts]
            else:
                # Enums supports either iterator of (name, value) pairs
                # or mappings.
                # TODO: support only list, tuples and mappings.
                if hasattr(names, 'items') and isinstance(names.items, list):
                    attributes = [
                        infer_first(const[0]).value for const in names.items
                        if isinstance(const[0], nodes.Const)
                    ]
                elif hasattr(names, 'elts'):
                    # Enums can support either ["a", "b", "c"]
                    # or [("a", 1), ("b", 2), ...], but they can't
                    # be mixed.
                    if all(
                            isinstance(const, nodes.Tuple)
                            for const in names.elts):
                        attributes = [
                            infer_first(const.elts[0]).value
                            for const in names.elts
                            if isinstance(const, nodes.Tuple)
                        ]
                    else:
                        attributes = [
                            infer_first(const).value for const in names.elts
                        ]
                else:
                    raise AttributeError
                if not attributes:
                    raise AttributeError
    except (AttributeError, exceptions.InferenceError):
        raise UseInferenceDefault()
    # we want to return a Class node instance with proper attributes set
    class_node = nodes.ClassDef(name, 'docstring')
    class_node.parent = node.parent
    # set base class=tuple
    class_node.bases.append(base_type)
    # XXX add __init__(*attributes) method
    for attr in attributes:
        fake_node = nodes.EmptyNode()
        fake_node.parent = class_node
        fake_node.attrname = attr
        class_node.instance_attrs[attr] = [fake_node]
    return class_node, name, attributes
示例#19
0
def transform_model(cls: ClassDef) -> None:
    """
    Anything that uses the ModelMeta needs _meta and id.
    Also keep track of relationships and make them in the related model class.
    """
    if cls.name != "Model":
        appname = "models"
        for mcls in cls.get_children():
            if isinstance(mcls, ClassDef):
                for attr in mcls.get_children():
                    if isinstance(attr,
                                  Assign) and attr.targets[0].name == "app":
                        appname = attr.value.value

        mname = f"{appname}.{cls.name}"
        MODELS[mname] = cls

        for relname, relval in FUTURE_RELATIONS.get(mname, []):
            cls.locals[relname] = relval

        for attr in cls.get_children():
            if isinstance(attr, (Assign, AnnAssign)):
                try:
                    attrname = attr.value.func.attrname
                except AttributeError:
                    pass
                else:
                    if attrname in [
                            "OneToOneField", "ForeignKeyField",
                            "ManyToManyField"
                    ]:
                        tomodel = attr.value.args[0].value
                        relname = ""
                        if attr.value.keywords:
                            for keyword in attr.value.keywords:
                                if keyword.arg == "related_name":
                                    relname = keyword.value.value

                        if not relname:
                            relname = cls.name.lower() + "s"

                        # Injected model attributes need to also have the relation manager
                        if attrname == "ManyToManyField":
                            relval = [
                                # attr.value.func,
                                MANAGER.ast_from_module_name(
                                    "tortoise.fields.relational").lookup(
                                        "ManyToManyFieldInstance")[1][0],
                                MANAGER.ast_from_module_name(
                                    "tortoise.fields.relational").lookup(
                                        "ManyToManyRelation")[1][0],
                            ]
                        elif attrname == "ForeignKeyField":
                            relval = [
                                MANAGER.ast_from_module_name(
                                    "tortoise.fields.relational").lookup(
                                        "ForeignKeyFieldInstance")[1][0],
                                MANAGER.ast_from_module_name(
                                    "tortoise.fields.relational").lookup(
                                        "ReverseRelation")[1][0],
                            ]
                        elif attrname == "OneToOneField":
                            relval = [
                                MANAGER.ast_from_module_name(
                                    "tortoise.fields.relational").lookup(
                                        "OneToOneFieldInstance")[1][0],
                                MANAGER.ast_from_module_name(
                                    "tortoise.fields.relational").lookup(
                                        "OneToOneRelation")[1][0],
                            ]

                        if tomodel in MODELS:
                            MODELS[tomodel].locals[relname] = relval
                        else:
                            FUTURE_RELATIONS.setdefault(tomodel, []).append(
                                (relname, relval))

    cls.locals["_meta"] = [
        MANAGER.ast_from_module_name("tortoise.models").lookup("MetaInfo")[1]
        [0].instantiate_class()
    ]
    if "id" not in cls.locals:
        cls.locals["id"] = [nodes.ClassDef("id", None)]
示例#20
0
        from six.moves import builtins
        astroid_builtin = Astroid_BUILDER.inspect_build(builtins)

    for cls, node_cls in node_classes.CONST_CLS.items():
        if cls is type(None):
            proxy = build_class('NoneType')
            proxy.parent = astroid_builtin
        elif cls is type(NotImplemented):
            proxy = build_class('NotImplementedType')
            proxy.parent = astroid_builtin
        else:
            proxy = astroid_builtin.getattr(cls.__name__)[0]
        if cls in (dict, list, set, tuple):
            node_cls._proxied = proxy
        else:
            _CONST_PROXY[cls] = proxy

_astroid_bootstrapping()

# TODO : find a nicer way to handle this situation;
# However __proxied introduced an
# infinite recursion (see https://bugs.launchpad.net/pylint/+bug/456870)
def _set_proxied(const):
    return _CONST_PROXY[const.value.__class__]
nodes.Const._proxied = property(_set_proxied)

_GeneratorType = nodes.ClassDef(types.GeneratorType.__name__, types.GeneratorType.__doc__)
_GeneratorType.parent = MANAGER.astroid_cache[six.moves.builtins.__name__]
bases.Generator._proxied = _GeneratorType
Astroid_BUILDER.object_build(bases.Generator._proxied, types.GeneratorType)
示例#21
0
def infer_enum(node, context=None):
    """ Specific inference function for enum Call node. """
    enum_meta = nodes.ClassDef("EnumMeta", 'docstring')
    class_node = infer_func_form(node, enum_meta,
                                 context=context, enum=True)[0]
    return iter([class_node])
示例#22
0
def infer_func_form(node, base_type, context=None, enum=False):
    """Specific inference function for namedtuple or Python 3 enum."""
    # node is a Call node, class name as first argument and generated class
    # attributes as second argument

    # namedtuple or enums list of attributes can be a list of strings or a
    # whitespace-separate string
    try:
        name, names = _find_func_form_arguments(node, context)
        try:
            attributes = names.value.replace(",", " ").split()
        except AttributeError as exc:
            if not enum:
                attributes = [
                    _infer_first(const, context).value for const in names.elts
                ]
            else:
                # Enums supports either iterator of (name, value) pairs
                # or mappings.
                if hasattr(names, "items") and isinstance(names.items, list):
                    attributes = [
                        _infer_first(const[0], context).value
                        for const in names.items
                        if isinstance(const[0], nodes.Const)
                    ]
                elif hasattr(names, "elts"):
                    # Enums can support either ["a", "b", "c"]
                    # or [("a", 1), ("b", 2), ...], but they can't
                    # be mixed.
                    if all(isinstance(const, nodes.Tuple) for const in names.elts):
                        attributes = [
                            _infer_first(const.elts[0], context).value
                            for const in names.elts
                            if isinstance(const, nodes.Tuple)
                        ]
                    else:
                        attributes = [
                            _infer_first(const, context).value for const in names.elts
                        ]
                else:
                    raise AttributeError from exc
                if not attributes:
                    raise AttributeError from exc
    except (AttributeError, InferenceError) as exc:
        raise UseInferenceDefault from exc

    if not enum:
        # namedtuple maps sys.intern(str()) over over field_names
        attributes = [str(attr) for attr in attributes]
        # XXX this should succeed *unless* __str__/__repr__ is incorrect or throws
        # in which case we should not have inferred these values and raised earlier
    attributes = [attr for attr in attributes if " " not in attr]

    # If we can't infer the name of the class, don't crash, up to this point
    # we know it is a namedtuple anyway.
    name = name or "Uninferable"
    # we want to return a Class node instance with proper attributes set
    class_node = nodes.ClassDef(name, "docstring")
    class_node.parent = node.parent
    # set base class=tuple
    class_node.bases.append(base_type)
    # XXX add __init__(*attributes) method
    for attr in attributes:
        fake_node = nodes.EmptyNode()
        fake_node.parent = class_node
        fake_node.attrname = attr
        class_node.instance_attrs[attr] = [fake_node]
    return class_node, name, attributes
示例#23
0
def infer_func_form(
    node: nodes.Call,
    base_type: list[nodes.NodeNG],
    context: InferenceContext | None = None,
    enum: bool = False,
) -> tuple[nodes.ClassDef, str, list[str]]:
    """Specific inference function for namedtuple or Python 3 enum."""
    # node is a Call node, class name as first argument and generated class
    # attributes as second argument

    # namedtuple or enums list of attributes can be a list of strings or a
    # whitespace-separate string
    try:
        name, names = _find_func_form_arguments(node, context)
        try:
            attributes: list[str] = names.value.replace(",", " ").split()
        except AttributeError as exc:
            # Handle attributes of NamedTuples
            if not enum:
                attributes = []
                fields = _get_namedtuple_fields(node)
                if fields:
                    fields_node = extract_node(fields)
                    attributes = [
                        _infer_first(const, context).value
                        for const in fields_node.elts
                    ]

            # Handle attributes of Enums
            else:
                # Enums supports either iterator of (name, value) pairs
                # or mappings.
                if hasattr(names, "items") and isinstance(names.items, list):
                    attributes = [
                        _infer_first(const[0], context).value
                        for const in names.items
                        if isinstance(const[0], nodes.Const)
                    ]
                elif hasattr(names, "elts"):
                    # Enums can support either ["a", "b", "c"]
                    # or [("a", 1), ("b", 2), ...], but they can't
                    # be mixed.
                    if all(
                            isinstance(const, nodes.Tuple)
                            for const in names.elts):
                        attributes = [
                            _infer_first(const.elts[0], context).value
                            for const in names.elts
                            if isinstance(const, nodes.Tuple)
                        ]
                    else:
                        attributes = [
                            _infer_first(const, context).value
                            for const in names.elts
                        ]
                else:
                    raise AttributeError from exc
                if not attributes:
                    raise AttributeError from exc
    except (AttributeError, InferenceError) as exc:
        raise UseInferenceDefault from exc

    if not enum:
        # namedtuple maps sys.intern(str()) over over field_names
        attributes = [str(attr) for attr in attributes]
        # XXX this should succeed *unless* __str__/__repr__ is incorrect or throws
        # in which case we should not have inferred these values and raised earlier
    attributes = [attr for attr in attributes if " " not in attr]

    # If we can't infer the name of the class, don't crash, up to this point
    # we know it is a namedtuple anyway.
    name = name or "Uninferable"
    # we want to return a Class node instance with proper attributes set
    class_node = nodes.ClassDef(name)
    # A typical ClassDef automatically adds its name to the parent scope,
    # but doing so causes problems, so defer setting parent until after init
    # see: https://github.com/PyCQA/pylint/issues/5982
    class_node.parent = node.parent
    class_node.postinit(
        # set base class=tuple
        bases=base_type,
        body=[],
        decorators=None,
    )
    # XXX add __init__(*attributes) method
    for attr in attributes:
        fake_node = nodes.EmptyNode()
        fake_node.parent = class_node
        fake_node.attrname = attr
        class_node.instance_attrs[attr] = [fake_node]
    return class_node, name, attributes