Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: use single inheritance #677

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ce634dd
Simplify po.get_base_type & po.get_unknown. Remove PyObject staticmethod
edreamleo Feb 12, 2023
d2ee568
Remove disabled methods
edreamleo Feb 12, 2023
e18fc31
Add rope.base.utils.predicates.py
edreamleo Feb 12, 2023
e10f548
Use predicates (almost?) everywhere
edreamleo Feb 12, 2023
db8826a
Remove last mentions of Abstract classes
edreamleo Feb 12, 2023
56aecfc
Remove another reference to an Abstract class
edreamleo Feb 12, 2023
e57ed11
Remove one last ref to an Abstract class
edreamleo Feb 12, 2023
3a1cae7
First successful version w/o Abstract classes
edreamleo Feb 13, 2023
d3f46b5
Cleanups
edreamleo Feb 13, 2023
c584054
Tweaks
edreamleo Feb 13, 2023
8da72cb
Convert ### comments to `# was...` comments.
edreamleo Feb 13, 2023
b16c27c
OMG! Single inheritance is so easy!
edreamleo Feb 13, 2023
7fca6bf
Single inheritance! PyDefinedObject is a PyObject
edreamleo Feb 13, 2023
3dd8127
Use super().__init__ where possible
edreamleo Feb 13, 2023
740aa8e
Annotate resolve_type w/o a union!
edreamleo Feb 13, 2023
6ca16a7
One more super().__init__
edreamleo Feb 13, 2023
a040a0f
Remove redundant base class
edreamleo Feb 13, 2023
b20ec1b
Add two methods from AbstractFunction, per mypy warning
edreamleo Feb 13, 2023
c9c277a
Add one method from AbstractClass
edreamleo Feb 13, 2023
c34f711
Move predicates to pyobjects.py
edreamleo Feb 13, 2023
e646a11
Remove predicates.py
edreamleo Feb 13, 2023
28e4540
Add a comment
edreamleo Feb 13, 2023
c88d487
Add notes and trace
edreamleo Feb 13, 2023
c86927c
Restore Abstract class. Remove predicates
edreamleo Feb 27, 2023
7159115
Revert libutils
edreamleo Feb 27, 2023
ab7836c
Cleanups
edreamleo Feb 27, 2023
3d34c3e
Make the _BuiltinElement class a subclass of PyObject
edreamleo Feb 27, 2023
cf1be1c
Remove dead code. Add docstrings for Abstract classes
edreamleo Feb 27, 2023
963f324
Merge branch 'master' into ekr-single-inheritance2
edreamleo Feb 27, 2023
dd389bb
Merge master into this branch, fixing a conflict in type_hinting.utils
edreamleo Mar 2, 2023
b8ec122
Add docstring for po.PyModule
edreamleo Mar 2, 2023
8256834
Merge branch 'master' into ekr-single-inheritance2
edreamleo Mar 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions rope/base/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

import rope.base.evaluate
from rope.base import arguments, ast, pynames, pyobjects, utils
from rope.base.pyobjects import get_base_type


class BuiltinModule(pyobjects.AbstractModule):
class BuiltinModule(pyobjects.PyObject, pyobjects.AbstractModule):
def __init__(self, name, pycore=None, initial={}):
super().__init__()
super().__init__(get_base_type("Module"))
self.name = name
self.pycore = pycore
self.initial = initial
Expand Down Expand Up @@ -48,8 +49,9 @@ def module(self):
return


class _BuiltinElement:
def __init__(self, builtin, parent=None):
class _BuiltinElement(pyobjects.PyObject):
def __init__(self, builtin, parent=None, type_=None):
super().__init__(type_)
self.builtin = builtin
self._parent = parent

Expand All @@ -70,8 +72,7 @@ def parent(self):

class BuiltinClass(_BuiltinElement, pyobjects.AbstractClass):
def __init__(self, builtin, attributes, parent=None):
_BuiltinElement.__init__(self, builtin, parent)
pyobjects.AbstractClass.__init__(self)
super().__init__(builtin, parent, type_=get_base_type("Type"))
self.initial = attributes

@utils.saveit
Expand All @@ -83,13 +84,15 @@ def get_attributes(self):
def get_module(self):
return builtins

def get_superclasses(self):
return []


class BuiltinFunction(_BuiltinElement, pyobjects.AbstractFunction):
def __init__(
self, returned=None, function=None, builtin=None, argnames=[], parent=None
):
_BuiltinElement.__init__(self, builtin, parent)
pyobjects.AbstractFunction.__init__(self)
super().__init__(builtin, parent, type_=get_base_type("Function"))
self.argnames = argnames
self.returned = returned
self.function = function
Expand Down Expand Up @@ -580,9 +583,9 @@ def get_definition_location(self):
return (None, None)


class Iterator(pyobjects.AbstractClass):
class Iterator(pyobjects.PyObject, pyobjects.AbstractClass):
def __init__(self, holding=None):
super().__init__()
super().__init__(get_base_type("Type"))
self.holding = holding
self.attributes = {
"next": BuiltinName(BuiltinFunction(self.holding)),
Expand All @@ -599,9 +602,9 @@ def get_returned_object(self, args):
get_iterator = _create_builtin_getter(Iterator)


class Generator(pyobjects.AbstractClass):
class Generator(pyobjects.PyObject, pyobjects.AbstractClass):
def __init__(self, holding=None):
super().__init__()
super().__init__(get_base_type("Type"))
self.holding = holding
self.attributes = {
"next": BuiltinName(BuiltinFunction(self.holding)),
Expand Down Expand Up @@ -681,9 +684,9 @@ def _property_function(args):
return pyobjects.PyObject(Property(parameters[0]))


class Lambda(pyobjects.AbstractFunction):
class Lambda(pyobjects.PyObject, pyobjects.AbstractFunction):
def __init__(self, node, scope):
super().__init__()
super().__init__(get_base_type("Function"))
self.node = node
self.arguments = node.args
self.scope = scope
Expand Down
8 changes: 2 additions & 6 deletions rope/base/oi/type_hinting/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Optional, Union

import rope.base.utils as base_utils
from rope.base import evaluate
from rope.base.exceptions import AttributeNotFoundError
from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction, PyObject
from rope.base.pyobjects import PyClass, PyFunction, PyObject


def get_super_func(pyfunc):
Expand Down Expand Up @@ -74,10 +73,7 @@ def get_mro(pyclass):
return class_list


def resolve_type(
type_name: str,
pyobject: Union[PyDefinedObject, PyObject],
) -> Optional[Union[PyDefinedObject, PyObject]]:
def resolve_type(type_name, pyobject: PyObject) -> PyObject: # No need for Union.
"""
Find proper type object from its name.
"""
Expand Down
139 changes: 69 additions & 70 deletions rope/base/pyobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@

class PyObject:
def __init__(self, type_):
if type_ is None:
type_ = self
self.type = type_
self.type = self if type_ is None else type_

def get_attributes(self):
if self.type is self:
Expand Down Expand Up @@ -66,106 +64,87 @@ 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]
_anchor_types = None


def get_base_type(name):
def get_base_type(name: str) -> PyObject:
"""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)``.
``is_abstract_function(pyobject)``.

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.
You can use `is_abstract_class` for classes, `is_abstract_functions` for
functions, and `is_abstract_module` for modules.

"""
return PyObject._get_base_type(name)
global _anchor_types
if _anchor_types is None:
base_type = PyObject(None)
_anchor_types = {
"Function": PyObject(base_type),
"Module": PyObject(base_type),
"Type": base_type, # a Class.
"Unknown": PyObject(base_type),
}
return _anchor_types[name]


def get_unknown():
"""Return a pyobject whose type is unknown
def get_unknown() -> PyObject:
"""Return a pyobject whose type is unknown.

Note that two unknown objects are equal. So for example you can
write::
Note that two unknown objects are equal.

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.

we had to check that in many places.
"""
if PyObject._unknown is None:
PyObject._unknown = PyObject(get_base_type("Unknown"))
return PyObject._unknown
return get_base_type("Unknown")


class AbstractClass(PyObject):
def __init__(self):
super().__init__(get_base_type("Type"))

def get_name(self):
pass

def get_doc(self):
pass

def get_superclasses(self):
return []
class AbstractClass:
"""
A mixin class that marks a class as the base of Rope's type hierarchy.

Rope contains many tests of the form `isinstance(obj, AbstractClass)
"""

class AbstractFunction(PyObject):
def __init__(self):
super().__init__(get_base_type("Function"))
pass

def get_name(self):
pass

def get_doc(self):
pass
class AbstractFunction:
"""
A mixin class that marks a function as the base of Rope's type hierarchy.

def get_param_names(self, special_args=True):
return []
Rope contains many tests of the form `isinstance(obj, AbstractFunction)
"""

def get_returned_object(self, args):
return get_unknown()
pass


class AbstractModule(PyObject):
def __init__(self, doc=None):
super().__init__(get_base_type("Module"))
class AbstractModule:
"""
A mixin class that marks a module as the base of Rope's type hierarchy.

def get_doc(self):
pass
Rope contains many tests of the form `isinstance(obj, AbstractModule).
"""

def get_resource(self):
pass
pass


class PyDefinedObject:
class PyDefinedObject(PyObject):
"""Python defined names that rope can access their sources"""

def __init__(self, pycore, ast_node, parent):
def __init__(self, pycore, ast_node, parent, type_):
super().__init__(type_)
self.pycore = pycore
self.ast_node = ast_node
self.scope = None
Expand Down Expand Up @@ -265,18 +244,33 @@ def _create_scope(self):


class PyFunction(PyDefinedObject, AbstractFunction):
pass
def __init__(self, pycore, ast_node, parent):
super().__init__(pycore, ast_node, parent, get_base_type("Function"))

# From AbstractFunction.

def get_param_names(self, special_args=True):
return []

class PyComprehension(PyDefinedObject, PyObject):
def get_returned_object(self, args):
return get_unknown()


class PyComprehension(PyDefinedObject):
pass

def get_name(self):
return "<comprehension>"


class PyClass(PyDefinedObject, AbstractClass):
pass
def __init__(self, pycore, ast_node, parent):
super().__init__(pycore, ast_node, parent, get_base_type("Type"))

# From AbstractClass.

def get_superclasses(self):
return []


class _ConcludedData:
Expand All @@ -299,11 +293,12 @@ def __str__(self):


class _PyModule(PyDefinedObject, AbstractModule):
"""The base class for PyModule and PyPackage."""

def __init__(self, pycore, ast_node, resource):
self.resource = resource
self.concluded_data = []
AbstractModule.__init__(self)
PyDefinedObject.__init__(self, pycore, ast_node, None)
super().__init__(pycore, ast_node, None, get_base_type("Module"))

@property
def absolute_name(self) -> str:
Expand All @@ -323,6 +318,10 @@ def get_resource(self):


class PyModule(_PyModule):
"""
A "target" class that allows tests of the form `isinstance(obj, pyobjects.PyModule)`.
"""

pass


Expand Down
11 changes: 4 additions & 7 deletions rope/base/pyobjectsdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@

class PyFunction(pyobjects.PyFunction):
def __init__(self, pycore, ast_node, parent):
rope.base.pyobjects.AbstractFunction.__init__(self)
rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent)
super().__init__(pycore, ast_node, parent)
self.arguments = self.ast_node.args
self.parameter_pyobjects = pynamesdef._Inferred(
self._infer_parameters, self.get_module()._get_concluded_data()
Expand Down Expand Up @@ -114,8 +113,7 @@ def decorators(self):
class PyComprehension(pyobjects.PyComprehension):
def __init__(self, pycore, ast_node, parent):
self.visitor_class = _ComprehensionVisitor
rope.base.pyobjects.PyObject.__init__(self, type_="Comp")
rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent)
super().__init__(pycore, ast_node, parent, type_="Comp")

def _create_scope(self):
return rope.base.pyscopes.ComprehensionScope(
Expand All @@ -129,8 +127,7 @@ def get_kind(self):
class PyClass(pyobjects.PyClass):
def __init__(self, pycore, ast_node, parent):
self.visitor_class = _ClassVisitor
rope.base.pyobjects.AbstractClass.__init__(self)
rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent)
super().__init__(pycore, ast_node, parent)
self.parent = parent
self._superclasses = self.get_module()._get_concluded_data()

Expand Down Expand Up @@ -400,7 +397,7 @@ def _Slice(self, node):

class _ScopeVisitor(_ExpressionVisitor):
def __init__(self, pycore, owner_object):
_ExpressionVisitor.__init__(self, scope_visitor=self)
super().__init__(scope_visitor=self)
self.pycore = pycore
self.owner_object = owner_object
self.names = {}
Expand Down