Skip to content

Commit

Permalink
Merge pull request #424 from python-rope/lieryan-add-repr-to-objects
Browse files Browse the repository at this point in the history
Add some basic __repr__ to make it easier for debugging
  • Loading branch information
lieryan committed Jun 8, 2022
2 parents aafb62c + de807f8 commit 44fa021
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 1 deletion.
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')

0 comments on commit 44fa021

Please sign in to comment.