diff --git a/benchmarks/benchmarks.py b/benchmarks/benchmarks.py index e48217f5a..65783fcf4 100644 --- a/benchmarks/benchmarks.py +++ b/benchmarks/benchmarks.py @@ -70,14 +70,14 @@ def generate_random_data( def setup_random_project( - N, num_keys=1, num_doc_keys=0, data_size_mean=0, data_size_std=0, seed=0, root=None + N, num_keys=1, num_doc_keys=0, data_size_mean=0, data_size_std=0, seed=0, path=None ): random.seed(seed) if not isinstance(N, int): raise TypeError("N must be an integer!") temp_dir = TemporaryDirectory() - project = signac.init_project(f"benchmark-N={N}", root=temp_dir.name) + project = signac.init_project(path=temp_dir.name) generate_random_data( project, N, num_keys, num_doc_keys, data_size_mean, data_size_std ) diff --git a/changelog.txt b/changelog.txt index 623dd5e67..093b3b299 100644 --- a/changelog.txt +++ b/changelog.txt @@ -22,6 +22,7 @@ Changed - Projects no longer have names and are identified solely by their root directories. This change also affects a number of public APIs where names are including, most prominently ``signac.init_project`` and ``Project.init_project``. Projects can now be constructed with just a root directory rather than a preloaded config (#677, #684, #706). - Project workspaces are no longer configurable, but are instead always defined as a subdirectory of the Project's root directory called ``workspace`` (#714). - Rather than searching upwards until the root, ``load_config`` will only load configuration files in the specified directory, which is assumed to be a project directory, as well as the user's home directory (#711). + - Changed the ``root`` parameter to ``path`` in the ``signac.get_project`` and ``signac.init_project`` functions and corresponding ``Project`` methods (#757, #758). Removed +++++++ diff --git a/signac/__main__.py b/signac/__main__.py index f84638b9d..4fa8f0213 100644 --- a/signac/__main__.py +++ b/signac/__main__.py @@ -73,7 +73,7 @@ SHELL_BANNER = """Python {python_version} signac {signac_version} 🎨 -Project:\t{root_path}{job_banner} +Project:\t{path}{job_banner} Size:\t\t{size} Interact with the project interface using the "project" or "pr" variable. @@ -230,7 +230,7 @@ def main_remove(args): def main_move(args): """Handle move subcommand.""" project = get_project() - dst_project = get_project(root=args.project) + dst_project = get_project(path=args.project) for job_id in args.job_id: try: job = _open_job_by_id(project, job_id) @@ -244,7 +244,7 @@ def main_move(args): def main_clone(args): """Handle clone subcommand.""" project = get_project() - dst_project = get_project(root=args.project) + dst_project = get_project(path=args.project) for job_id in args.job_id: try: job = _open_job_by_id(project, job_id) @@ -333,7 +333,7 @@ def main_view(args): def main_init(args): """Handle init subcommand.""" - init_project(root=os.getcwd()) + init_project(path=os.getcwd()) _print_err("Initialized project.") @@ -397,9 +397,9 @@ def _sig(st): # Setup synchronization process # - source = get_project(root=args.source) + source = get_project(path=args.source) try: - destination = get_project(root=args.destination) + destination = get_project(path=args.destination) except LookupError: _print_err("WARNING: The destination does not appear to be a project path.") raise @@ -529,7 +529,7 @@ def _main_import_interactive(project, origin, args): python_version=sys.version, signac_version=__version__, job_banner="", - root_path=project.path, + path=project.path, size=len(project), origin=args.origin, ), @@ -870,7 +870,7 @@ def write_history_file(): python_version=sys.version, signac_version=__version__, job_banner=f"\nJob:\t\t{job.id}" if job is not None else "", - root_path=project.path, + path=project.path, size=len(project), ), ) @@ -1085,7 +1085,7 @@ def main(): parser_move.add_argument( "project", type=str, - help="The root directory of the project to move one or more jobs to.", + help="The destination project directory.", ) parser_move.add_argument( "job_id", @@ -1099,7 +1099,7 @@ def main(): parser_clone.add_argument( "project", type=str, - help="The root directory of the project to clone one or more jobs in.", + help="The directory of the project to clone one or more jobs in.", ) parser_clone.add_argument( "job_id", @@ -1322,12 +1322,12 @@ def main(): ) parser_sync.add_argument( "source", - help="The root directory of the project that this project should be synchronized with.", + help="The directory of the project that this project should be synchronized with.", ) parser_sync.add_argument( "destination", nargs="?", - help="Optional: The root directory of the project that should be modified for " + help="Optional: The directory of the project that should be modified for " "synchronization, defaults to the local project.", ) _add_verbosity_argument(parser_sync, default=2) diff --git a/signac/common/config.py b/signac/common/config.py index 4918f412d..0fe74a022 100644 --- a/signac/common/config.py +++ b/signac/common/config.py @@ -19,35 +19,32 @@ # functions from the public API. -def _get_project_config_fn(root): - return os.path.abspath(os.path.join(root, PROJECT_CONFIG_FN)) +def _get_project_config_fn(path): + return os.path.abspath(os.path.join(path, PROJECT_CONFIG_FN)) def _locate_config_dir(search_path): - """Locates root directory containing a signac configuration file in a directory hierarchy. + """Locates directory containing a signac configuration file in a directory hierarchy. Parameters ---------- - root : str + search_path : str Starting path to search. Returns -------- str or None - The root directory containing the configuration file if one is found, otherwise None. + The directory containing the configuration file if one is found, otherwise None. """ - root = os.path.abspath(search_path) + search_path = os.path.abspath(search_path) while True: - if os.path.isfile(_get_project_config_fn(root)): - return root - # TODO: Could use the walrus operator here when we completely drop - # Python 3.7 support if we like the operator. - up = os.path.dirname(root) - if up == root: + if os.path.isfile(_get_project_config_fn(search_path)): + return search_path + if (up := os.path.dirname(search_path)) == search_path: logger.debug("Reached filesystem root, no config found.") return None else: - root = up + search_path = up def read_config_file(filename): @@ -81,12 +78,12 @@ def read_config_file(filename): return config -def load_config(root=None): +def load_config(path=None): """Load configuration from a project directory. Parameters ---------- - root : str + path : str The project path to pull project-local configuration data from. Returns @@ -96,8 +93,8 @@ def load_config(root=None): config data if requested. Note that because this config is a composite, modifications to the returned value will not be reflected in the files. """ - if root is None: - root = os.getcwd() + if path is None: + path = os.getcwd() config = Config(configspec=cfg.split("\n")) # Add in any global or user config files. For now this only finds user-specific @@ -106,8 +103,8 @@ def load_config(root=None): if os.path.isfile(fn): config.merge(read_config_file(fn)) - if os.path.isfile(_get_project_config_fn(root)): - config.merge(read_config_file(_get_project_config_fn(root))) + if os.path.isfile(_get_project_config_fn(path)): + config.merge(read_config_file(_get_project_config_fn(path))) return config diff --git a/signac/contrib/job.py b/signac/contrib/job.py index ea3d87e70..885afe0ad 100644 --- a/signac/contrib/job.py +++ b/signac/contrib/job.py @@ -818,7 +818,7 @@ def sync(self, other, strategy=None, exclude=None, doc_sync=None, **kwargs): ) def fn(self, filename): - """Prepend a filename with the job's workspace directory path. + """Prepend a filename with the job path. Parameters ---------- @@ -828,13 +828,13 @@ def fn(self, filename): Returns ------- str - The full workspace path of the file. + The absolute path to the file. """ return os.path.join(self.path, filename) def isfile(self, filename): - """Return True if file exists in the job's workspace. + """Check if a filename exists in the job directory. Parameters ---------- @@ -844,7 +844,7 @@ def isfile(self, filename): Returns ------- bool - True if file with filename exists in workspace. + True if filename exists in the job directory. """ return os.path.isfile(self.fn(filename)) diff --git a/signac/contrib/project.py b/signac/contrib/project.py index 1dc242527..23d0800bf 100644 --- a/signac/contrib/project.py +++ b/signac/contrib/project.py @@ -77,14 +77,14 @@ class Project: A :class:`Project` may only be constructed in a directory that is already a signac project, i.e. a directory in which :func:`~signac.init_project` has - already been run. If project discovery (searching upwards in the folder - hierarchy until a project root is discovered) is desired, users should - instead invoke :func:`~signac.get_project` or :meth:`Project.get_project`. + already been run. To search upwards in the folder hierarchy until a project + is found, instead invoke :func:`~signac.get_project` or + :meth:`Project.get_project`. Parameters ---------- - root : str, optional - The project root directory. By default, the current working directory + path : str, optional + The project directory. By default, the current working directory (Default value = None). """ @@ -100,17 +100,17 @@ class Project: _use_pandas_for_html_repr = True # toggle use of pandas for html repr - def __init__(self, root=None): - if root is None: - root = os.getcwd() - if not os.path.isfile(_get_project_config_fn(root)): + def __init__(self, path=None): + if path is None: + path = os.getcwd() + if not os.path.isfile(_get_project_config_fn(path)): raise LookupError( - f"Unable to find project at path '{os.path.abspath(root)}'." + f"Unable to find project at path '{os.path.abspath(path)}'." ) - # Project constructor does not search upward, so the provided root must + # Project constructor does not search upward, so the provided path must # be a project directory. - config = load_config(root) + config = load_config(path) self._config = _ProjectConfig(config) self._lock = RLock() @@ -123,9 +123,9 @@ def __init__(self, root=None): # Prepare project H5StoreManager self._stores = None - # Prepare root directory and workspace paths. + # Prepare project and workspace directories. # os.path is used instead of pathlib.Path for performance. - self._path = os.path.abspath(root) + self._path = os.path.abspath(path) self._workspace = os.path.join(self._path, "workspace") # Prepare workspace directory. @@ -134,7 +134,7 @@ def __init__(self, root=None): _mkdir_p(self.workspace) except OSError: logger.error( - "Error occurred while trying to create workspace directory for project at root " + "Error occurred while trying to create workspace directory for project at path " f"{self.path}." ) raise @@ -264,7 +264,7 @@ def min_len_unique_id(self): return i def fn(self, filename): - """Prepend a filename with the project's root directory path. + """Prepend a filename with the project path. Parameters ---------- @@ -274,13 +274,13 @@ def fn(self, filename): Returns ------- str - The joined path of project root directory and filename. + The absolute path of the file. """ return os.path.join(self.path, filename) def isfile(self, filename): - """Check if a filename exists in the project's root directory. + """Check if a filename exists in the project path. Parameters ---------- @@ -290,7 +290,7 @@ def isfile(self, filename): Returns ------- bool - True if filename exists in the project's root directory. + True if filename exists in the project path. """ return os.path.isfile(self.fn(filename)) @@ -356,11 +356,11 @@ def doc(self, new_doc): def stores(self): """Get HDF5-stores associated with this project. - Use this property to access an HDF5 file within the project's root + Use this property to access an HDF5 file within the project directory using the H5Store dict-like interface. This is an example for accessing an HDF5 file called ``'my_data.h5'`` - within the project's root directory: + within the project directory: .. code-block:: python @@ -839,7 +839,7 @@ def create_linked_view(self, prefix=None, job_ids=None, path=None): Similar to :meth:`~signac.Project.export_to`, this function expands the data space for the selected jobs, but instead of copying data will create symbolic links to the - individual job workspace directories. This is primarily useful for browsing through + individual job directories. This is primarily useful for browsing through the data space using a file-browser with human-interpretable directory paths. By default, the paths of the view will be based on variable state point keys as part @@ -1318,7 +1318,7 @@ def update_cache(self): """Update the persistent state point cache. This function updates a persistent state point cache, which - is stored in the project root directory. Most data space operations, + is stored in the project directory. Most data space operations, including iteration and filtering or selection are expected to be significantly faster after calling this function, especially for large data spaces. @@ -1370,7 +1370,7 @@ def _read_cache(self): def temporary_project(self, dir=None): """Context manager for the initialization of a temporary project. - The temporary project is by default created within the root project's + The temporary project is by default created within the parent project's workspace to ensure that they share the same file system. This is an example for how this method can be used for the import and synchronization of external data spaces. @@ -1384,7 +1384,7 @@ def temporary_project(self, dir=None): Parameters ---------- dir : str - Optionally specify where the temporary project root directory is to be + Optionally specify where the temporary project directory is to be created. Defaults to the project's workspace directory. Returns @@ -1400,8 +1400,8 @@ def temporary_project(self, dir=None): yield tmp_project @classmethod - def init_project(cls, *, root=None): - """Initialize a project in the provided root directory. + def init_project(cls, path=None): + """Initialize a project in the provided directory. It is safe to call this function multiple times with the same arguments. However, a `RuntimeError` is raised if an existing project @@ -1412,8 +1412,8 @@ def init_project(cls, *, root=None): Parameters ---------- - root : str, optional - The root directory for the project. + path : str, optional + The directory for the project. Defaults to the current working directory. Returns @@ -1424,38 +1424,38 @@ def init_project(cls, *, root=None): Raises ------ RuntimeError - If the project root path already contains a conflicting project + If the project path already contains a conflicting project configuration. """ - if root is None: - root = os.getcwd() + if path is None: + path = os.getcwd() try: - project = cls.get_project(root=root, search=False) + project = cls.get_project(path=path, search=False) except LookupError: - fn_config = _get_project_config_fn(root) + fn_config = _get_project_config_fn(path) _mkdir_p(os.path.dirname(fn_config)) config = read_config_file(fn_config) config["schema_version"] = SCHEMA_VERSION config.write() - project = cls.get_project(root=root) + project = cls.get_project(path=path) return project @classmethod - def get_project(cls, root=None, search=True, **kwargs): + def get_project(cls, path=None, search=True, **kwargs): r"""Find a project configuration and return the associated project. Parameters ---------- - root : str + path : str The starting point to search for a project, defaults to the current working directory. search : bool If True, search for project configurations inside and above - the specified root directory, otherwise only return projects - with a root directory identical to the specified root argument - (Default value = True). + the specified directory, otherwise only return projects with + a directory whose path is identical to the specified path + argument (Default value = True). \*\*kwargs : Optional keyword arguments that are forwarded to the :class:`.Project` class constructor. @@ -1471,32 +1471,31 @@ def get_project(cls, root=None, search=True, **kwargs): When project configuration cannot be found. """ - if root is None: - root = os.getcwd() + if path is None: + path = os.getcwd() - old_root = root - if not search and not os.path.isfile(_get_project_config_fn(root)): - root = None + old_path = path + if not search and not os.path.isfile(_get_project_config_fn(path)): + path = None else: - root = _locate_config_dir(root) + path = _locate_config_dir(path) - if not root: + if not path: raise LookupError( - f"Unable to find project at path '{os.path.abspath(old_root)}'." + f"Unable to find project at path '{os.path.abspath(old_path)}'." ) - return cls(root=root, **kwargs) + return cls(path=path, **kwargs) @classmethod - def get_job(cls, root=None): + def get_job(cls, path=None): """Find a Job in or above the current working directory (or provided path). Parameters ---------- - root : str - The job root directory. - If no root directory is given, the current working directory is - assumed to be the job directory (Default value = None). + path : str + The job directory. If no path is given, the current working + directory is used (Default value = None). Returns ------- @@ -1509,24 +1508,24 @@ def get_job(cls, root=None): When job cannot be found. """ - if root is None: - root = os.getcwd() - root = os.path.abspath(root) + if path is None: + path = os.getcwd() + path = os.path.abspath(path) - # Ensure the root path exists, which is not guaranteed by the regex match - if not os.path.exists(root): - raise LookupError(f"Path does not exist: '{root}'.") + # Ensure the path exists, which is not guaranteed by the regex match + if not os.path.exists(path): + raise LookupError(f"Path does not exist: '{path}'.") # Find the last match instance of a job id - results = list(re.finditer(JOB_ID_REGEX, root)) + results = list(re.finditer(JOB_ID_REGEX, path)) if len(results) == 0: - raise LookupError(f"Could not find a job id in path '{root}'.") + raise LookupError(f"Could not find a job id in path '{path}'.") match = results[-1] job_id = match.group(0) - job_root = root[: match.end()] + job_path = path[: match.end()] - # Find a project *above* the root directory (avoid finding nested projects) - project = cls.get_project(os.path.join(job_root, os.pardir)) + # Find a project *above* the path (avoid finding nested projects) + project = cls.get_project(os.path.join(job_path, os.pardir)) # Return the matched job id from the found project return project.open_job(id=job_id) @@ -1561,8 +1560,9 @@ def TemporaryProject(cls=None, **kwargs): The class of the temporary project. Defaults to :class:`~signac.Project`. \*\*kwargs : - Optional keyword arguments that are forwarded to the TemporaryDirectory class - constructor, which is used to create a temporary root directory. + Optional keyword arguments that are forwarded to the + TemporaryDirectory class constructor, which is used to create a + temporary project directory. Yields ------ @@ -1573,7 +1573,7 @@ def TemporaryProject(cls=None, **kwargs): if cls is None: cls = Project with TemporaryDirectory(**kwargs) as tmp_dir: - yield cls.init_project(root=tmp_dir) + yield cls.init_project(path=tmp_dir) def _skip_errors(iterable, log=print): @@ -1999,7 +1999,7 @@ def _repr_html_(self): return repr(self) + self._repr_html_jobs() -def init_project(*args, root=None, **kwargs): +def init_project(path=None): """Initialize a project. It is safe to call this function multiple times with the same arguments. @@ -2008,8 +2008,8 @@ def init_project(*args, root=None, **kwargs): Parameters ---------- - root : str, optional - The root directory for the project. + path : str, optional + The directory for the project. Defaults to the current working directory. Returns @@ -2020,26 +2020,25 @@ def init_project(*args, root=None, **kwargs): Raises ------ RuntimeError - If the project root path already contains a conflicting project + If the project path already contains a conflicting project configuration. """ - return Project.init_project(*args, root=root, **kwargs) + return Project.init_project(path=path) -def get_project(root=None, search=True, **kwargs): +def get_project(path=None, search=True, **kwargs): r"""Find a project configuration and return the associated project. Parameters ---------- - root : str + path : str The starting point to search for a project, defaults to the current working directory. search : bool If True, search for project configurations inside and above the - specified root directory, otherwise only return projects with a root - directory identical to the specified root argument (Default value = - True). + specified path, otherwise only return a project in the specified + path (Default value = True). \*\*kwargs : Optional keyword arguments that are forwarded to :meth:`~signac.Project.get_project`. @@ -2055,18 +2054,17 @@ def get_project(root=None, search=True, **kwargs): If no project configuration can be found. """ - return Project.get_project(root=root, search=search, **kwargs) + return Project.get_project(path=path, search=search, **kwargs) -def get_job(root=None): - """Find a Job in or above the current working directory (or provided path). +def get_job(path=None): + """Find a Job in or above the provided path (or the current working directory). Parameters ---------- - root : str - The job root directory. - If no root directory is given, the current working directory is - assumed to be within the current job workspace directory (Default value = None). + path : str + The path from which to search. Returns the first job found in or above this path. + (Default value = None). Returns ------- @@ -2080,10 +2078,10 @@ def get_job(root=None): Examples -------- - When the current directory is a job workspace directory: + When the current directory is a job directory: >>> signac.get_job() signac.contrib.job.Job(project=..., statepoint={...}) """ - return Project.get_job(root=root) + return Project.get_job(path=path) diff --git a/signac/sync.py b/signac/sync.py index 40e4bb647..759931267 100644 --- a/signac/sync.py +++ b/signac/sync.py @@ -303,7 +303,7 @@ def sync_jobs( callable with signature ``strategy(src, dst, filepath)`` where ``src`` and ``dst`` are the source and destination instances of :py:class:`~signac.Project` and ``filepath`` is the filepath relative - to the project root. If no strategy is provided, a + to the project path. If no strategy is provided, a :class:`.errors.SyncConflict` exception will be raised upon conflict. (Default value = None) exclude : str @@ -435,7 +435,7 @@ def sync_projects( callable with signature ``strategy(src, dst, filepath)`` where ``src`` and ``dst`` are the source and destination instances of :py:class:`~signac.Project` and ``filepath`` is the filepath relative - to the project root. If no strategy is provided, a + to the project path. If no strategy is provided, a :class:`.errors.SyncConflict` exception will be raised upon conflict. (Default value = None) exclude : str diff --git a/tests/test_diff.py b/tests/test_diff.py index bdf9833b4..09186405e 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -16,7 +16,7 @@ class TestDiffBase: def setUp(self, request): self._tmp_dir = TemporaryDirectory(prefix="signac_") request.addfinalizer(self._tmp_dir.cleanup) - self.project = self.project_class.init_project(root=self._tmp_dir.name) + self.project = self.project_class.init_project(path=self._tmp_dir.name) class TestDiff(TestDiffBase): diff --git a/tests/test_job.py b/tests/test_job.py index f1965bc37..2fea1520e 100644 --- a/tests/test_job.py +++ b/tests/test_job.py @@ -72,7 +72,7 @@ def setUp(self, request): self._tmp_pr = os.path.join(self._tmp_dir.name, "pr") os.mkdir(self._tmp_pr) self.config = signac.common.config.load_config() - self.project = self.project_class.init_project(root=self._tmp_pr) + self.project = self.project_class.init_project(path=self._tmp_pr) def tearDown(self): pass @@ -1332,7 +1332,7 @@ def test_move_inter_project(self): job = self.open_job(test_token).init() project_a = self.project project_b = self.project_class.init_project( - root=os.path.join(self._tmp_pr, "project_b") + path=os.path.join(self._tmp_pr, "project_b") ) job.move(project_b) job.move(project_a) diff --git a/tests/test_project.py b/tests/test_project.py index 44c1437de..a3eedcc1d 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -104,7 +104,7 @@ def test_repr(self): def test_str(self): assert str(self.project) == self.project.path - def test_root_directory(self): + def test_path(self): assert self._tmp_pr == self.project.path def test_workspace_directory(self): @@ -139,7 +139,7 @@ def test_document(self): self.project.document["a"] = 42 assert len(self.project.document) == 1 assert self.project.document - prj2 = type(self.project).get_project(root=self.project.path) + prj2 = type(self.project).get_project(path=self.project.path) assert prj2.document assert len(prj2.document) == 1 self.project.document.clear() @@ -160,7 +160,7 @@ def test_doc(self): self.project.doc["a"] = 42 assert len(self.project.doc) == 1 assert self.project.doc - prj2 = type(self.project).get_project(root=self.project.path) + prj2 = type(self.project).get_project(path=self.project.path) assert prj2.doc assert len(prj2.doc) == 1 self.project.doc.clear() @@ -184,7 +184,7 @@ def test_data(self): self.project.data["a"] = 42 assert len(self.project.data) == 1 assert self.project.data - prj2 = type(self.project).get_project(root=self.project.path) + prj2 = type(self.project).get_project(path=self.project.path) with prj2.data: assert prj2.data assert len(prj2.data) == 1 @@ -221,7 +221,7 @@ def test_no_workspace_warn_on_find(self, caplog): @pytest.mark.skipif(WINDOWS, reason="Symbolic links are unsupported on Windows.") def test_workspace_broken_link_error_on_find(self): with TemporaryDirectory() as tmp_dir: - project = self.project_class.init_project(root=tmp_dir) + project = self.project_class.init_project(path=tmp_dir) os.rmdir(project.workspace) os.symlink( os.path.join(tmp_dir, "workspace~"), @@ -601,7 +601,7 @@ def test_custom_project(self): class CustomProject(signac.Project): pass - project = CustomProject.get_project(root=self.project.path) + project = CustomProject.get_project(path=self.project.path) assert isinstance(project, signac.Project) assert isinstance(project, CustomProject) @@ -619,9 +619,9 @@ def test_JobsCursor_contains(self): assert job in cursor def test_job_move(self): - root = self._tmp_dir.name - project_a = signac.init_project(root=os.path.join(root, "a")) - project_b = signac.init_project(root=os.path.join(root, "b")) + path = self._tmp_dir.name + project_a = signac.init_project(path=os.path.join(path, "a")) + project_b = signac.init_project(path=os.path.join(path, "b")) job = project_a.open_job(dict(a=0)) job_b = project_b.open_job(dict(a=0)) assert job != job_b @@ -648,9 +648,9 @@ def test_job_move(self): assert job_.document["a"] == 0 def test_job_clone(self): - root = self._tmp_dir.name - project_a = signac.init_project(root=os.path.join(root, "a")) - project_b = signac.init_project(root=os.path.join(root, "b")) + path = self._tmp_dir.name + project_a = signac.init_project(path=os.path.join(path, "a")) + project_b = signac.init_project(path=os.path.join(path, "b")) job_a = project_a.open_job(dict(a=0)) assert job_a not in project_a assert job_a not in project_b @@ -930,12 +930,12 @@ def get_doc(i): def test_temp_project(self): with self.project.temporary_project() as tmp_project: assert len(tmp_project) == 0 - tmp_root_dir = tmp_project.path - assert os.path.isdir(tmp_root_dir) + tmp_path = tmp_project.path + assert os.path.isdir(tmp_path) for i in range(10): # init some jobs tmp_project.open_job(dict(a=i)).init() assert len(tmp_project) == 10 - assert not os.path.isdir(tmp_root_dir) + assert not os.path.isdir(tmp_path) class TestProjectExportImport(TestProjectBase): @@ -2109,87 +2109,87 @@ def setUp(self, request): request.addfinalizer(self._tmp_dir.cleanup) def test_get_project(self): - root = self._tmp_dir.name + path = self._tmp_dir.name with pytest.raises(LookupError): - signac.get_project(root=root) - project = signac.init_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root - project = signac.Project.init_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root - project = signac.get_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root - project = signac.Project.get_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root + signac.get_project(path=path) + project = signac.init_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path + project = signac.Project.init_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path + project = signac.get_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path + project = signac.Project.get_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path def test_get_project_non_local(self): - root = self._tmp_dir.name - subdir = os.path.join(root, "subdir") + path = self._tmp_dir.name + subdir = os.path.join(path, "subdir") os.mkdir(subdir) - project = signac.init_project(root=root) - assert project == project.get_project(root=root) - assert project == signac.get_project(root=root) - assert project == project.get_project(root=root, search=False) - assert project == signac.get_project(root=root, search=False) - assert project == project.get_project(root=os.path.relpath(root), search=False) - assert project == signac.get_project(root=os.path.relpath(root), search=False) + project = signac.init_project(path=path) + assert project == project.get_project(path=path) + assert project == signac.get_project(path=path) + assert project == project.get_project(path=path, search=False) + assert project == signac.get_project(path=path, search=False) + assert project == project.get_project(path=os.path.relpath(path), search=False) + assert project == signac.get_project(path=os.path.relpath(path), search=False) with pytest.raises(LookupError): - assert project == project.get_project(root=subdir, search=False) + assert project == project.get_project(path=subdir, search=False) with pytest.raises(LookupError): - assert project == signac.get_project(root=subdir, search=False) - assert project == project.get_project(root=subdir, search=True) - assert project == signac.get_project(root=subdir, search=True) + assert project == signac.get_project(path=subdir, search=False) + assert project == project.get_project(path=subdir, search=True) + assert project == signac.get_project(path=subdir, search=True) def test_init(self): - root = self._tmp_dir.name + path = self._tmp_dir.name with pytest.raises(LookupError): - signac.get_project(root=root) - project = signac.init_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root + signac.get_project(path=path) + project = signac.init_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path # Second initialization should not make any difference. - project = signac.init_project(root=root) - project = signac.get_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root - project = signac.Project.get_project(root=root) - assert project.workspace == os.path.join(root, "workspace") - assert project.path == root + project = signac.init_project(path=path) + project = signac.get_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path + project = signac.Project.get_project(path=path) + assert project.workspace == os.path.join(path, "workspace") + assert project.path == path def test_nested_project(self): - def check_root(root=None): - if root is None: - root = os.getcwd() + def check_path(path=None): + if path is None: + path = os.getcwd() assert os.path.realpath( - signac.get_project(root=root).path - ) == os.path.realpath(root) - - root = self._tmp_dir.name - root_a = os.path.join(root, "project_a") - root_b = os.path.join(root_a, "project_b") - signac.init_project(root=root_a) - check_root(root_a) - signac.init_project(root=root_b) - check_root(root_b) + signac.get_project(path=path).path + ) == os.path.realpath(path) + + path = self._tmp_dir.name + path_a = os.path.join(path, "project_a") + path_b = os.path.join(path_a, "project_b") + signac.init_project(path=path_a) + check_path(path_a) + signac.init_project(path=path_b) + check_path(path_b) cwd = os.getcwd() try: - os.chdir(root_a) - check_root() + os.chdir(path_a) + check_path() finally: os.chdir(cwd) try: - os.chdir(root_b) - check_root() + os.chdir(path_b) + check_path() finally: os.chdir(cwd) def test_get_job_valid_workspace(self): - # Test case: The root-path is the job workspace path. - root = self._tmp_dir.name - project = signac.init_project(root=root) + # Test case: The path is the job workspace path. + path = self._tmp_dir.name + project = signac.init_project(path=path) job = project.open_job({"a": 1}) job.init() with job: @@ -2198,9 +2198,9 @@ def test_get_job_valid_workspace(self): assert signac.get_job() == job def test_get_job_invalid_workspace(self): - # Test case: The root-path is not the job workspace path. - root = self._tmp_dir.name - project = signac.init_project(root=root) + # Test case: The path is not the job workspace path. + path = self._tmp_dir.name + project = signac.init_project(path=path) job = project.open_job({"a": 1}) job.init() # We shouldn't be able to find a job while in the workspace directory, @@ -2216,9 +2216,9 @@ def test_get_job_invalid_workspace(self): os.chdir(cwd) def test_get_job_nested_project(self): - # Test case: The job workspace dir is also a project root dir. - root = self._tmp_dir.name - project = signac.init_project(root=root) + # Test case: The job workspace dir is also a project dir. + path = self._tmp_dir.name + project = signac.init_project(path=path) job = project.open_job({"a": 1}) job.init() with job: @@ -2229,8 +2229,8 @@ def test_get_job_nested_project(self): def test_get_job_subdir(self): # Test case: Get a job from a sub-directory of the job workspace dir. - root = self._tmp_dir.name - project = signac.init_project(root=root) + path = self._tmp_dir.name + project = signac.init_project(path=path) job = project.open_job({"a": 1}) job.init() with job: @@ -2242,9 +2242,9 @@ def test_get_job_subdir(self): def test_get_job_nested_project_subdir(self): # Test case: Get a job from a sub-directory of the job workspace dir - # when the job workspace is also a project root dir - root = self._tmp_dir.name - project = signac.init_project(root=root) + # when the job directory is also a project directory + path = self._tmp_dir.name + project = signac.init_project(path=path) job = project.open_job({"a": 1}) job.init() with job: @@ -2259,13 +2259,13 @@ def test_get_job_nested_project_subdir(self): @pytest.mark.skipif(WINDOWS, reason="Symbolic links are unsupported on Windows.") def test_get_job_symlink_other_project(self): # Test case: Get a job from a symlink in another project workspace - root = self._tmp_dir.name - project_a_dir = os.path.join(root, "project_a") - project_b_dir = os.path.join(root, "project_b") + path = self._tmp_dir.name + project_a_dir = os.path.join(path, "project_a") + project_b_dir = os.path.join(path, "project_b") os.mkdir(project_a_dir) os.mkdir(project_b_dir) - project_a = signac.init_project(root=project_a_dir) - project_b = signac.init_project(root=project_b_dir) + project_a = signac.init_project(path=project_a_dir) + project_b = signac.init_project(path=project_b_dir) job_a = project_a.open_job({"a": 1}) job_a.init() job_b = project_b.open_job({"b": 1}) @@ -2290,7 +2290,7 @@ def test_project_schema_versions(self): config["schema_version"] = impossibly_high_schema_version config.write() with pytest.raises(IncompatibleSchemaVersion): - signac.init_project(root=self.project.path) + signac.init_project(path=self.project.path) # Ensure that migration fails on an unsupported version. with pytest.raises(RuntimeError): @@ -2369,7 +2369,7 @@ def test_project_schema_version_migration(self, implicit_version, workspace_exis apply_migrations(dirname) config = load_config(dirname) assert config["schema_version"] == "2" - project = signac.get_project(root=dirname) + project = signac.get_project(path=dirname) assert project.config["schema_version"] == "2" assert "OK" in err.getvalue() assert "0 to 1" in err.getvalue() @@ -2427,7 +2427,7 @@ def setUp_base_h5Store(self, request): self._tmp_pr = os.path.join(self._tmp_dir.name, "pr") os.mkdir(self._tmp_pr) self.config = load_config() - self.project = self.project_class.init_project(root=self._tmp_pr) + self.project = self.project_class.init_project(path=self._tmp_pr) self._fn_store = os.path.join(self._tmp_dir.name, "signac_data.h5") self._fn_store_other = os.path.join(self._tmp_dir.name, "other.h5") diff --git a/tests/test_shell.py b/tests/test_shell.py index 61d2b7d22..d2a5106c4 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -291,7 +291,7 @@ def test_diff(self): def test_clone(self): self.call("python -m signac init".split()) project_a = signac.Project() - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) job = project_a.open_job({"a": 0}) job.init() assert len(project_a) == 1 @@ -333,7 +333,7 @@ def test_clone(self): def test_move(self): self.call("python -m signac init".split()) project_a = signac.Project() - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) job = project_a.open_job({"a": 0}) job.init() assert len(project_a) == 1 @@ -415,7 +415,7 @@ def test_schema(self): assert s.format() == out.strip().replace(os.linesep, "\n") def test_sync(self): - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) self.call("python -m signac init".split()) project_a = signac.Project() for i in range(4): @@ -460,7 +460,7 @@ def test_sync(self): ) def test_sync_merge(self): - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) self.call("python -m signac init".split()) project_a = signac.Project() for i in range(4): @@ -493,7 +493,7 @@ def test_sync_merge(self): def test_sync_document(self): self.call("python -m signac init".split()) project_a = signac.Project() - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) job_src = project_a.open_job({"a": 0}) job_dst = project_b.open_job({"a": 0}) @@ -563,7 +563,7 @@ def reset(): def test_sync_file(self): self.call("python -m signac init".split()) project_a = signac.Project() - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) job_src = project_a.open_job({"a": 0}).init() job_dst = project_b.open_job({"a": 0}).init() for i, job in enumerate([job_src, job_dst]): @@ -641,7 +641,7 @@ def test_import(self): ) def test_import_sync(self): - project_b = signac.init_project(root=os.path.join(self.tmpdir.name, "b")) + project_b = signac.init_project(path=os.path.join(self.tmpdir.name, "b")) self.call("python -m signac init".split()) prefix_data = os.path.join(self.tmpdir.name, "data") project_a = signac.Project() diff --git a/tests/test_sync.py b/tests/test_sync.py index 4c927237d..710577bcb 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -546,8 +546,8 @@ def setUp(self, request): self._tmp_pr_b = os.path.join(self._tmp_dir.name, "pr_b") os.mkdir(self._tmp_pr_a) os.mkdir(self._tmp_pr_b) - self.project_a = signac.Project.init_project(root=self._tmp_pr_a) - self.project_b = signac.Project.init_project(root=self._tmp_pr_b) + self.project_a = signac.Project.init_project(path=self._tmp_pr_a) + self.project_b = signac.Project.init_project(path=self._tmp_pr_b) def _init_job(self, job, data="data"): with job: