diff options
| author | root <none@none> | 2006-04-26 10:48:09 +0000 |
|---|---|---|
| committer | root <none@none> | 2006-04-26 10:48:09 +0000 |
| commit | 85529cfcb8e870333d7292cb493f54d7f3fd92cf (patch) | |
| tree | ab1c5d7f169245ebf38ec6c8dba5065cbd48ec9f /raw_building.py | |
| download | astroid-git-85529cfcb8e870333d7292cb493f54d7f3fd92cf.tar.gz | |
forget the past.
forget the past.
Diffstat (limited to 'raw_building.py')
| -rw-r--r-- | raw_building.py | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/raw_building.py b/raw_building.py new file mode 100644 index 00000000..d00fdfb1 --- /dev/null +++ b/raw_building.py @@ -0,0 +1,214 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +"""this module contains a set of functions to create astng trees from scratch +(build_* functions) or from living object (object_build_* functions) + +:version: $Revision: 1.12 $ +:author: Sylvain Thenault +:copyright: 2003-2005 LOGILAB S.A. (Paris, FRANCE) +:contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org +:copyright: 2003-2005 Sylvain Thenault +:contact: mailto:thenault@gmail.com +""" + +__revision__ = "$Id: raw_building.py,v 1.12 2006-03-05 14:44:15 syt Exp $" +__doctype__ = "restructuredtext en" + +import sys +from inspect import getargspec + +from logilab.astng import nodes + +def attach___dict__(node): + """attach the __dict__ attribute to Class and Module objects""" + dictn = nodes.Dict([]) + dictn.parent = node + node.locals['__dict__'] = [dictn] + +def attach_dummy_node(node, name): + """create a dummy node and register it in the locals of the given + node with the specified name + """ + _attach_local_node(node, nodes.EmptyNode(), name) + +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 + """ + _attach_local_node(node, nodes.Const(value), name) + +def attach_import_node(node, modname, membername): + """create a From node and register it in the locals of the given + node with the specified name + """ + _attach_local_node(node, nodes.From(modname, ( (membername, None), ) ), + membername) + +def _attach_local_node(parent, node, name): + node.name = name # needed by add_local_node + node.parent = parent + node.lineno = 1 + parent.add_local_node(node) + + +def build_module(name, doc=None): + """create and initialize a astng Module node""" + node = nodes.Module(doc, nodes.Stmt([])) + node.node.parent = node + node.name = name + node.pure_python = False + node.package = False + node.parent = None + node.globals = node.locals = {} + return node + +def build_class(name, basenames=None, doc=None): + """create and initialize a astng Class node""" + klass = nodes.Class(name, [], doc, nodes.Stmt([])) + bases = [nodes.Name(base) for base in basenames] + for base in bases: + base.parent = klass + klass.basenames = basenames + klass.bases = bases + klass.code.parent = klass + klass.locals = {} + klass.instance_attrs = {} + for name, value in ( ('__name__', name), + #('__module__', node.root().name), + ): + const = nodes.Const(value) + const.parent = klass + klass.locals[name] = [const] + return klass + +# introduction of decorators has changed the Function initializer arguments +if sys.version_info >= (2, 4): + try: + from compiler.ast import Decorators as BaseDecorators + class Decorators(BaseDecorators): + def __init__(self): + BaseDecorators.__init__(self, [], 0) + except ImportError: + Decorators = list + + 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 = nodes.Function(Decorators(), name, args, defaults, flag, doc, + nodes.Stmt([])) + func.code.parent = func + func.locals = {} + if args: + register_arguments(func, args) + return func + +else: + 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 [] + func = nodes.Function(name, args, defaults, flag, doc, nodes.Stmt([])) + func.code.parent = func + func.locals = {} + if args: + register_arguments(func, args) + return func + + +def build_name_assign(name, value): + """create and initialize an astng Assign for a name assignment""" + return nodes.Assign([nodes.AssName(name, 'OP_ASSIGN')], nodes.Const(value)) + +def build_attr_assign(name, value, attr='self'): + """create and initialize an astng Assign for an attribute assignment""" + return nodes.Assign([nodes.AssAttr(nodes.Name(attr), name, 'OP_ASSIGN')], + nodes.Const(value)) + +def build_from_import(fromname, names): + """create and intialize an astng From import statement""" + return nodes.From(fromname, [(name, None) for name in names]) + +def register_arguments(node, args): + """add given arguments to local + + args is a list that may contains nested lists + (i.e. def func(a, (b, c, d)): ...) + """ + for arg in args: + if type(arg) is type(''): + node.set_local(arg, node) + else: + register_arguments(node, arg) + + +def object_build_class(node, member): + """create astng for a living class object""" + basenames = [base.__name__ for base in member.__bases__] + return _base_class_object_build(node, member, basenames) + +def object_build_function(node, member): + """create astng for a living function object""" + args, varargs, varkw, defaults = getargspec(member) + if varargs is not None: + args.append(varargs) + if varkw is not None: + args.append(varkw) + func = build_function(member.__name__, args, defaults, + member.func_code.co_flags, member.__doc__) + node.add_local_node(func) + +def object_build_datadescriptor(node, member, name): + """create astng for a living data descriptor object""" + return _base_class_object_build(node, member, [], name) + +def object_build_methoddescriptor(node, member): + """create astng for a living method descriptor object""" + # FIXME get arguments ? + func = build_function(member.__name__, doc=member.__doc__) + # set argnames to None to notice that we have no information, not + # and empty argument list + func.argnames = None + node.add_local_node(func) + +def _base_class_object_build(node, member, basenames, name=None): + """create astng for a living class object, with a given set of base names + (e.g. ancestors) + """ + klass = build_class(name or member.__name__, basenames, member.__doc__) + klass._newstyle = isinstance(member, type) + node.add_local_node(klass) + 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: + pass + else: + for name in instdict.keys(): + valnode = nodes.EmptyNode() + valnode.parent = klass + valnode.lineno = 1 + klass.instance_attrs[name] = [valnode] + return klass + + +__all__ = ('register_arguments', 'build_module', + 'object_build_class', 'object_build_function', + 'object_build_datadescriptor', 'object_build_methoddescriptor', + 'attach___dict__', 'attach_dummy_node', + 'attach_const_node', 'attach_import_node') |
