def _arguments_infer_argname(self, name, context): # arguments information may be missing, in which case we can't do anything # more if not (self.args or self.vararg or self.kwarg): yield YES return # first argument of instance/class method if self.args and getattr(self.args[0], 'name', None) == name: functype = self.parent.type if functype == 'method': yield Instance(self.parent.parent.frame()) return if functype == 'classmethod': yield self.parent.parent.frame() return if name == self.vararg: yield const_factory(()) return if name == self.kwarg: yield const_factory({}) return # if there is a default value, yield it. And then yield YES to reflect # we can't guess given argument value try: context = copy_context(context) for infered in self.default_value(name).infer(context): yield infered yield YES except NoDefault: yield YES
def const_infer_unary_op(self, operator): if operator == 'not': return const_factory(not self.value) # XXX log potentially raised TypeError elif operator == '+': return const_factory(+self.value) else: # operator == '-': return const_factory(-self.value)
def test_infered_dont_pollute(self): code = ''' def func(a=None): a.custom_attr = 0 def func2(a={}): a.custom_attr = 0 ''' astng = self.builder.string_build(code) nonetype = nodes.const_factory(None) self.failIf('custom_attr' in nonetype.locals) self.failIf('custom_attr' in nonetype.instance_attrs) nonetype = nodes.const_factory({}) self.failIf('custom_attr' in nonetype.locals) self.failIf('custom_attr' in nonetype.instance_attrs)
def test_builtin_lookup(self): self.assertEqual(builtin_lookup('__dict__')[1], ()) intstmts = builtin_lookup('int')[1] self.assertEqual(len(intstmts), 1) self.assertIsInstance(intstmts[0], nodes.Class) self.assertEqual(intstmts[0].name, 'int') self.assertIs(intstmts[0], nodes.const_factory(1)._proxied)
def _test(self, value): node = nodes.const_factory(value) self.assertIsInstance(node._proxied, nodes.Class) self.assertEqual(node._proxied.name, value.__class__.__name__) self.assertIs(node.value, value) self.assertTrue(node._proxied.parent) self.assertEqual(node._proxied.root().name, value.__class__.__module__)
def build_function(name, args=None, defaults=None, flag=0, doc=None): """create and initialize a astng Function node""" args, defaults = args or [], defaults or [] # first argument is now a list of decorators func = Function(name, doc) func.args = argsnode = Arguments() argsnode.args = [] for arg in args: argsnode.args.append(Name()) argsnode.args[-1].name = arg argsnode.args[-1].parent = argsnode argsnode.defaults = [] for default in defaults: argsnode.defaults.append(const_factory(default)) argsnode.defaults[-1].parent = argsnode argsnode.kwarg = None argsnode.vararg = None argsnode.parent = func if args: register_arguments(func) return func
def const_infer_binary_op(self, operator, other, context): for other in other.infer(context): if isinstance(other, nodes.Const): try: impl = BIN_OP_IMPL[operator] try: yield const_factory(impl(self.value, other.value)) except StandardError: # ArithmeticError is not enough: float >> float is a TypeError # TODO : let pylint know about the problem pass except TypeError: # XXX log TypeError continue elif other is YES: yield other else: try: for val in other.infer_binary_op(operator, self, context): yield val except AttributeError: yield YES
def function_factory(name, args, defaults, flag=0, doc=None): """create and initialize a astng Function node""" # XXX local import necessary due to cyclic deps from logilab.astng.nodes import const_factory node = Function() node.decorators = None node.body = [] node.name = name # XXX ensure we get a compatible representation node.args = argsnode = Arguments() argsnode.args = [] for arg in args: argsnode.args.append(Name()) argsnode.args[-1].name = arg argsnode.args[-1].parent = argsnode argsnode.defaults = [] for default in defaults: argsnode.defaults.append(const_factory(default)) argsnode.defaults[-1].parent = argsnode argsnode.kwarg = None argsnode.vararg = None argsnode.parent = node node.doc = doc return node
def attach_const_node(node, name, value): """create a Const node and register it in the locals of the given node with the specified name """ if not name in node.special_attributes: _attach_local_node(node, const_factory(value), name)
def dict_infer_unary_op(self, operator): if operator == 'not': return const_factory(not bool(self.items)) raise TypeError() # XXX log unsupported operation
def infer_argument(self, funcnode, name, context): """infer a function argument value according to the call context""" # 1. search in named keywords try: return self.nargs[name].infer(context) except KeyError: # Function.args.args can be None in astng (means that we don't have # information on argnames) argindex = funcnode.args.find_argname(name)[0] if argindex is not None: # 2. first argument of instance/class method if argindex == 0 and funcnode.type in ('method', 'classmethod'): if context.boundnode is not None: boundnode = context.boundnode else: # XXX can do better ? boundnode = funcnode.parent.frame() if funcnode.type == 'method': if not isinstance(boundnode, Instance): boundnode = Instance(boundnode) return iter((boundnode,)) if funcnode.type == 'classmethod': return iter((boundnode,)) # 2. search arg index try: return self.args[argindex].infer(context) except IndexError: pass # 3. search in *args (.starargs) if self.starargs is not None: its = [] for infered in self.starargs.infer(context): if infered is YES: its.append((YES,)) continue try: its.append(infered.getitem(argindex, context).infer(context)) except (InferenceError, AttributeError): its.append((YES,)) except (IndexError, TypeError): continue if its: return chain(*its) # 4. XXX search in **kwargs (.dstarargs) if self.dstarargs is not None: its = [] for infered in self.dstarargs.infer(context): if infered is YES: its.append((YES,)) continue try: its.append(infered.getitem(name, context).infer(context)) except (InferenceError, AttributeError): its.append((YES,)) except (IndexError, TypeError): continue if its: return chain(*its) # 5. */** argument, (Tuple or Dict) if name == funcnode.args.vararg: return iter((nodes.const_factory(()))) if name == funcnode.args.kwarg: return iter((nodes.const_factory({}))) # 6. return default value if any try: return funcnode.args.default_value(name).infer(context) except NoDefault: raise InferenceError(name)
def infer_argument(self, funcnode, name, context): """infer a function argument value according to the call context""" # 1. search in named keywords try: return self.nargs[name].infer(context) except KeyError: # Function.args.args can be None in astng (means that we don't have # information on argnames) argindex = funcnode.args.find_argname(name)[0] if argindex is not None: # 2. first argument of instance/class method if argindex == 0 and funcnode.type in ('method', 'classmethod'): if context.boundnode is not None: boundnode = context.boundnode else: # XXX can do better ? boundnode = funcnode.parent.frame() if funcnode.type == 'method': if not isinstance(boundnode, Instance): boundnode = Instance(boundnode) return iter((boundnode, )) if funcnode.type == 'classmethod': return iter((boundnode, )) # 2. search arg index try: return self.args[argindex].infer(context) except IndexError: pass # 3. search in *args (.starargs) if self.starargs is not None: its = [] for infered in self.starargs.infer(context): if infered is YES: its.append((YES, )) continue try: its.append( infered.getitem(argindex, context).infer(context)) except (InferenceError, AttributeError): its.append((YES, )) except (IndexError, TypeError): continue if its: return chain(*its) # 4. XXX search in **kwargs (.dstarargs) if self.dstarargs is not None: its = [] for infered in self.dstarargs.infer(context): if infered is YES: its.append((YES, )) continue try: its.append(infered.getitem(name, context).infer(context)) except (InferenceError, AttributeError): its.append((YES, )) except (IndexError, TypeError): continue if its: return chain(*its) # 5. */** argument, (Tuple or Dict) if name == funcnode.args.vararg: return iter((nodes.const_factory(()))) if name == funcnode.args.kwarg: return iter((nodes.const_factory({}))) # 6. return default value if any try: return funcnode.args.default_value(name).infer(context) except NoDefault: raise InferenceError(name)