pyobjects.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. from rope.base.fscommands import _decode_data
  2. from rope.base import ast, exceptions, utils
  3. class PyObject(object):
  4. def __init__(self, type_):
  5. if type_ is None:
  6. type_ = self
  7. self.type = type_
  8. def get_attributes(self):
  9. if self.type is self:
  10. return {}
  11. return self.type.get_attributes()
  12. def get_attribute(self, name):
  13. if name not in self.get_attributes():
  14. raise exceptions.AttributeNotFoundError(
  15. 'Attribute %s not found' % name)
  16. return self.get_attributes()[name]
  17. def get_type(self):
  18. return self.type
  19. def __getitem__(self, key):
  20. """The same as ``get_attribute(key)``"""
  21. return self.get_attribute(key)
  22. def __contains__(self, key):
  23. """The same as ``key in self.get_attributes()``"""
  24. return key in self.get_attributes()
  25. def __eq__(self, obj):
  26. """Check the equality of two `PyObject`\s
  27. Currently it is assumed that instances (the direct instances
  28. of `PyObject`, not the instances of its subclasses) are equal
  29. if their types are equal. For every other object like
  30. defineds or builtins rope assumes objects are reference
  31. objects and their identities should match.
  32. """
  33. if self.__class__ != obj.__class__:
  34. return False
  35. if type(self) == PyObject:
  36. if self is not self.type:
  37. return self.type == obj.type
  38. else:
  39. return self.type is obj.type
  40. return self is obj
  41. def __ne__(self, obj):
  42. return not self.__eq__(obj)
  43. def __hash__(self):
  44. """See docs for `__eq__()` method"""
  45. if type(self) == PyObject and self != self.type:
  46. return hash(self.type) + 1
  47. else:
  48. return super(PyObject, self).__hash__()
  49. def __iter__(self):
  50. """The same as ``iter(self.get_attributes())``"""
  51. return iter(self.get_attributes())
  52. _types = None
  53. _unknown = None
  54. @staticmethod
  55. def _get_base_type(name):
  56. if PyObject._types is None:
  57. PyObject._types = {}
  58. base_type = PyObject(None)
  59. PyObject._types['Type'] = base_type
  60. PyObject._types['Module'] = PyObject(base_type)
  61. PyObject._types['Function'] = PyObject(base_type)
  62. PyObject._types['Unknown'] = PyObject(base_type)
  63. return PyObject._types[name]
  64. def get_base_type(name):
  65. """Return the base type with name `name`.
  66. The base types are 'Type', 'Function', 'Module' and 'Unknown'. It
  67. was used to check the type of a `PyObject` but currently its use
  68. is discouraged. Use classes defined in this module instead.
  69. For example instead of
  70. ``pyobject.get_type() == get_base_type('Function')`` use
  71. ``isinstance(pyobject, AbstractFunction)``.
  72. You can use `AbstractClass` for classes, `AbstractFunction` for
  73. functions, and `AbstractModule` for modules. You can also use
  74. `PyFunction` and `PyClass` for testing if an object is
  75. defined somewhere and rope can access its source. These classes
  76. provide more methods.
  77. """
  78. return PyObject._get_base_type(name)
  79. def get_unknown():
  80. """Return a pyobject whose type is unknown
  81. Note that two unknown objects are equal. So for example you can
  82. write::
  83. if pyname.get_object() == get_unknown():
  84. print 'cannot determine what this pyname holds'
  85. Rope could have used `None` for indicating unknown objects but
  86. we had to check that in many places. So actually this method
  87. returns a null object.
  88. """
  89. if PyObject._unknown is None:
  90. PyObject._unknown = PyObject(get_base_type('Unknown'))
  91. return PyObject._unknown
  92. class AbstractClass(PyObject):
  93. def __init__(self):
  94. super(AbstractClass, self).__init__(get_base_type('Type'))
  95. def get_name(self):
  96. pass
  97. def get_doc(self):
  98. pass
  99. def get_superclasses(self):
  100. return []
  101. class AbstractFunction(PyObject):
  102. def __init__(self):
  103. super(AbstractFunction, self).__init__(get_base_type('Function'))
  104. def get_name(self):
  105. pass
  106. def get_doc(self):
  107. pass
  108. def get_param_names(self, special_args=True):
  109. return []
  110. def get_returned_object(self, args):
  111. return get_unknown()
  112. class AbstractModule(PyObject):
  113. def __init__(self, doc=None):
  114. super(AbstractModule, self).__init__(get_base_type('Module'))
  115. def get_doc(self):
  116. pass
  117. def get_resource(self):
  118. pass
  119. class PyDefinedObject(object):
  120. """Python defined names that rope can access their sources"""
  121. def __init__(self, pycore, ast_node, parent):
  122. self.pycore = pycore
  123. self.ast_node = ast_node
  124. self.scope = None
  125. self.parent = parent
  126. self.structural_attributes = None
  127. self.concluded_attributes = self.get_module()._get_concluded_data()
  128. self.attributes = self.get_module()._get_concluded_data()
  129. self.defineds = None
  130. visitor_class = None
  131. @utils.prevent_recursion(lambda: {})
  132. def _get_structural_attributes(self):
  133. if self.structural_attributes is None:
  134. self.structural_attributes = self._create_structural_attributes()
  135. return self.structural_attributes
  136. @utils.prevent_recursion(lambda: {})
  137. def _get_concluded_attributes(self):
  138. if self.concluded_attributes.get() is None:
  139. self._get_structural_attributes()
  140. self.concluded_attributes.set(self._create_concluded_attributes())
  141. return self.concluded_attributes.get()
  142. def get_attributes(self):
  143. if self.attributes.get() is None:
  144. result = dict(self._get_concluded_attributes())
  145. result.update(self._get_structural_attributes())
  146. self.attributes.set(result)
  147. return self.attributes.get()
  148. def get_attribute(self, name):
  149. if name in self._get_structural_attributes():
  150. return self._get_structural_attributes()[name]
  151. if name in self._get_concluded_attributes():
  152. return self._get_concluded_attributes()[name]
  153. raise exceptions.AttributeNotFoundError('Attribute %s not found' %
  154. name)
  155. def get_scope(self):
  156. if self.scope is None:
  157. self.scope = self._create_scope()
  158. return self.scope
  159. def get_module(self):
  160. current_object = self
  161. while current_object.parent is not None:
  162. current_object = current_object.parent
  163. return current_object
  164. def get_doc(self):
  165. if len(self.get_ast().body) > 0:
  166. expr = self.get_ast().body[0]
  167. if isinstance(expr, ast.Expr) and \
  168. isinstance(expr.value, ast.Str):
  169. docstring = expr.value.s
  170. coding = self.get_module().coding
  171. return _decode_data(docstring, coding)
  172. def _get_defined_objects(self):
  173. if self.defineds is None:
  174. self._get_structural_attributes()
  175. return self.defineds
  176. def _create_structural_attributes(self):
  177. if self.visitor_class is None:
  178. return {}
  179. new_visitor = self.visitor_class(self.pycore, self)
  180. for child in ast.get_child_nodes(self.ast_node):
  181. ast.walk(child, new_visitor)
  182. self.defineds = new_visitor.defineds
  183. return new_visitor.names
  184. def _create_concluded_attributes(self):
  185. return {}
  186. def get_ast(self):
  187. return self.ast_node
  188. def _create_scope(self):
  189. pass
  190. class PyFunction(PyDefinedObject, AbstractFunction):
  191. """Only a placeholder"""
  192. class PyClass(PyDefinedObject, AbstractClass):
  193. """Only a placeholder"""
  194. class _ConcludedData(object):
  195. def __init__(self):
  196. self.data_ = None
  197. def set(self, data):
  198. self.data_ = data
  199. def get(self):
  200. return self.data_
  201. data = property(get, set)
  202. def _invalidate(self):
  203. self.data = None
  204. def __str__(self):
  205. return '<' + str(self.data) + '>'
  206. class _PyModule(PyDefinedObject, AbstractModule):
  207. def __init__(self, pycore, ast_node, resource):
  208. self.resource = resource
  209. self.concluded_data = []
  210. AbstractModule.__init__(self)
  211. PyDefinedObject.__init__(self, pycore, ast_node, None)
  212. def _get_concluded_data(self):
  213. new_data = _ConcludedData()
  214. self.concluded_data.append(new_data)
  215. return new_data
  216. def _forget_concluded_data(self):
  217. for data in self.concluded_data:
  218. data._invalidate()
  219. def get_resource(self):
  220. return self.resource
  221. class PyModule(_PyModule):
  222. """Only a placeholder"""
  223. class PyPackage(_PyModule):
  224. """Only a placeholder"""
  225. class IsBeingInferredError(exceptions.RopeError):
  226. pass