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

Add some basic __repr__ to make it easier for debugging #424

Merged
merged 10 commits into from
Jun 8, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- #479 Add ABC and type hints for TaskHandle and JobSet (@bageljrkhanofemus)
- #486 Drop Python 2 support (@bageljrkhanofemus, @lieryan)
- #487 Improved value inference of __all__ declaration (@lieryan)
- #424 Add some basic __repr__ to make it easier for debugging (@lieryan)

# Release 1.1.1

Expand Down
7 changes: 7 additions & 0 deletions rope/base/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ def __init__(
self._init_prefs(prefs)
self._init_source_folders()

def __repr__(self):
return '<{}.{} "{}">'.format(
self.__class__.__module__,
self.__class__.__name__,
self.address,
)

@utils.deprecated("Delete once deprecated functions are gone")
def _init_source_folders(self):
for path in self.prefs.get("source_folders", []):
Expand Down
20 changes: 20 additions & 0 deletions rope/base/pyobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ def __init__(self, pycore, ast_node, parent):
self.attributes = self.get_module()._get_concluded_data()
self.defineds = None

def __repr__(self):
return '<{}.{} "{}" at {}>'.format(
self.__class__.__module__,
self.__class__.__name__,
self.absolute_name,
hex(id(self)),
)

@property
def absolute_name(self):
obj_name = self.get_name() if hasattr(self, "get_name") else ""
return self.get_module().get_name() + ("::" + obj_name if obj_name else "")

visitor_class = None

@utils.prevent_recursion(lambda: {})
Expand Down Expand Up @@ -250,6 +263,9 @@ class PyFunction(PyDefinedObject, AbstractFunction):
class PyComprehension(PyDefinedObject, PyObject):
"""Only a placeholder"""

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


class PyClass(PyDefinedObject, AbstractClass):
"""Only a placeholder"""
Expand Down Expand Up @@ -281,6 +297,10 @@ def __init__(self, pycore, ast_node, resource):
AbstractModule.__init__(self)
PyDefinedObject.__init__(self, pycore, ast_node, None)

@property
def absolute_name(self) -> str:
return self.get_name()

def _get_concluded_data(self):
new_data = _ConcludedData()
self.concluded_data.append(new_data)
Expand Down
5 changes: 4 additions & 1 deletion rope/base/pyobjectsdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def logical_lines(self):
return rope.base.codeanalyze.CachingLogicalLineFinder(self.lines)

def get_name(self):
return rope.base.libutils.modname(self.get_resource())
return rope.base.libutils.modname(self.resource) if self.resource else ""


class PyPackage(pyobjects.PyPackage):
Expand Down Expand Up @@ -298,6 +298,9 @@ def get_module(self):
return self.pycore.project.get_pymodule(init_dot_py)
return self

def get_name(self):
return rope.base.libutils.modname(self.resource) if self.resource else ""


class _AnnAssignVisitor:
def __init__(self, scope_visitor):
Expand Down
8 changes: 8 additions & 0 deletions rope/base/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ def __init__(self, project, path):
self.project = project
self._path = path

def __repr__(self):
return '<{}.{} "{}" at {}>'.format(
self.__class__.__module__,
self.__class__.__name__,
self.path,
hex(id(self)),
)

def move(self, new_location):
"""Move resource to `new_location`"""
self._perform_change(
Expand Down
120 changes: 120 additions & 0 deletions ropetest/reprtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import tempfile

import pytest

from rope.base import libutils, resources, pyobjectsdef, pynames
from rope.base.project import Project
from ropetest import testutils


@pytest.fixture
def project():
proj = testutils.sample_project()
yield proj
testutils.remove_project(proj)


@pytest.fixture
def mod(project):
return testutils.create_module(project, "mod")


@pytest.fixture
def mod1(project):
testutils.create_package(project, "pkg1")
return testutils.create_module(project, "pkg1.mod1")


def test_repr_project():
with tempfile.TemporaryDirectory() as folder:
obj = testutils.sample_project(folder)
assert isinstance(obj, Project)
assert repr(obj) == f'<rope.base.project.Project "{folder}">'


def test_repr_file(project):
obj = project.get_file("test/file.py")
assert isinstance(obj, resources.File)
assert repr(obj).startswith('<rope.base.resources.File "test/file.py" at 0x')


def test_repr_folder(project):
obj = project.get_folder("test/folder")
assert isinstance(obj, resources.Folder)
assert repr(obj).startswith('<rope.base.resources.Folder "test/folder" at 0x')


def test_repr_pyobjectsdef_pymodule(project, mod1):
obj = project.get_module("pkg1.mod1")
assert isinstance(obj, pyobjectsdef.PyModule)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyModule "pkg1.mod1" at 0x')


def test_repr_pyobjectsdef_pymodule_without_associated_resource(project):
obj = pyobjectsdef.PyModule(project.pycore, "a = 1")
assert isinstance(obj, pyobjectsdef.PyModule)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyModule "" at 0x')


def test_repr_pyobjectsdef_pypackage(project, mod1):
obj = project.get_module("pkg1")
assert isinstance(obj, pyobjectsdef.PyPackage)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyPackage "pkg1" at 0x')


def test_repr_pyobjectsdef_pypackage_without_associated_resource(project, mod1):
obj = pyobjectsdef.PyPackage(project.pycore)
assert isinstance(obj, pyobjectsdef.PyPackage)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyPackage "" at 0x')


def test_repr_pyobjectsdef_pyfunction(project, mod1):
code = """def func(arg): pass"""
mod = libutils.get_string_module(project, code, mod1)
obj = mod.get_attribute("func").pyobject
assert isinstance(obj, pyobjectsdef.PyFunction)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyFunction "pkg1.mod1::func" at 0x')


def test_repr_pyobjectsdef_pyfunction_without_associated_resource(project):
code = """def func(arg): pass"""
mod = libutils.get_string_module(project, code)
obj = mod.get_attribute("func").pyobject
assert isinstance(obj, pyobjectsdef.PyFunction)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyFunction "::func" at 0x')


def test_repr_pyobjectsdef_pyclass(project, mod1):
code = """class MyClass: pass"""
mod = libutils.get_string_module(project, code, mod1)
obj = mod.get_attribute("MyClass").pyobject
assert isinstance(obj, pyobjectsdef.PyClass)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyClass "pkg1.mod1::MyClass" at 0x')


def test_repr_pyobjectsdef_pyclass_without_associated_resource(project):
code = """class MyClass: pass"""
mod = libutils.get_string_module(project, code)
obj = mod.get_attribute("MyClass").pyobject
assert isinstance(obj, pyobjectsdef.PyClass)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyClass "::MyClass" at 0x')


def test_repr_pyobjectsdef_pycomprehension(project, mod1):
code = """[a for a in b]"""
mod = libutils.get_string_module(project, code, mod1)
mod._create_structural_attributes()
assert len(mod.defineds) == 1
obj = mod.defineds[0]
assert isinstance(obj, pyobjectsdef.PyComprehension)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyComprehension "pkg1.mod1::<comprehension>" at 0x')


def test_repr_pyobjectsdef_pycomprehension_without_associated_resource(project):
code = """[a for a in b]"""
mod = libutils.get_string_module(project, code)
mod._create_structural_attributes()
assert len(mod.defineds) == 1
obj = mod.defineds[0]
assert isinstance(obj, pyobjectsdef.PyComprehension)
assert repr(obj).startswith('<rope.base.pyobjectsdef.PyComprehension "::<comprehension>" at 0x')