PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/packages/logilab-astng/raw_building.py

https://github.com/mozilla/doozer-lib
Python | 212 lines | 110 code | 27 blank | 75 comment | 26 complexity | 10bf5742c5f0af49a1b7610fb6f6b7e1 MD5 | raw file
  1. # This program is free software; you can redistribute it and/or modify it under
  2. # the terms of the GNU Lesser 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 Lesser General Public License for more details.
  9. #
  10. # You should have received a copy of the GNU Lesser 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. # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  14. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
  15. # copyright 2003-2010 Sylvain Thenault, all rights reserved.
  16. # contact mailto:thenault@gmail.com
  17. #
  18. # This file is part of logilab-astng.
  19. #
  20. # logilab-astng is free software: you can redistribute it and/or modify it
  21. # under the terms of the GNU Lesser General Public License as published by the
  22. # Free Software Foundation, either version 2.1 of the License, or (at your
  23. # option) any later version.
  24. #
  25. # logilab-astng is distributed in the hope that it will be useful, but
  26. # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  27. # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  28. # for more details.
  29. #
  30. # You should have received a copy of the GNU Lesser General Public License along
  31. # with logilab-astng. If not, see <http://www.gnu.org/licenses/>.
  32. """this module contains a set of functions to create astng trees from scratch
  33. (build_* functions) or from living object (object_build_* functions)
  34. """
  35. __docformat__ = "restructuredtext en"
  36. import sys
  37. from inspect import getargspec
  38. from logilab.astng import nodes
  39. def _attach_local_node(parent, node, name):
  40. node.name = name # needed by add_local_node
  41. parent.add_local_node(node)
  42. _marker = object()
  43. def attach_dummy_node(node, name, object=_marker):
  44. """create a dummy node and register it in the locals of the given
  45. node with the specified name
  46. """
  47. enode = nodes.EmptyNode()
  48. enode.object = object
  49. _attach_local_node(node, enode, name)
  50. nodes.EmptyNode.has_underlying_object = lambda self: self.object is not _marker
  51. def attach_const_node(node, name, value):
  52. """create a Const node and register it in the locals of the given
  53. node with the specified name
  54. """
  55. if not name in node.special_attributes:
  56. _attach_local_node(node, nodes.const_factory(value), name)
  57. def attach_import_node(node, modname, membername):
  58. """create a From node and register it in the locals of the given
  59. node with the specified name
  60. """
  61. from_node = nodes.From(modname, [(membername, None)])
  62. _attach_local_node(node, from_node, membername)
  63. def build_module(name, doc=None):
  64. """create and initialize a astng Module node"""
  65. node = nodes.Module(name, doc, pure_python=False)
  66. node.package = False
  67. node.parent = None
  68. return node
  69. def build_class(name, basenames=(), doc=None):
  70. """create and initialize a astng Class node"""
  71. node = nodes.Class(name, doc)
  72. for base in basenames:
  73. basenode = nodes.Name()
  74. basenode.name = base
  75. node.bases.append(basenode)
  76. basenode.parent = node
  77. return node
  78. def build_function(name, args=None, defaults=None, flag=0, doc=None):
  79. """create and initialize a astng Function node"""
  80. args, defaults = args or [], defaults or []
  81. # first argument is now a list of decorators
  82. func = nodes.Function(name, doc)
  83. func.args = argsnode = nodes.Arguments()
  84. argsnode.args = []
  85. for arg in args:
  86. argsnode.args.append(nodes.Name())
  87. argsnode.args[-1].name = arg
  88. argsnode.args[-1].parent = argsnode
  89. argsnode.defaults = []
  90. for default in defaults:
  91. argsnode.defaults.append(nodes.const_factory(default))
  92. argsnode.defaults[-1].parent = argsnode
  93. argsnode.kwarg = None
  94. argsnode.vararg = None
  95. argsnode.parent = func
  96. if args:
  97. register_arguments(func)
  98. return func
  99. # def build_name_assign(name, value):
  100. # """create and initialize an astng Assign for a name assignment"""
  101. # return nodes.Assign([nodes.AssName(name, 'OP_ASSIGN')], nodes.Const(value))
  102. # def build_attr_assign(name, value, attr='self'):
  103. # """create and initialize an astng Assign for an attribute assignment"""
  104. # return nodes.Assign([nodes.AssAttr(nodes.Name(attr), name, 'OP_ASSIGN')],
  105. # nodes.Const(value))
  106. def build_from_import(fromname, names):
  107. """create and initialize an astng From import statement"""
  108. return nodes.From(fromname, [(name, None) for name in names])
  109. def register_arguments(func, args=None):
  110. """add given arguments to local
  111. args is a list that may contains nested lists
  112. (i.e. def func(a, (b, c, d)): ...)
  113. """
  114. if args is None:
  115. args = func.args.args
  116. if func.args.vararg:
  117. func.set_local(func.args.vararg, func.args)
  118. if func.args.kwarg:
  119. func.set_local(func.args.kwarg, func.args)
  120. for arg in args:
  121. if isinstance(arg, nodes.Name):
  122. func.set_local(arg.name, arg)
  123. else:
  124. register_arguments(func, arg.elts)
  125. def object_build_class(node, member, localname):
  126. """create astng for a living class object"""
  127. basenames = [base.__name__ for base in member.__bases__]
  128. return _base_class_object_build(node, member, basenames,
  129. localname=localname)
  130. def object_build_function(node, member, localname):
  131. """create astng for a living function object"""
  132. args, varargs, varkw, defaults = getargspec(member)
  133. if varargs is not None:
  134. args.append(varargs)
  135. if varkw is not None:
  136. args.append(varkw)
  137. func = build_function(getattr(member, '__name__', None) or localname, args,
  138. defaults, member.func_code.co_flags, member.__doc__)
  139. node.add_local_node(func, localname)
  140. def object_build_datadescriptor(node, member, name):
  141. """create astng for a living data descriptor object"""
  142. return _base_class_object_build(node, member, [], name)
  143. def object_build_methoddescriptor(node, member, localname):
  144. """create astng for a living method descriptor object"""
  145. # FIXME get arguments ?
  146. func = build_function(getattr(member, '__name__', None) or localname,
  147. doc=member.__doc__)
  148. # set node's arguments to None to notice that we have no information, not
  149. # and empty argument list
  150. func.args.args = None
  151. node.add_local_node(func, localname)
  152. def _base_class_object_build(node, member, basenames, name=None, localname=None):
  153. """create astng for a living class object, with a given set of base names
  154. (e.g. ancestors)
  155. """
  156. klass = build_class(name or getattr(member, '__name__', None) or localname,
  157. basenames, member.__doc__)
  158. klass._newstyle = isinstance(member, type)
  159. node.add_local_node(klass, localname)
  160. try:
  161. # limit the instantiation trick since it's too dangerous
  162. # (such as infinite test execution...)
  163. # this at least resolves common case such as Exception.args,
  164. # OSError.errno
  165. if issubclass(member, Exception):
  166. instdict = member().__dict__
  167. else:
  168. raise TypeError
  169. except:
  170. pass
  171. else:
  172. for name, obj in instdict.items():
  173. valnode = nodes.EmptyNode()
  174. valnode.object = obj
  175. valnode.parent = klass
  176. valnode.lineno = 1
  177. klass.instance_attrs[name] = [valnode]
  178. return klass
  179. __all__ = ('register_arguments', 'build_module',
  180. 'object_build_class', 'object_build_function',
  181. 'object_build_datadescriptor', 'object_build_methoddescriptor',
  182. 'attach_dummy_node',
  183. 'attach_const_node', 'attach_import_node')