From 59fae27e3fb0ca7f2da967361fb9331452182929 Mon Sep 17 00:00:00 2001 From: antazoey Date: Mon, 13 Jan 2025 17:13:56 -0700 Subject: [PATCH] feat: ctx-mgmt for changing into proj --- src/ape/managers/project.py | 33 ++++++++++++++++++-------------- src/ape/utils/os.py | 18 +++++++++++++++++ tests/functional/test_project.py | 12 ++++++++++++ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/ape/managers/project.py b/src/ape/managers/project.py index a1b183e5f9..390e70b29f 100644 --- a/src/ape/managers/project.py +++ b/src/ape/managers/project.py @@ -40,6 +40,7 @@ get_relative_path, in_tempdir, path_match, + within_directory, ) @@ -2583,28 +2584,22 @@ def clean(self): self.sources._path_cache = None self._clear_cached_config() - def chdir(self, path: Path): + def chdir(self, path: Optional[Path] = None): """ Change the local project to the new path. Args: path (Path): The path of the new project. """ - if self.path == path: - return # Already there! - + path = path or self.path os.chdir(path) + if self.path == path: + return # Already setup. - # Clear cached properties. - for prop in ( - "path", - "_deduced_contracts_folder", - "project_api", - "contracts", - "interfaces_folder", - "sources", - ): - self.__dict__.pop(prop, None) + # New path: clear cached properties. + for attr in list(self.__dict__.keys()): + if isinstance(getattr(type(self), attr, None), cached_property): + del self.__dict__[attr] # Re-initialize self._session_source_change_check = set() @@ -2613,6 +2608,16 @@ def chdir(self, path: Path): self.manifest_path = self._base_path / ".build" / "__local__.json" self._manifest = self.load_manifest() + @contextmanager + def within_project_path(self): + """ + A context-manager for changing the current working directory to the + project's ``.path``. Then, switch back to whatever the current + directory was before calling this method. + """ + with within_directory(self.path): + yield + def reload_config(self): """ Reload the local ape-config.yaml file. diff --git a/src/ape/utils/os.py b/src/ape/utils/os.py index 6a3a4213df..31cac896f2 100644 --- a/src/ape/utils/os.py +++ b/src/ape/utils/os.py @@ -436,3 +436,21 @@ def get_data(self, key: str) -> dict: def delete_data(self, key: str): file = self.get_file(key) file.unlink(missing_ok=True) + + +@contextmanager +def within_directory(directory: Path): + """ + A context-manager for changing the cwd to the given path. + + Args: + directory (Path): The directory to change. + """ + here = Path.cwd() + if directory != here: + os.chdir(directory) + try: + yield + finally: + if Path.cwd() != here: + os.chdir(here) diff --git a/tests/functional/test_project.py b/tests/functional/test_project.py index 40482d0329..1a2309f614 100644 --- a/tests/functional/test_project.py +++ b/tests/functional/test_project.py @@ -1064,3 +1064,15 @@ def test_chdir(project): # Undo. project.chdir(original_path) assert project.path == original_path + + +def test_within_project_path(): + start_cwd = Path.cwd() + with create_tempdir() as new_path: + project = Project(new_path) + assert Path.cwd() != new_path + + with project.within_project_path(): + assert Path.cwd() == project.path + + assert Path.cwd() == start_cwd