def infer_named_tuple(node, context=None): """Specific inference function for namedtuple CallFunc node""" # 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 = node.args[0].value try: attributes = node.args[1].value.split() except AttributeError: attributes = [const.value for const in node.args[1].elts] except AttributeError: raise UseInferenceDefault() # we want to return a Class node instance with proper attributes set class_node = nodes.Class(name, 'docstring') # 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 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] fake = AstroidBuilder(MANAGER).string_build(''' class %(name)s(tuple): def _asdict(self): return self.__dict__ @classmethod def _make(cls, iterable, new=tuple.__new__, len=len): return new(cls, iterable) def _replace(_self, **kwds): result = _self._make(map(kwds.pop, %(fields)r, _self)) if kwds: raise ValueError('Got unexpected field names: %%r' %% list(kwds)) return result ''' % { 'name': name, 'fields': attributes }) class_node.locals['_asdict'] = fake.body[0].locals['_asdict'] class_node.locals['_make'] = fake.body[0].locals['_make'] class_node.locals['_replace'] = fake.body[0].locals['_replace'] # we use UseInferenceDefault, we can't be a generator so return an iterator return iter([class_node])
def visit_class(self, node, parent): """visit a Class node to become astroid""" newnode = new.Class(node.name, None) _lineno_parent(node, newnode, parent) _init_set_doc(node, newnode) newnode.bases = [self.visit(child, newnode) for child in node.bases] newnode.body = [self.visit(child, newnode) for child in node.body] if 'decorator_list' in node._fields and node.decorator_list:# py >= 2.6 newnode.decorators = self.visit_decorators(node, newnode) newnode.parent.frame().set_local(newnode.name, newnode) return newnode
def visit_class(self, node, parent): """visit a Class node to become astroid""" self._metaclass.append(self._metaclass[-1]) newnode = new.Class(node.name, None) _lineno_parent(node, newnode, parent) _init_set_doc(node, newnode) newnode.bases = [self.visit(child, newnode) for child in node.bases] newnode.body = [self.visit(child, newnode) for child in node.body] if 'decorator_list' in node._fields and node.decorator_list: # py >= 2.6 newnode.decorators = self.visit_decorators(node, newnode) newnode.set_line_info(newnode.last_child()) metaclass = self._metaclass.pop() if not newnode.bases: # no base classes, detect new / style old style according to # current scope newnode._newstyle = metaclass == 'type' newnode.parent.frame().set_local(newnode.name, newnode) return newnode
def infer_enum(node, context=None): """ Specific inference function for enum CallFunc node. """ enum_meta = nodes.Class("EnumMeta", 'docstring') class_node = infer_func_form(node, enum_meta, context=context, enum=True)[0] return iter([class_node.instanciate_class()])
def infer_func_form(node, base_type, context=None, enum=False): """Specific inference function for namedtuple or Python 3 enum. """ def infer_first(node): try: value = next(node.infer(context=context)) 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 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) as exc: 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(base_type) # 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] return class_node, name, attributes