| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- from rope.base.fscommands import _decode_data
- from rope.base import ast, exceptions, utils
- class PyObject(object):
- def __init__(self, type_):
- if type_ is None:
- type_ = self
- self.type = type_
- def get_attributes(self):
- if self.type is self:
- return {}
- return self.type.get_attributes()
- def get_attribute(self, name):
- if name not in self.get_attributes():
- raise exceptions.AttributeNotFoundError(
- 'Attribute %s not found' % name)
- return self.get_attributes()[name]
- def get_type(self):
- return self.type
- def __getitem__(self, key):
- """The same as ``get_attribute(key)``"""
- return self.get_attribute(key)
- def __contains__(self, key):
- """The same as ``key in self.get_attributes()``"""
- return key in self.get_attributes()
- def __eq__(self, obj):
- """Check the equality of two `PyObject`\s
- Currently it is assumed that instances (the direct instances
- of `PyObject`, not the instances of its subclasses) are equal
- if their types are equal. For every other object like
- defineds or builtins rope assumes objects are reference
- objects and their identities should match.
- """
- if self.__class__ != obj.__class__:
- return False
- if type(self) == PyObject:
- if self is not self.type:
- return self.type == obj.type
- else:
- return self.type is obj.type
- return self is obj
- def __ne__(self, obj):
- return not self.__eq__(obj)
- def __hash__(self):
- """See docs for `__eq__()` method"""
- if type(self) == PyObject and self != self.type:
- return hash(self.type) + 1
- else:
- return super(PyObject, self).__hash__()
- def __iter__(self):
- """The same as ``iter(self.get_attributes())``"""
- return iter(self.get_attributes())
- _types = None
- _unknown = None
- @staticmethod
- def _get_base_type(name):
- if PyObject._types is None:
- PyObject._types = {}
- base_type = PyObject(None)
- PyObject._types['Type'] = base_type
- PyObject._types['Module'] = PyObject(base_type)
- PyObject._types['Function'] = PyObject(base_type)
- PyObject._types['Unknown'] = PyObject(base_type)
- return PyObject._types[name]
- def get_base_type(name):
- """Return the base type with name `name`.
- The base types are 'Type', 'Function', 'Module' and 'Unknown'. It
- was used to check the type of a `PyObject` but currently its use
- is discouraged. Use classes defined in this module instead.
- For example instead of
- ``pyobject.get_type() == get_base_type('Function')`` use
- ``isinstance(pyobject, AbstractFunction)``.
- You can use `AbstractClass` for classes, `AbstractFunction` for
- functions, and `AbstractModule` for modules. You can also use
- `PyFunction` and `PyClass` for testing if an object is
- defined somewhere and rope can access its source. These classes
- provide more methods.
- """
- return PyObject._get_base_type(name)
- def get_unknown():
- """Return a pyobject whose type is unknown
- Note that two unknown objects are equal. So for example you can
- write::
- if pyname.get_object() == get_unknown():
- print 'cannot determine what this pyname holds'
- Rope could have used `None` for indicating unknown objects but
- we had to check that in many places. So actually this method
- returns a null object.
- """
- if PyObject._unknown is None:
- PyObject._unknown = PyObject(get_base_type('Unknown'))
- return PyObject._unknown
- class AbstractClass(PyObject):
- def __init__(self):
- super(AbstractClass, self).__init__(get_base_type('Type'))
- def get_name(self):
- pass
- def get_doc(self):
- pass
- def get_superclasses(self):
- return []
- class AbstractFunction(PyObject):
- def __init__(self):
- super(AbstractFunction, self).__init__(get_base_type('Function'))
- def get_name(self):
- pass
- def get_doc(self):
- pass
- def get_param_names(self, special_args=True):
- return []
- def get_returned_object(self, args):
- return get_unknown()
- class AbstractModule(PyObject):
- def __init__(self, doc=None):
- super(AbstractModule, self).__init__(get_base_type('Module'))
- def get_doc(self):
- pass
- def get_resource(self):
- pass
- class PyDefinedObject(object):
- """Python defined names that rope can access their sources"""
- def __init__(self, pycore, ast_node, parent):
- self.pycore = pycore
- self.ast_node = ast_node
- self.scope = None
- self.parent = parent
- self.structural_attributes = None
- self.concluded_attributes = self.get_module()._get_concluded_data()
- self.attributes = self.get_module()._get_concluded_data()
- self.defineds = None
- visitor_class = None
- @utils.prevent_recursion(lambda: {})
- def _get_structural_attributes(self):
- if self.structural_attributes is None:
- self.structural_attributes = self._create_structural_attributes()
- return self.structural_attributes
- @utils.prevent_recursion(lambda: {})
- def _get_concluded_attributes(self):
- if self.concluded_attributes.get() is None:
- self._get_structural_attributes()
- self.concluded_attributes.set(self._create_concluded_attributes())
- return self.concluded_attributes.get()
- def get_attributes(self):
- if self.attributes.get() is None:
- result = dict(self._get_concluded_attributes())
- result.update(self._get_structural_attributes())
- self.attributes.set(result)
- return self.attributes.get()
- def get_attribute(self, name):
- if name in self._get_structural_attributes():
- return self._get_structural_attributes()[name]
- if name in self._get_concluded_attributes():
- return self._get_concluded_attributes()[name]
- raise exceptions.AttributeNotFoundError('Attribute %s not found' %
- name)
- def get_scope(self):
- if self.scope is None:
- self.scope = self._create_scope()
- return self.scope
- def get_module(self):
- current_object = self
- while current_object.parent is not None:
- current_object = current_object.parent
- return current_object
- def get_doc(self):
- if len(self.get_ast().body) > 0:
- expr = self.get_ast().body[0]
- if isinstance(expr, ast.Expr) and \
- isinstance(expr.value, ast.Str):
- docstring = expr.value.s
- coding = self.get_module().coding
- return _decode_data(docstring, coding)
- def _get_defined_objects(self):
- if self.defineds is None:
- self._get_structural_attributes()
- return self.defineds
- def _create_structural_attributes(self):
- if self.visitor_class is None:
- return {}
- new_visitor = self.visitor_class(self.pycore, self)
- for child in ast.get_child_nodes(self.ast_node):
- ast.walk(child, new_visitor)
- self.defineds = new_visitor.defineds
- return new_visitor.names
- def _create_concluded_attributes(self):
- return {}
- def get_ast(self):
- return self.ast_node
- def _create_scope(self):
- pass
- class PyFunction(PyDefinedObject, AbstractFunction):
- """Only a placeholder"""
- class PyClass(PyDefinedObject, AbstractClass):
- """Only a placeholder"""
- class _ConcludedData(object):
- def __init__(self):
- self.data_ = None
- def set(self, data):
- self.data_ = data
- def get(self):
- return self.data_
- data = property(get, set)
- def _invalidate(self):
- self.data = None
- def __str__(self):
- return '<' + str(self.data) + '>'
- class _PyModule(PyDefinedObject, AbstractModule):
- def __init__(self, pycore, ast_node, resource):
- self.resource = resource
- self.concluded_data = []
- AbstractModule.__init__(self)
- PyDefinedObject.__init__(self, pycore, ast_node, None)
- def _get_concluded_data(self):
- new_data = _ConcludedData()
- self.concluded_data.append(new_data)
- return new_data
- def _forget_concluded_data(self):
- for data in self.concluded_data:
- data._invalidate()
- def get_resource(self):
- return self.resource
- class PyModule(_PyModule):
- """Only a placeholder"""
- class PyPackage(_PyModule):
- """Only a placeholder"""
- class IsBeingInferredError(exceptions.RopeError):
- pass
|