From c2c7b26daedb01495f67e59329117d933c1d69a2 Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Wed, 3 Jan 2024 12:18:06 +1100 Subject: [PATCH 1/6] Simplify code that uses pathlib.Path to use Resource.pathlib property --- rope/contrib/autoimport/sqlite.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/rope/contrib/autoimport/sqlite.py b/rope/contrib/autoimport/sqlite.py index 1755f2f2b..563cebd63 100644 --- a/rope/contrib/autoimport/sqlite.py +++ b/rope/contrib/autoimport/sqlite.py @@ -113,7 +113,7 @@ def __init__( autoimport = AutoImport(..., memory=True) """ self.project = project - project_package = get_package_tuple(Path(project.root.real_path), project) + project_package = get_package_tuple(project.root.pathlib, project) assert project_package is not None assert project_package.path is not None self.project_package = project_package @@ -175,9 +175,7 @@ def calculate_project_hash(data: str) -> str: f"file:rope-{project_hash}:?mode=memory&cache=shared", uri=True ) else: - return sqlite3.connect( - str(Path(project.ropefolder.real_path) / "autoimport.db") - ) + return sqlite3.connect(project.ropefolder.pathlib / "autoimport.db") @property def connection(self): @@ -627,7 +625,7 @@ def _resource_to_module( ) -> ModuleFile: assert self.project_package.path underlined = underlined if underlined else self.underlined - resource_path: Path = Path(resource.real_path) + resource_path: Path = resource.pathlib # The project doesn't need its name added to the path, # since the standard python file layout accounts for that # so we set add_package_name to False From a21d34b64b28cd52eecae6d00ae8a7b2e5a1f7a0 Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Wed, 3 Jan 2024 12:37:05 +1100 Subject: [PATCH 2/6] Add type annotations to Resource --- rope/base/resources.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rope/base/resources.py b/rope/base/resources.py index eaf194857..bc8c42724 100644 --- a/rope/base/resources.py +++ b/rope/base/resources.py @@ -75,7 +75,7 @@ def parent(self): return self.project.get_folder(parent) @property - def path(self): + def path(self) -> str: """Return the path of this resource relative to the project root The path is the list of parent directories separated by '/' followed @@ -84,17 +84,17 @@ def path(self): return self._path @property - def name(self): + def name(self) -> str: """Return the name of this resource""" return self.path.split("/")[-1] @property - def real_path(self): + def real_path(self) -> str: """Return the file system path of this resource""" return self.project._get_resource_path(self.path) @property - def pathlib(self): + def pathlib(self) -> Path: """Return the file as a pathlib path.""" return Path(self.real_path) From bafb28eaa957d42e061ccb1bd24a5eb393485e10 Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Wed, 3 Jan 2024 12:37:24 +1100 Subject: [PATCH 3/6] Make Resouce implement os.PathLike --- rope/base/resources.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/rope/base/resources.py b/rope/base/resources.py index bc8c42724..cb975bde1 100644 --- a/rope/base/resources.py +++ b/rope/base/resources.py @@ -34,7 +34,7 @@ from rope.base import change, exceptions, fscommands -class Resource: +class Resource(os.PathLike): """Represents files and folders in a project""" def __init__(self, project, path): @@ -49,6 +49,10 @@ def __repr__(self): hex(id(self)), ) + def __fspath__(self) -> str: + """Return the file system path of this resource""" + return self.project._get_resource_path(self.path) + def move(self, new_location): """Move resource to `new_location`""" self._perform_change( @@ -67,7 +71,7 @@ def create(self): """Create this resource""" def exists(self): - return os.path.exists(self.real_path) + return os.path.exists(self) @property def parent(self): @@ -90,13 +94,12 @@ def name(self) -> str: @property def real_path(self) -> str: - """Return the file system path of this resource""" - return self.project._get_resource_path(self.path) + return os.fspath(self) @property def pathlib(self) -> Path: """Return the file as a pathlib path.""" - return Path(self.real_path) + return Path(self) def __eq__(self, obj): return self.__class__ == obj.__class__ and self.path == obj.path @@ -135,7 +138,7 @@ def read_bytes(self): DeprecationWarning, stacklevel=2, ) - with open(self.real_path, "rb") as handle: + with open(self, "rb") as handle: return handle.read() return self.project.fscommands.read(self.real_path) @@ -165,7 +168,7 @@ def is_folder(self): def get_children(self): """Return the children of this folder""" try: - children = os.listdir(self.real_path) + children = os.listdir(self) except OSError: return [] result = [] From 3ffb1c2a4ac2a1e498a255e15999a0aa3a7a4154 Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Wed, 3 Jan 2024 13:10:53 +1100 Subject: [PATCH 4/6] Renamed Resource.{is_folder() -> is_dir()} --- rope/base/resources.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rope/base/resources.py b/rope/base/resources.py index cb975bde1..b284ba9f1 100644 --- a/rope/base/resources.py +++ b/rope/base/resources.py @@ -64,8 +64,11 @@ def remove(self): """Remove resource from the project""" self._perform_change(change.RemoveResource(self), "Removing <%s>" % self.path) + def is_dir(self): + """Alias for `is_folder()`""" + def is_folder(self): - """Return true if the resource is a folder""" + """Return True if the resource is a Folder""" def create(self): """Create this resource""" From 655b5671b4173da45288cda0624d8e5b40df0fee Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Wed, 3 Jan 2024 13:26:36 +1100 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fa900e16..0fbad4fe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - #733 skip directories with perm error when building autoimport index (@MrBago) - #722, #723 Remove site-packages from packages search tree (@tkrabel) +- #738 Implement os.PathLike on Resource (@lieryan) # Release 1.11.0 From e747c39d172ac19ff5aee41b3cf118e3f8a50d84 Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Wed, 3 Jan 2024 13:31:16 +1100 Subject: [PATCH 6/6] Add test for `Resource.__fspath__()` --- ropetest/projecttest.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ropetest/projecttest.py b/ropetest/projecttest.py index 2efa25183..151384518 100644 --- a/ropetest/projecttest.py +++ b/ropetest/projecttest.py @@ -9,6 +9,7 @@ from rope.base.libutils import path_to_resource from rope.base.project import NoProject, Project, _realpath from rope.base.resourceobserver import FilteredResourceObserver +from rope.base.resources import File, Folder from ropetest import testutils @@ -610,6 +611,18 @@ def test_multi_source_folders2(self): self.assertEqual(2, len(source_folders)) self.assertTrue(self.project.root in source_folders and src in source_folders) + def test_folder_is_pathlike(self): + resource = self.project.root.create_folder("src") + self.assertIsInstance(resource, Folder) + + self.assertIsInstance(os.fspath(resource), str) + + def test_file_is_pathlike(self): + resource = self.project.root.create_file("mod.py") + self.assertIsInstance(resource, File) + + self.assertIsInstance(os.fspath(resource), str) + class ResourceObserverTest(unittest.TestCase): def setUp(self):