root / logilab.pylintinstaller / logilab / astng / raw_building.py

Revision 202:d67e86292521, 8.4 kB (checked in by tziade@…, 11 months ago)

added logilab.pylintinstaller

Line 
1# This program is free software; you can redistribute it and/or modify it under
2# the terms of the GNU General Public License as published by the Free Software
3# Foundation; either version 2 of the License, or (at your option) any later
4# version.
5#
6# This program is distributed in the hope that it will be useful, but WITHOUT
7# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9#
10# You should have received a copy of the GNU General Public License along with
11# this program; if not, write to the Free Software Foundation, Inc.,
12# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
13"""this module contains a set of functions to create astng trees from scratch
14(build_* functions) or from living object (object_build_* functions)
15
16:author:    Sylvain Thenault
17:copyright: 2003-2007 LOGILAB S.A. (Paris, FRANCE)
18:contact:   http://www.logilab.fr/ -- mailto:python-projects@logilab.org
19:copyright: 2003-2007 Sylvain Thenault
20:contact:   mailto:thenault@gmail.com
21"""
22
23__docformat__ = "restructuredtext en"
24
25import sys
26from inspect import getargspec
27
28from logilab.astng import nodes
29
30def attach___dict__(node):
31    """attach the __dict__ attribute to Class and Module objects"""
32    dictn = nodes.Dict([])
33    dictn.parent = node
34    node.locals['__dict__'] = [dictn]
35
36_marker = object()
37
38def attach_dummy_node(node, name, object=_marker):
39    """create a dummy node and register it in the locals of the given
40    node with the specified name
41    """
42    enode = nodes.EmptyNode()
43    enode.object = object
44    _attach_local_node(node, enode, name)
45
46nodes.EmptyNode.has_underlying_object = lambda self: self.object is not _marker
47
48def attach_const_node(node, name, value):
49    """create a Const node and register it in the locals of the given
50    node with the specified name
51    """
52    _attach_local_node(node, nodes.Const(value), name)
53
54if sys.version_info < (2, 5):
55    def attach_import_node(node, modname, membername):
56        """create a From node and register it in the locals of the given
57        node with the specified name
58        """
59        _attach_local_node(node,
60                           nodes.From(modname, ( (membername, None), ) ),
61                           membername)
62else:
63    def attach_import_node(node, modname, membername):
64        """create a From node and register it in the locals of the given
65        node with the specified name
66        """
67        _attach_local_node(node,
68                           nodes.From(modname, ( (membername, None), ), 0),
69                           membername)
70   
71def _attach_local_node(parent, node, name):
72    node.name = name # needed by add_local_node
73    node.parent = parent
74    node.lineno = 1
75    parent.add_local_node(node)
76
77
78def build_module(name, doc=None):
79    """create and initialize a astng Module node"""
80    node = nodes.Module(doc, nodes.Stmt([]))
81    node.node.parent = node
82    node.name = name
83    node.pure_python = False
84    node.package = False
85    node.parent = None
86    node.globals = node.locals = {}
87    return node
88
89def build_class(name, basenames=None, doc=None):
90    """create and initialize a astng Class node"""
91    klass = nodes.Class(name, [], doc, nodes.Stmt([]))
92    bases = [nodes.Name(base) for base in basenames]
93    for base in bases:
94        base.parent = klass
95    klass.basenames = basenames
96    klass.bases = bases
97    klass.code.parent = klass
98    klass.locals = {}
99    klass.instance_attrs = {}
100    for name, value in ( ('__name__', name),
101                         #('__module__', node.root().name),
102                         ):
103        const = nodes.Const(value)
104        const.parent = klass
105        klass.locals[name] = [const]
106    return klass
107
108# introduction of decorators has changed the Function initializer arguments
109if sys.version_info >= (2, 4):
110    try:
111        from compiler.ast import Decorators as BaseDecorators
112        class Decorators(BaseDecorators):
113            def __init__(self):
114                BaseDecorators.__init__(self, [], 0)
115    except ImportError:
116        Decorators = list
117       
118    def build_function(name, args=None, defaults=None, flag=0, doc=None):
119        """create and initialize a astng Function node"""
120        args, defaults = args or [], defaults or []
121        # first argument is now a list of decorators
122        func = nodes.Function(Decorators(), name, args, defaults, flag, doc,
123                              nodes.Stmt([]))
124        func.code.parent = func
125        func.locals = {}
126        if args:
127            register_arguments(func, args)
128        return func
129   
130else:   
131    def build_function(name, args=None, defaults=None, flag=0, doc=None):
132        """create and initialize a astng Function node"""
133        args, defaults = args or [], defaults or []
134        func = nodes.Function(name, args, defaults, flag, doc, nodes.Stmt([]))
135        func.code.parent = func
136        func.locals = {}
137        if args:
138            register_arguments(func, args)
139        return func
140
141
142def build_name_assign(name, value):
143    """create and initialize an astng Assign for a name assignment"""
144    return nodes.Assign([nodes.AssName(name, 'OP_ASSIGN')], nodes.Const(value))
145
146def build_attr_assign(name, value, attr='self'):
147    """create and initialize an astng Assign for an attribute assignment"""
148    return nodes.Assign([nodes.AssAttr(nodes.Name(attr), name, 'OP_ASSIGN')],
149                        nodes.Const(value))
150
151if sys.version_info < (2, 5):
152    def build_from_import(fromname, names):
153        """create and intialize an astng From import statement"""
154        return nodes.From(fromname, [(name, None) for name in names])
155else:
156    def build_from_import(fromname, names):
157        """create and intialize an astng From import statement"""
158        return nodes.From(fromname, [(name, None) for name in names], 0)
159
160def register_arguments(node, args):
161    """add given arguments to local
162   
163    args is a list that may contains nested lists
164    (i.e. def func(a, (b, c, d)): ...)
165    """
166    for arg in args:
167        if type(arg) is type(''):
168            node.set_local(arg, node)
169        else:
170            register_arguments(node, arg)
171
172
173def object_build_class(node, member):
174    """create astng for a living class object"""
175    basenames = [base.__name__ for base in member.__bases__]
176    return _base_class_object_build(node, member, basenames)
177
178def object_build_function(node, member):
179    """create astng for a living function object"""
180    args, varargs, varkw, defaults = getargspec(member)
181    if varargs is not None:
182        args.append(varargs)
183    if varkw is not None:
184        args.append(varkw)
185    func = build_function(member.__name__, args, defaults,
186                          member.func_code.co_flags, member.__doc__)
187    node.add_local_node(func)
188
189def object_build_datadescriptor(node, member, name):
190    """create astng for a living data descriptor object"""
191    return _base_class_object_build(node, member, [], name)
192
193def object_build_methoddescriptor(node, member):
194    """create astng for a living method descriptor object"""
195    # FIXME get arguments ?
196    func = build_function(member.__name__, doc=member.__doc__)
197    # set argnames to None to notice that we have no information, not
198    # and empty argument list
199    func.argnames = None 
200    node.add_local_node(func)
201
202def _base_class_object_build(node, member, basenames, name=None):
203    """create astng for a living class object, with a given set of base names
204    (e.g. ancestors)
205    """
206    klass = build_class(name or member.__name__, basenames, member.__doc__)
207    klass._newstyle = isinstance(member, type)
208    node.add_local_node(klass)
209    try:
210        # limit the instantiation trick since it's too dangerous
211        # (such as infinite test execution...)
212        # this at least resolves common case such as Exception.args,
213        # OSError.errno
214        if issubclass(member, Exception):
215            instdict = member().__dict__
216        else:
217            raise TypeError
218    except:
219        pass
220    else:
221        for name, obj in instdict.items():
222            valnode = nodes.EmptyNode()
223            valnode.object = obj
224            valnode.parent = klass
225            valnode.lineno = 1
226            klass.instance_attrs[name] = [valnode]
227    return klass
228
229
230__all__ = ('register_arguments',  'build_module', 
231           'object_build_class', 'object_build_function', 
232           'object_build_datadescriptor', 'object_build_methoddescriptor',
233           'attach___dict__', 'attach_dummy_node',
234           'attach_const_node', 'attach_import_node')
Note: See TracBrowser for help on using the browser.