def attach_dummy_node(node, name, runtime_object=_marker): """create a dummy node and register it in the locals of the given node with the specified name """ enode = nodes.EmptyNode() enode.object = runtime_object _attach_local_node(node, enode, name)
def _base_class_object_build(node, member, basenames, name=None, localname=None): """create astroid for a living class object, with a given set of base names (e.g. ancestors) """ klass = build_class(name or getattr(member, '__name__', None) or localname, basenames, member.__doc__) klass._newstyle = isinstance(member, type) node.add_local_node(klass, localname) try: # limit the instantiation trick since it's too dangerous # (such as infinite test execution...) # this at least resolves common case such as Exception.args, # OSError.errno if issubclass(member, Exception): instdict = member().__dict__ else: raise TypeError except: # pylint: disable=bare-except pass else: for name, obj in instdict.items(): valnode = nodes.EmptyNode() valnode.object = obj valnode.parent = klass valnode.lineno = 1 klass.instance_attrs[name] = [valnode] return klass
def _transform(cls): # fix the "no-member" error on instances of # letsencrypt.acme.util.ImmutableMap subclasses (instance # attributes are initialized dynamically based on __slots__) if (('Message' in cls.basenames or 'ImmutableMap' in cls.basenames or 'util.ImmutableMap' in cls.basenames) and (cls.slots() is not None)): for slot in cls.slots(): cls.locals[slot.value] = [nodes.EmptyNode()]
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
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(), ))
def _transform(cls): # fix the "no-member" error on instances of # letsencrypt.acme.util.ImmutableMap subclasses (instance # attributes are initialized dynamically based on __slots__) # TODO: this is too broad and applies to any tested class... #if cls.slots() is not None: # for slot in cls.slots(): # cls.locals[slot.value] = [nodes.EmptyNode()] if cls.name == 'JSONObjectWithFields': # _fields is magically introduced by JSONObjectWithFieldsMeta cls.locals['_fields'] = [nodes.EmptyNode()]
def infer_named_tuple(node, context=None): """Specific inference function for namedtuple CallFunc node""" def infer_first(node): try: value = node.infer().next() if value is YES: raise UseInferenceDefault() else: return value except StopIteration: raise InferenceError() # node is a CallFunc 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 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.split() except AttributeError: attributes = [infer_first(const).value for const in names.elts] except (AttributeError, exceptions.InferenceError): raise UseInferenceDefault() # we want to return a Class node instance with proper attributes set class_node = nodes.Class(name, 'docstring') class_node.parent = node.parent # set base class=tuple class_node.bases.append(nodes.Tuple._proxied) # XXX add __init__(*attributes) method for attr in attributes: fake_node = nodes.EmptyNode() fake_node.parent = class_node class_node.instance_attrs[attr] = [fake_node] # we use UseInferenceDefault, we can't be a generator so return an iterator return iter([class_node])
def _base_class_object_build( node: nodes.Module | nodes.ClassDef, member: type, basenames: list[str], name: str | None = None, localname: str | None = None, ) -> nodes.ClassDef: """create astroid for a living class object, with a given set of base names (e.g. ancestors) """ class_name = name or getattr(member, "__name__", None) or localname assert isinstance(class_name, str) klass = build_class( class_name, basenames, member.__doc__, ) klass._newstyle = isinstance(member, type) node.add_local_node(klass, localname) try: # limit the instantiation trick since it's too dangerous # (such as infinite test execution...) # this at least resolves common case such as Exception.args, # OSError.errno if issubclass(member, Exception): instdict = member().__dict__ else: raise TypeError except TypeError: pass else: for item_name, obj in instdict.items(): valnode = nodes.EmptyNode() valnode.object = obj valnode.parent = klass valnode.lineno = 1 klass.instance_attrs[item_name] = [valnode] return klass
def visit_emptynode(self, node, parent): """visit an EmptyNode node by returning a fresh instance of it""" return nodes.EmptyNode(getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent)
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
def visit_emptynode(self, node, parent): """visit an EmptyNode node by returning a fresh instance of it""" newnode = new.EmptyNode() _set_infos(node, newnode, parent) return newnode
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
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