From 648585c27f4b9c3e871f8211ca3ce1b3ebf8c715 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 11:23:57 -0400 Subject: [PATCH 01/10] Remove doc filter support. --- signac/contrib/project.py | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/signac/contrib/project.py b/signac/contrib/project.py index 700bb9cf6..d7f53cc2b 100644 --- a/signac/contrib/project.py +++ b/signac/contrib/project.py @@ -51,19 +51,6 @@ JOB_ID_LENGTH = 32 JOB_ID_REGEX = re.compile(f"[a-f0-9]{{{JOB_ID_LENGTH}}}") -# The warning used for doc filter deprecation everywhere. Don't use -# triple-quoted multi-line string to avoid inserting newlines. -# (issue #725) TODO: In signac 2.0, remove all docstrings for doc_filter parameters. The -# doc_filter parameters will only be preserved for backwards compatibility but -# not advertised as part of the API in signac 2.0. -DOC_FILTER_WARNING = ( - "The doc_filter argument is deprecated as of version 1.7 and will be removed " - "in version 3.0. Users should instead use a filter with a 'doc.' prefix. For " - "example, `doc_filter={'foo': 'bar'}` is equivalent to `filter={'doc.foo': 'bar'}`. " - "See https://docs.signac.io/en/latest/query.html#query-namespaces for more " - "information." -) - # Temporary default for project names until they are removed entirely in signac 2.0 _DEFAULT_PROJECT_NAME = None @@ -695,7 +682,7 @@ def _find_job_ids(self, filter=None): ) return list(index.find(filter)) - def find_jobs(self, filter=None, *args, **kwargs): + def find_jobs(self, filter=None): """Find all jobs in the project's workspace. The filter argument must be a JSON-serializable Mapping of key-value @@ -725,14 +712,7 @@ def find_jobs(self, filter=None, *args, **kwargs): If the filters are invalid. """ - doc_filter = next(iter(args), None) or kwargs.pop("doc_filter", None) - if len(args) > 1 or len(kwargs): - raise TypeError("Unsupported arguments were provided.") - filter = dict(parse_filter(_add_prefix("sp.", filter))) - if doc_filter: - warnings.warn(DOC_FILTER_WARNING, FutureWarning) - filter.update(parse_filter(_add_prefix("doc.", doc_filter))) - return JobsCursor(self, filter) + return JobsCursor(self, dict(parse_filter(_add_prefix("sp.", filter)))) def __iter__(self): return iter(self.find_jobs()) From 6b77544045e71e732beb76f175490c90254e9484 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 11:25:37 -0400 Subject: [PATCH 02/10] Remove support for workspace as function. --- signac/contrib/project.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/signac/contrib/project.py b/signac/contrib/project.py index d7f53cc2b..88e7b92c6 100644 --- a/signac/contrib/project.py +++ b/signac/contrib/project.py @@ -55,19 +55,6 @@ _DEFAULT_PROJECT_NAME = None -class _CallableString(str): - # A string object that returns itself when called. Introduced temporarily - # to support deprecating Project.workspace, which will become a property. - def __call__(self): - assert version.parse(__version__) < version.parse("2.0.0") - warnings.warn( - "This method will soon become a property and should be used " - "without the call operator (parentheses).", - FutureWarning, - ) - return self - - class _ProjectConfig(Config): r"""Extends the project config to make it immutable. @@ -145,9 +132,7 @@ def __init__(self, root=None): # Prepare root directory and workspace paths. # os.path is used instead of pathlib.Path for performance. self._root_directory = os.path.abspath(root) - self._workspace = _CallableString( - os.path.join(self._root_directory, "workspace") - ) + self._workspace = os.path.join(self._root_directory, "workspace") # Prepare workspace directory. if not os.path.isdir(self.workspace): From 785de01a64292a92bff3f46fb0ab553b1d5eee25 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 11:30:44 -0400 Subject: [PATCH 03/10] Remove backwards compatibility layer for project_names in init. --- signac/contrib/project.py | 56 +-------------------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/signac/contrib/project.py b/signac/contrib/project.py index 88e7b92c6..db0796d18 100644 --- a/signac/contrib/project.py +++ b/signac/contrib/project.py @@ -19,8 +19,6 @@ from tempfile import TemporaryDirectory from threading import RLock -from packaging import version - from ..common.config import ( Config, _get_project_config_fn, @@ -1433,7 +1431,7 @@ def temporary_project(self, dir=None): yield tmp_project @classmethod - def init_project(cls, *args, root=None, **kwargs): + def init_project(cls, *, root=None): """Initialize a project in the provided root directory. It is safe to call this function multiple times with the same @@ -1461,61 +1459,11 @@ def init_project(cls, *args, root=None, **kwargs): configuration. """ - # TODO: Remove both the `if args` and `if kwargs` blocks in version 3.0 - # when we remove backwards compatibility for project name APIs. - name = None - # The key used to store project names in the project document. - name_key = "signac_project_name" - if args: - num_args = len(args) - if num_args == 1: - name = args[0] - else: - # Match the usual error from misusing keyword-only args. - raise TypeError( - f"init_project() takes 0 positional arguments but {num_args} were given" - ) - if kwargs: - name = kwargs.pop("name", None) - if kwargs: - # Match the usual error from extra keyword args. - raise TypeError( - f"init_project() got an unexpected keyword argument '{next(iter(kwargs))}'" - ) - - if name is not None: - assert version.parse(__version__) < version.parse("3.0.0") - warnings.warn( - "Project names were removed in signac 2.0. If you intended to call " - "`init_project` with a root directory as the sole positional argument, please " - f"provide it as a keyword argument: `init_project(root={name})`. If your " - "project name contains important information, consider storing it in the " - "project document instead. The name provided will be stored in the project " - f"document with the key `{name_key}`. Calling `init_project` with a name will " - "become an error in signac 3.0.", - FutureWarning, - ) - if root is None: root = os.getcwd() - if name is not None: - warnings.warn( - "Project names are deprecated and will be removed in signac 2.0 in favor of using " - "the project root directory to identify projects. The name argument to " - "init_project should be removed.", - FutureWarning, - ) - else: - name = _DEFAULT_PROJECT_NAME try: project = cls.get_project(root=root, search=False) - existing_name = project.doc.get(name_key) - if name is not None and name != existing_name: - raise ValueError( - "The name provided to `init_project` does not match the existing " - f"project document in which {name_key}={existing_name}." - ) except LookupError: fn_config = _get_project_config_fn(root) _mkdir_p(os.path.dirname(fn_config)) @@ -1523,8 +1471,6 @@ def init_project(cls, *args, root=None, **kwargs): config["schema_version"] = SCHEMA_VERSION config.write() project = cls.get_project(root=root) - if name is not None: - project.doc[name_key] = name return project @classmethod From 6b138b0061e9d23d362180d7d49bb6e769732e89 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 11:43:27 -0400 Subject: [PATCH 04/10] Remove backwards compat layers for schema. --- signac/contrib/schema.py | 85 +--------------------------------------- 1 file changed, 2 insertions(+), 83 deletions(-) diff --git a/signac/contrib/schema.py b/signac/contrib/schema.py index 6c30ee66f..859d0236f 100644 --- a/signac/contrib/schema.py +++ b/signac/contrib/schema.py @@ -3,8 +3,6 @@ # This software is licensed under the BSD 3-Clause License. """Project Schema.""" -import itertools -import warnings from collections import defaultdict from collections.abc import Mapping from numbers import Number @@ -12,7 +10,6 @@ from packaging import version -from ..common.deprecation import deprecated from ..version import __version__ from ._searchindexer import _DictPlaceholder from .utility import _nested_dicts_to_dotted_keys @@ -111,28 +108,6 @@ def __init__(self, schema=None): schema = {} self._schema = schema - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - ) - @classmethod - def detect(cls, statepoint_index): - """Detect Project's state point schema. - - Parameters - ---------- - statepoint_index : - State point index. - - Returns - ------- - :class:`~ProjectSchema` - The detected project schema. - - """ - return cls({key: _collect_by_type(value) for key, value in statepoint_index}) - def format(self, depth=None, precision=None, max_num_range=None): """Format the schema for printing. @@ -265,31 +240,10 @@ def _repr_html_(self): output += "
" + str(self) + "
" return output - # TODO: This method can be removed in signac 2.0 once support for list keys - # is removed. - def __contains__(self, key_or_keys): - # NotOverride default __contains__ to support sequence and str inputs. - assert version.parse(__version__) < version.parse("2.0.0") - if not isinstance(key_or_keys, str): - warnings.warn( - "Support for checking nested keys in a schema using a list of keys is deprecated " - "and will be removed in signac 2.0. Construct the nested key using '.'.join(keys) " - "instead.", - FutureWarning, - ) - key_or_keys = ".".join(key_or_keys) - return key_or_keys in self._schema + # def __contains__(self, key_or_keys): + # return key_or_keys in self._schema def __getitem__(self, key_or_keys): - assert version.parse(__version__) < version.parse("2.0.0") - if not isinstance(key_or_keys, str): - warnings.warn( - "Support for checking nested keys in a schema using a list of keys is deprecated " - "and will be removed in signac 2.0. Construct the nested key using '.'.join(keys) " - "instead.", - FutureWarning, - ) - key_or_keys = ".".join(key_or_keys) return self._schema[key_or_keys] def __iter__(self): @@ -322,38 +276,3 @@ def difference(self, other, ignore_values=False): } ) return ret - - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - ) - def __call__(self, jobs_or_statepoints): - """Evaluate the schema for the given state points. - - Parameters - ---------- - jobs_or_statepoints : - An iterable of jobs or state points. - - Returns - ------- - :class:`~ProjectSchema` - Schema of the project. - - """ - schema_data = {} - iterators = itertools.tee(jobs_or_statepoints, len(self)) - for key, it in zip(self, iterators): - values = [] - tokens = key.split(".") - for statepoint in it: - if not isinstance(statepoint, Mapping): - # Assumes that a job was provided instead of a state point - statepoint = statepoint.statepoint - value = statepoint[tokens[0]] - for token in tokens[1:]: - value = value[token] - values.append(value) - schema_data[key] = _collect_by_type(values) - return ProjectSchema(schema_data) From b7488e82ba75ecc84bd1e70567458af8e52b8645 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 11:45:36 -0400 Subject: [PATCH 05/10] Remove backwards compat layers in CLI. --- signac/__main__.py | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/signac/__main__.py b/signac/__main__.py index 492cf8846..73b355375 100644 --- a/signac/__main__.py +++ b/signac/__main__.py @@ -161,20 +161,6 @@ def find_with_filter(args): return project._find_job_ids(filter=filter_) -def main_project(args): - """Handle project subcommand.""" - warnings.warn( - "The `project` command is deprecated as of version 1.8 and will be removed in " - "version 2.0.", - FutureWarning, - ) - project = get_project() - if args.workspace: - print(project.workspace) - else: - print(project) - - def main_job(args): """Handle job subcommand.""" project = get_project() @@ -190,13 +176,6 @@ def main_job(args): job = project.open_job(statepoint) if args.create: job.init() - if args.workspace: - warnings.warn( - "The `-w/--workspace` parameter is deprecated as of version 1.8 and will be removed in " - "version 2.0. Use -p/--path instead", - FutureWarning, - ) - args.path = True if args.path: print(job.path) else: @@ -922,15 +901,6 @@ def main(): parser_init.add_argument("project_id", nargs="?", help=argparse.SUPPRESS) parser_init.set_defaults(func=main_init) - parser_project = subparsers.add_parser("project") - parser_project.add_argument( - "-w", - "--workspace", - action="store_true", - help="Print the project's workspace path instead of the project id.", - ) - parser_project.set_defaults(func=main_project) - parser_job = subparsers.add_parser("job") parser_job.add_argument( "statepoint", From 39bc2c48ba80b132f1b1d8e038ad6c16fabb4171 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 21:44:04 -0700 Subject: [PATCH 06/10] Get all tests passing. --- signac/__main__.py | 7 +- signac/contrib/job.py | 79 +++------------ signac/contrib/project.py | 44 ++------ signac/contrib/schema.py | 3 - signac/sync.py | 2 +- tests/test_job.py | 32 +++--- tests/test_project.py | 174 +++++--------------------------- tests/test_shell.py | 12 +-- tests/test_temporary_project.py | 8 +- 9 files changed, 73 insertions(+), 288 deletions(-) diff --git a/signac/__main__.py b/signac/__main__.py index 73b355375..f84638b9d 100644 --- a/signac/__main__.py +++ b/signac/__main__.py @@ -333,7 +333,7 @@ def main_view(args): def main_init(args): """Handle init subcommand.""" - init_project(name=args.project_id, root=os.getcwd()) + init_project(root=os.getcwd()) _print_err("Initialized project.") @@ -529,7 +529,7 @@ def _main_import_interactive(project, origin, args): python_version=sys.version, signac_version=__version__, job_banner="", - root_path=project.root_directory(), + root_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.root_directory(), + root_path=project.path, size=len(project), ), ) @@ -898,7 +898,6 @@ def main(): subparsers = parser.add_subparsers() parser_init = subparsers.add_parser("init") - parser_init.add_argument("project_id", nargs="?", help=argparse.SUPPRESS) parser_init.set_defaults(func=main_init) parser_job = subparsers.add_parser("job") diff --git a/signac/contrib/job.py b/signac/contrib/job.py index 3b3dd3d6e..e2762db8a 100644 --- a/signac/contrib/job.py +++ b/signac/contrib/job.py @@ -12,7 +12,6 @@ from threading import RLock from typing import FrozenSet -from ..common.deprecation import deprecated from ..core.h5store import H5StoreManager from ..sync import sync_jobs from ..synced_collections.backends.collection_json import ( @@ -21,7 +20,6 @@ json_attr_dict_validator, ) from ..synced_collections.errors import KeyTypeError -from ..version import __version__ from .errors import DestinationExistsError, JobsCorruptedError from .hashing import calc_id from .utility import _mkdir_p @@ -317,16 +315,6 @@ def __repr__(self): self.__class__.__name__, repr(self._project), self.statepoint ) - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - details="Use Job.path instead.", - ) - def workspace(self): - """Alias for :attr:`~Job.path`.""" - return self.path - @property def _statepoint_filename(self): """Get the path of the state point file for this job.""" @@ -335,19 +323,6 @@ def _statepoint_filename(self): # instead of os.path.join for speed. return os.sep.join((self.path, self.FN_STATE_POINT)) - # Tell mypy to ignore type checking of the decorator because decorated - # properties aren't supported: https://github.com/python/mypy/issues/1362 - @property # type: ignore - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - details="Use Job.path instead.", - ) - def ws(self): - """Alias for :attr:`~Job.path`.""" - return self.path - @property def path(self): """str: The path to the job directory. @@ -360,45 +335,6 @@ def path(self): self._path = os.sep.join((self._project.workspace, self.id)) return self._path - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - details="Use job.statepoint = new_statepoint instead.", - ) - def reset_statepoint(self, new_statepoint): - """Overwrite the state point of this job while preserving job data. - - This method will change the job id if the state point has been altered. - - For more information, see - `Modifying the State Point - `_. - - .. danger:: - - Use this function with caution! Resetting a job's state point - may sometimes be necessary, but can possibly lead to incoherent - data spaces. - - Parameters - ---------- - new_statepoint : dict - The job's new state point. - - """ - with self._lock: - if self._statepoint_requires_init: - # Instantiate state point data lazily - no load is required, since - # we are provided with the new state point data. - self._statepoint = _StatePointDict( - jobs=[self], filename=self._statepoint_filename - ) - self._statepoint_requires_init = False - self.statepoint.reset(new_statepoint) - - self._project._register(self.id, new_statepoint) - def update_statepoint(self, update, overwrite=False): """Change the state point of this job while preserving job data. @@ -446,7 +382,7 @@ def update_statepoint(self, update, overwrite=False): "mapping with another value." ) statepoint.update(update) - self.reset_statepoint(statepoint) + self.statepoint = statepoint @property def statepoint(self): @@ -505,7 +441,18 @@ def statepoint(self, new_statepoint): new_statepoint : dict The new state point to be assigned. """ - self.reset_statepoint(new_statepoint) + with self._lock: + if self._statepoint_requires_init: + # Instantiate state point data lazily - no load is required, since + # we are provided with the new state point data. + self._statepoint = _StatePointDict( + jobs=[self], filename=self._statepoint_filename + ) + self._statepoint_requires_init = False + self.statepoint.reset(new_statepoint) + + self._project._register(self.id, new_statepoint) + @property def sp(self): diff --git a/signac/contrib/project.py b/signac/contrib/project.py index db0796d18..a1a2fb92e 100644 --- a/signac/contrib/project.py +++ b/signac/contrib/project.py @@ -26,7 +26,6 @@ load_config, read_config_file, ) -from ..common.deprecation import deprecated from ..core.h5store import H5StoreManager from ..sync import sync_projects from ..synced_collections.backends.collection_json import BufferedJSONAttrDict @@ -139,7 +138,7 @@ def __init__(self, root=None): except OSError: logger.error( "Error occurred while trying to create workspace directory for project at root " - f"{self.root_directory()}." + f"{self.path}." ) raise @@ -157,10 +156,10 @@ def __init__(self, root=None): ) def __str__(self): - return str(self.root_directory()) + return str(self.path) def __repr__(self): - return f"{self.__class__.__name__}({repr(self.root_directory())})" + return f"{self.__class__.__name__}({repr(self.path)})" def _repr_html_(self): """Project details in HTML format for use in IPython environment. @@ -201,16 +200,6 @@ def config(self): """ return self._config - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - details="Use Project.path instead.", - ) - def root_directory(self): - """Alias for :attr:`~Project.path`.""" - return self.path - @property def path(self): """str: The path to the project directory.""" @@ -291,7 +280,7 @@ def fn(self, filename): The joined path of project root directory and filename. """ - return os.path.join(self.root_directory(), filename) + return os.path.join(self.path, filename) def isfile(self, filename): """Check if a filename exists in the project's root directory. @@ -321,7 +310,7 @@ def document(self): """ with self._lock: if self._document is None: - fn_doc = os.path.join(self.root_directory(), self.FN_DOCUMENT) + fn_doc = os.path.join(self.path, self.FN_DOCUMENT) self._document = BufferedJSONAttrDict( filename=fn_doc, write_concern=True ) @@ -401,7 +390,7 @@ def stores(self): """ with self._lock: if self._stores is None: - self._stores = H5StoreManager(self.root_directory()) + self._stores = H5StoreManager(self.path) return self._stores @property @@ -536,23 +525,6 @@ def _job_dirs(self): ) raise WorkspaceError(error) - @deprecated( - deprecated_in="1.8", - removed_in="2.0", - current_version=__version__, - details="The num_jobs method is deprecated. Use len(project) instead.", - ) - def num_jobs(self): - """Return the number of initialized jobs. - - Returns - ------- - int - Count of initialized jobs. - - """ - return len(self) - def __len__(self): # We simply count the the number of valid directories and avoid building a list # for improved performance. @@ -1673,10 +1645,6 @@ def __init__(self, project, filter=None): if self._filter == {}: self._filter = None - # This private attribute allows us to implement the deprecated - # next() method for this class. - self._next_iter = None - def __eq__(self, other): return self._project == other._project and self._filter == other._filter diff --git a/signac/contrib/schema.py b/signac/contrib/schema.py index 859d0236f..3d2713a70 100644 --- a/signac/contrib/schema.py +++ b/signac/contrib/schema.py @@ -240,9 +240,6 @@ def _repr_html_(self): output += "
" + str(self) + "
" return output - # def __contains__(self, key_or_keys): - # return key_or_keys in self._schema - def __getitem__(self, key_or_keys): return self._schema[key_or_keys] diff --git a/signac/sync.py b/signac/sync.py index a7d27f3ff..40e4bb647 100644 --- a/signac/sync.py +++ b/signac/sync.py @@ -537,7 +537,7 @@ def sync_projects( ) else: logger.info(f"Synchronizing project '{source}' to '{destination}'.") - logger.more(f"'{source.root_directory()}' -> '{destination.root_directory()}'") + logger.more(f"'{source.path}' -> '{destination.path}'") if dry_run: logger.info("Performing dry run!") if exclude is not None: diff --git a/tests/test_job.py b/tests/test_job.py index 53967f26a..f1965bc37 100644 --- a/tests/test_job.py +++ b/tests/test_job.py @@ -565,7 +565,7 @@ def test_open_job_recursive(self): assert cwd == rp(os.getcwd()) with job: assert rp(job.path) == rp(os.getcwd()) - os.chdir(self.project.root_directory()) + os.chdir(self.project.path) assert cwd == rp(os.getcwd()) with job: assert rp(job.path) == rp(os.getcwd()) @@ -575,10 +575,10 @@ def test_open_job_recursive(self): assert cwd == rp(os.getcwd()) with job: assert rp(job.path) == rp(os.getcwd()) - os.chdir(self.project.root_directory()) + os.chdir(self.project.path) with job: assert rp(job.path) == rp(os.getcwd()) - assert rp(os.getcwd()) == rp(self.project.root_directory()) + assert rp(os.getcwd()) == rp(self.project.path) assert cwd == rp(os.getcwd()) with job: job.close() @@ -966,7 +966,7 @@ def test_reset_statepoint_job(self): src_job.data[key] = d assert key in src_job.data assert len(src_job.data) == 1 - src_job.reset_statepoint(dst) + src_job.statepoint = dst src_job = self.open_job(src) dst_job = self.open_job(dst) assert key in dst_job.document @@ -976,9 +976,9 @@ def test_reset_statepoint_job(self): assert len(dst_job.data) == 1 assert key not in src_job.data with pytest.raises(RuntimeError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(DestinationExistsError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst @pytest.mark.skipif(not H5PY, reason="test requires the h5py package") def test_reset_statepoint_job_lazy_access(self): @@ -1000,7 +1000,7 @@ def test_reset_statepoint_job_lazy_access(self): # Check that the state point will be instantiated lazily during the # call to reset_statepoint assert src_job_by_id._statepoint_requires_init - src_job_by_id.reset_statepoint(dst) + src_job_by_id.statepoint = dst src_job = self.open_job(src) dst_job = self.open_job(dst) assert key in dst_job.document @@ -1010,9 +1010,9 @@ def test_reset_statepoint_job_lazy_access(self): assert len(dst_job.data) == 1 assert key not in src_job.data with pytest.raises(RuntimeError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(DestinationExistsError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst @pytest.mark.skipif(not H5PY, reason="test requires the h5py package") def test_update_statepoint(self): @@ -1043,9 +1043,9 @@ def test_update_statepoint(self): assert len(dst_job.data) == 1 assert key not in src_job.data with pytest.raises(RuntimeError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(DestinationExistsError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(KeyError): dst_job.update_statepoint(extension2) dst_job.update_statepoint(extension2, overwrite=True) @@ -1443,7 +1443,7 @@ def test_reset_statepoint_job(self): src_job.data[key] = d assert key in src_job.data assert len(src_job.data) == 1 - src_job.reset_statepoint(dst) + src_job.statepoint = dst src_job = self.open_job(src) dst_job = self.open_job(dst) with self.open_data(dst_job): @@ -1452,9 +1452,9 @@ def test_reset_statepoint_job(self): with self.open_data(src_job): assert key not in src_job.data with pytest.raises(RuntimeError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(DestinationExistsError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst def test_update_statepoint(self): key = "move_job" @@ -1481,9 +1481,9 @@ def test_update_statepoint(self): with self.open_data(src_job): assert key not in src_job.data with pytest.raises(RuntimeError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(DestinationExistsError): - src_job.reset_statepoint(dst) + src_job.statepoint = dst with pytest.raises(KeyError): dst_job.update_statepoint(extension2) dst_job.update_statepoint(extension2, overwrite=True) diff --git a/tests/test_project.py b/tests/test_project.py index 99f0ac4f8..780dbe21b 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -102,10 +102,10 @@ def test_repr(self): assert p == self.project def test_str(self): - assert str(self.project) == self.project.root_directory() + assert str(self.project) == self.project.path def test_root_directory(self): - assert self._tmp_pr == self.project.root_directory() + assert self._tmp_pr == self.project.path def test_workspace_directory(self): assert os.path.join(self._tmp_pr, "workspace") == self.project.workspace @@ -124,7 +124,7 @@ def test_workspace_directory_exists(self): def test_fn(self): assert self.project.fn("test/abc") == os.path.join( - self.project.root_directory(), "test/abc" + self.project.path, "test/abc" ) def test_isfile(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.root_directory()) + prj2 = type(self.project).get_project(root=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.root_directory()) + prj2 = type(self.project).get_project(root=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.root_directory()) + prj2 = type(self.project).get_project(root=self.project.path) with prj2.data: assert prj2.data assert len(prj2.data) == 1 @@ -261,64 +261,18 @@ def test_find_jobs(self): assert len(statepoints) == len(list(self.project.find_jobs({}))) assert 1 == len(list(self.project.find_jobs({"a": 0}))) assert 0 == len(list(self.project.find_jobs({"a": 5}))) - assert 1 == len(list(self.project.find_jobs({"a": 0}, None))) - assert 0 == len(list(self.project.find_jobs({"a": 5}, None))) - assert 1 == len(list(self.project.find_jobs({"a": 0}, doc_filter=None))) - assert 0 == len(list(self.project.find_jobs({"a": 5}, doc_filter=None))) - assert 1 == len(list(self.project.find_jobs(filter={"a": 0}, doc_filter=None))) - assert 0 == len(list(self.project.find_jobs(filter={"a": 5}, doc_filter=None))) + assert 1 == len(list(self.project.find_jobs({"a": 0}))) + assert 0 == len(list(self.project.find_jobs({"a": 5}))) assert 1 == len(list(self.project.find_jobs({"sp.a": 0}))) assert 0 == len(list(self.project.find_jobs({"sp.a": 5}))) - with pytest.warns(FutureWarning): - assert 1 == len(list(self.project.find_jobs(doc_filter={"b": 0}))) - with pytest.warns(FutureWarning): - assert 0 == len(list(self.project.find_jobs(doc_filter={"b": 5}))) - with pytest.warns(FutureWarning): - assert 1 == len(list(self.project.find_jobs(None, doc_filter={"b": 0}))) - with pytest.warns(FutureWarning): - assert 0 == len(list(self.project.find_jobs(None, doc_filter={"b": 5}))) - with pytest.warns(FutureWarning): - assert 1 == len( - list(self.project.find_jobs(filter=None, doc_filter={"b": 0})) - ) - with pytest.warns(FutureWarning): - assert 0 == len( - list(self.project.find_jobs(filter=None, doc_filter={"b": 5})) - ) - with pytest.warns(FutureWarning): - assert 1 == len(list(self.project.find_jobs(None, {"b": 0}))) - with pytest.warns(FutureWarning): - assert 0 == len(list(self.project.find_jobs(None, {"b": 5}))) assert 1 == len(list(self.project.find_jobs({"doc.b": 0}))) assert 0 == len(list(self.project.find_jobs({"doc.b": 5}))) assert 1 == len(list(self.project.find_jobs({"a": 0, "doc.b": 0}))) - with pytest.warns(FutureWarning): - assert 1 == len(list(self.project.find_jobs({"a": 0}, {"b": 0}))) - with pytest.warns(FutureWarning): - assert 1 == len( - list(self.project.find_jobs(filter={"a": 0}, doc_filter={"b": 0})) - ) - with pytest.warns(FutureWarning): - assert 1 == len(list(self.project.find_jobs({"a": 0}, doc_filter={"b": 0}))) assert 1 == len(list(self.project.find_jobs({"sp.a": 0, "doc.b": 0}))) assert 0 == len(list(self.project.find_jobs({"a": 0, "doc.b": 5}))) - with pytest.warns(FutureWarning): - assert 0 == len(list(self.project.find_jobs({"a": 0}, {"b": 5}))) - with pytest.warns(FutureWarning): - assert 0 == len( - list(self.project.find_jobs(filter={"a": 0}, doc_filter={"b": 5})) - ) - with pytest.warns(FutureWarning): - assert 0 == len(list(self.project.find_jobs({"a": 0}, doc_filter={"b": 5}))) assert 0 == len(list(self.project.find_jobs({"sp.a": 0, "doc.b": 5}))) assert 0 == len(list(self.project.find_jobs({"sp.a": 5, "doc.b": 0}))) assert 0 == len(list(self.project.find_jobs({"sp.a": 5, "doc.b": 5}))) - with pytest.raises(TypeError): - self.project.find_jobs({"a": 0}, {"b": 5}, "invalid positional arg") - with pytest.raises(TypeError): - self.project.find_jobs({"a": 0}, invalid_kwarg="invalid argument") - with pytest.raises(TypeError): - self.project.find_jobs({"a": 0}, {"b": 0}, doc_filter={"b": 0}) for job in self.project.find_jobs(): assert self.project.open_job(id=job.id).id == job.id @@ -339,11 +293,6 @@ def test_find_jobs_JobsCursor_contains(self): for sp in statepoints: assert self.project.open_job(sp) in cursor_doc - with pytest.warns(FutureWarning): - cursor_doc = self.project.find_jobs(doc_filter={"test": True}) - for sp in statepoints: - assert self.project.open_job(sp) in cursor_doc - def test_find_jobs_arithmetic_operators(self): for i in range(10): self.project.open_job(dict(a=i)).init() @@ -446,11 +395,10 @@ def assert_result_len(q, num): assert_result_len({"$and": [{"sp.a": 0}, {"doc.d": 1}]}, 0) assert_result_len({"$or": [{"sp.a": 0}, {"doc.d": 1}]}, 2) - def test_num_jobs(self): + def test_len_project(self): statepoints = [{"a": i} for i in range(5)] for sp in statepoints: self.project.open_job(sp).init() - assert len(statepoints) == self.project.num_jobs() assert len(statepoints) == len(self.project) assert len(statepoints) == len(self.project.find_jobs()) @@ -653,7 +601,7 @@ def test_custom_project(self): class CustomProject(signac.Project): pass - project = CustomProject.get_project(root=self.project.root_directory()) + project = CustomProject.get_project(root=self.project.path) assert isinstance(project, signac.Project) assert isinstance(project, CustomProject) @@ -763,14 +711,7 @@ def test_schema(self): "f.f2", ): assert k in s - if "." in k: - with pytest.warns(FutureWarning): - assert k.split(".") in s - # The following calls should not error out. s[k] - if "." in k: - with pytest.warns(FutureWarning): - s[k.split(".")] repr(s) assert s.format() == str(s) s = self.project.detect_schema(exclude_const=True) @@ -795,16 +736,6 @@ def test_schema_subset(self): ) assert s == s_sub - def test_schema_eval(self): - for i in range(10): - for j in range(10): - self.project.open_job(dict(a=i, b=j)).init() - s = self.project.detect_schema() - assert s == s(self.project) - assert s == s([job.sp for job in self.project]) - # Check that it works with iterables that can only be consumed once - assert s == s(job.sp for job in self.project) - def test_schema_difference(self): def get_sp(i): return { @@ -998,7 +929,7 @@ 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.root_directory() + tmp_root_dir = tmp_project.path assert os.path.isdir(tmp_root_dir) for i in range(10): # init some jobs tmp_project.open_job(dict(a=i)).init() @@ -1006,57 +937,6 @@ def test_temp_project(self): assert not os.path.isdir(tmp_root_dir) -class TestProjectNameDeprecations: - warning_context = pytest.warns( - FutureWarning, match="Project names were removed in signac 2.0" - ) - - @pytest.fixture(autouse=True) - def setUp(self, request): - self._tmp_dir = TemporaryDirectory() - - def test_name_only_positional(self): - assert _CURRENT_VERSION < _VERSION_3 - with self.warning_context: - project = signac.init_project("name", root=self._tmp_dir.name) - - # Check that the name was stored as expected, and that trying to open - # again with a different name raises the expected exception. - assert "signac_project_name" in project.doc - with self.warning_context: - signac.init_project("name", root=self._tmp_dir.name) - with pytest.raises(ValueError, match="does not match the existing"): - with self.warning_context: - signac.init_project("new_name", root=self._tmp_dir.name) - - def test_name_with_other_args_positional(self): - assert _CURRENT_VERSION < _VERSION_3 - with pytest.raises( - TypeError, match="takes 0 positional arguments but 2 were given" - ): - signac.init_project("project", self._tmp_dir.name) - - def test_name_only_keyword(self): - assert _CURRENT_VERSION < _VERSION_3 - os.chdir(self._tmp_dir.name) - with self.warning_context: - project = signac.init_project(name="name") - - # Check that the name was stored as expected, and that trying to open - # again with a different name raises the expected exception. - assert "signac_project_name" in project.doc - with self.warning_context: - signac.init_project(name="name") - with pytest.raises(ValueError, match="does not match the existing"): - with self.warning_context: - signac.init_project(name="new_name") - - def test_name_with_other_args_keyword(self): - assert _CURRENT_VERSION < _VERSION_3 - with pytest.raises(TypeError, match="got an unexpected keyword argument 'foo'"): - signac.init_project(name="project", foo="bar") - - class TestProjectExportImport(TestProjectBase): def test_export(self): prefix_data = os.path.join(self._tmp_dir.name, "data") @@ -1697,10 +1577,10 @@ def clean(filter=None): ) ) src = set(map(lambda j: os.path.realpath(j.path), self.project.find_jobs())) - assert len(all_links) == self.project.num_jobs() + assert len(all_links) == len(self.project) self.project.create_linked_view(prefix=view_prefix) all_links = list(_find_all_links(view_prefix)) - assert len(all_links) == self.project.num_jobs() + assert len(all_links) == len(self.project) dst = set( map( lambda l: os.path.realpath(os.path.join(view_prefix, l, "job")), @@ -1727,7 +1607,7 @@ def clean(filter=None): # some jobs removed clean({"b": 0}) all_links = list(_find_all_links(view_prefix)) - assert len(all_links) == self.project.num_jobs() + assert len(all_links) == len(self.project) dst = set( map( lambda l: os.path.realpath(os.path.join(view_prefix, l, "job")), @@ -1739,7 +1619,7 @@ def clean(filter=None): # all jobs removed clean() all_links = list(_find_all_links(view_prefix)) - assert len(all_links) == self.project.num_jobs() + assert len(all_links) == len(self.project) dst = set( map( lambda l: os.path.realpath(os.path.join(view_prefix, l, "job")), @@ -2233,16 +2113,16 @@ def test_get_project(self): signac.get_project(root=root) project = signac.init_project(root=root) assert project.workspace == os.path.join(root, "workspace") - assert project.root_directory() == root + assert project.path == root project = signac.Project.init_project(root=root) assert project.workspace == os.path.join(root, "workspace") - assert project.root_directory() == root + assert project.path == root project = signac.get_project(root=root) assert project.workspace == os.path.join(root, "workspace") - assert project.root_directory() == root + assert project.path == root project = signac.Project.get_project(root=root) assert project.workspace == os.path.join(root, "workspace") - assert project.root_directory() == root + assert project.path == root def test_get_project_non_local(self): root = self._tmp_dir.name @@ -2268,22 +2148,22 @@ def test_init(self): signac.get_project(root=root) project = signac.init_project(root=root) assert project.workspace == os.path.join(root, "workspace") - assert project.root_directory() == root + assert project.path == root # 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.root_directory() == root + assert project.path == root project = signac.Project.get_project(root=root) assert project.workspace == os.path.join(root, "workspace") - assert project.root_directory() == root + assert project.path == root def test_nested_project(self): def check_root(root=None): if root is None: root = os.getcwd() assert os.path.realpath( - signac.get_project(root=root).root_directory() + signac.get_project(root=root).path ) == os.path.realpath(root) root = self._tmp_dir.name @@ -2405,15 +2285,15 @@ def test_project_schema_versions(self): assert version.parse(self.project.config["schema_version"]) < version.parse( impossibly_high_schema_version ) - config = read_config_file(_get_project_config_fn(self.project.root_directory())) + config = read_config_file(_get_project_config_fn(self.project.path)) config["schema_version"] = impossibly_high_schema_version config.write() with pytest.raises(IncompatibleSchemaVersion): - signac.init_project(root=self.project.root_directory()) + signac.init_project(root=self.project.path) # Ensure that migration fails on an unsupported version. with pytest.raises(RuntimeError): - apply_migrations(self.project.root_directory()) + apply_migrations(self.project.path) def test_no_migration(self): # This unit test should fail as long as there are no schema migrations @@ -2425,7 +2305,7 @@ def test_no_migration(self): # 2. Either update or remove this unit test. from signac.contrib.migration import _collect_migrations - migrations = list(_collect_migrations(self.project.root_directory())) + migrations = list(_collect_migrations(self.project.path)) assert len(migrations) == 0 diff --git a/tests/test_shell.py b/tests/test_shell.py index 5635cedb6..cf8402904 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -92,13 +92,7 @@ def test_help(self): def test_init_project(self): self.call("python -m signac init".split()) - assert signac.get_project().root_directory() == os.getcwd() - - def test_project_workspace(self): - self.call("python -m signac init".split()) - assert os.path.realpath( - self.call("python -m signac project --workspace".split()).strip() - ) == os.path.realpath(os.path.join(self.tmpdir.name, "workspace")) + assert signac.get_project().path == os.getcwd() def test_job_with_argument(self): self.call("python -m signac init".split()) @@ -114,7 +108,7 @@ def test_job_with_argument_workspace(self): ) assert os.path.realpath( self.call( - ["python", "-m", "signac", "job", "--workspace", '{"a": 0}'] + ["python", "-m", "signac", "job", "--path", '{"a": 0}'] ).strip() ) == os.path.realpath(wd_path) @@ -795,7 +789,7 @@ def test_config_verify(self): err = self.call("python -m signac config --local verify".split(), error=True) assert "Did not find a local configuration file" in err - self.call("python -m signac init my_project".split()) + self.call("python -m signac init".split()) err = self.call("python -m signac config --local verify".split(), error=True) assert "Passed" in err diff --git a/tests/test_temporary_project.py b/tests/test_temporary_project.py index abab37b95..b60587d75 100644 --- a/tests/test_temporary_project.py +++ b/tests/test_temporary_project.py @@ -9,17 +9,17 @@ class TestTemporaryProject: def test_init_context_manager_constructor(self): with signac.TemporaryProject() as tmp_project: - assert os.path.isdir(tmp_project.root_directory()) + assert os.path.isdir(tmp_project.path) for i in range(10): tmp_project.open_job(dict(a=i)).init() assert len(tmp_project) == 10 - assert not os.path.isdir(tmp_project.root_directory()) + assert not os.path.isdir(tmp_project.path) def test_init_project_method(self): with signac.TemporaryProject() as project: with project.temporary_project() as tmp_project: - assert os.path.isdir(tmp_project.root_directory()) + assert os.path.isdir(tmp_project.path) for i in range(10): tmp_project.open_job(dict(a=i)).init() assert len(tmp_project) == 10 - assert not os.path.isdir(tmp_project.root_directory()) + assert not os.path.isdir(tmp_project.path) From a1fc6d0c9c16cf3a5a57eec2bc58731fec978796 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 21:48:50 -0700 Subject: [PATCH 07/10] Fix style. --- signac/contrib/job.py | 1 - tests/test_shell.py | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/signac/contrib/job.py b/signac/contrib/job.py index e2762db8a..ea3d87e70 100644 --- a/signac/contrib/job.py +++ b/signac/contrib/job.py @@ -453,7 +453,6 @@ def statepoint(self, new_statepoint): self._project._register(self.id, new_statepoint) - @property def sp(self): """Alias for :attr:`~Job.statepoint`.""" diff --git a/tests/test_shell.py b/tests/test_shell.py index cf8402904..61d2b7d22 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -107,9 +107,7 @@ def test_job_with_argument_workspace(self): self.tmpdir.name, "workspace", "9bfd29df07674bc4aa960cf661b5acd2" ) assert os.path.realpath( - self.call( - ["python", "-m", "signac", "job", "--path", '{"a": 0}'] - ).strip() + self.call(["python", "-m", "signac", "job", "--path", '{"a": 0}']).strip() ) == os.path.realpath(wd_path) def test_job_with_argument_create_workspace(self): From ccf70e06a49d5e14bf55fc2c9e084adc5d90b787 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 22:08:50 -0700 Subject: [PATCH 08/10] Update changelog. --- changelog.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6cdf74107..770e5c79c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -29,8 +29,8 @@ Removed - The pre-SyncedCollection synchronized dictionary classes, including SyncedDict, SyncedAttrDict, and JSONDict (#577). - The old custom JSON encoder and dumps wrapper (#577). - The MPIPool and the filesystems.py module (#575). - - The following Project methods: ``get_id``, ``build_job_search_index``, ``build_job_statepoint_index``, ``find_job_ids``, ``reset_statepoint``, ``update_statepoint``, ``create_access_module``, ``index``, ``dump_statepoints``, ``get_statepoint``, ``read_statepoints``, ``write_statepoints``, ``groupbydoc`` (#574, #593, #599, #601). - - The following Job methods: ``get_id`` (#578). + - The following Project methods: ``get_id``, ``build_job_search_index``, ``build_job_statepoint_index``, ``find_job_ids``, ``reset_statepoint``, ``update_statepoint``, ``create_access_module``, ``index``, ``dump_statepoints``, ``get_statepoint``, ``read_statepoints``, ``write_statepoints``, ``groupbydoc``, ``root_directory`` (#574, #593, #599, #601, #752). + - The following Job methods: ``get_id``, ``workspace``, ``ws``, ``reset_statepoint`` (#578, #752). - The ``syncutil.copytree`` method (#581). - All Crawlers, including ``RegexFileCrawler``, ``MainCrawler``, ``MasterCrawler``, ``SignacProjectCrawler``, and ``BaseCrawler``, in addition to all associated functionality in indexing.py (#580). - The cite.py module (#594). @@ -42,7 +42,9 @@ Removed - The ``Project.config`` property is no longer mutable. Use the command line ``$ signac config`` to modify configuration (#608, #246, #244). - The following config related functions: ``get_config_file``, ``search_standard_dirs`` (#674). - ``Project`` subclasses can no longer define a ``Job`` subclass to use (#588, #693). - - The ``Collection`` class has been removed (#664, #667, #683). + - The ``Collection`` class (#664, #667, #683). + - The ``project`` command line command (#752). + - The ``workspace parameter to the command line ``job`` command (#752). Version 1 ========= From 0a230240ebc8b26a112093d951f21a0000e694ba Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 1 May 2022 22:24:06 -0700 Subject: [PATCH 09/10] Update changelog. --- changelog.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 770e5c79c..db061b474 100644 --- a/changelog.txt +++ b/changelog.txt @@ -29,7 +29,7 @@ Removed - The pre-SyncedCollection synchronized dictionary classes, including SyncedDict, SyncedAttrDict, and JSONDict (#577). - The old custom JSON encoder and dumps wrapper (#577). - The MPIPool and the filesystems.py module (#575). - - The following Project methods: ``get_id``, ``build_job_search_index``, ``build_job_statepoint_index``, ``find_job_ids``, ``reset_statepoint``, ``update_statepoint``, ``create_access_module``, ``index``, ``dump_statepoints``, ``get_statepoint``, ``read_statepoints``, ``write_statepoints``, ``groupbydoc``, ``root_directory`` (#574, #593, #599, #601, #752). + - The following Project methods: ``get_id``, ``build_job_search_index``, ``build_job_statepoint_index``, ``find_job_ids``, ``reset_statepoint``, ``update_statepoint``, ``create_access_module``, ``index``, ``dump_statepoints``, ``get_statepoint``, ``read_statepoints``, ``write_statepoints``, ``groupbydoc``, ``root_directory``, ``num_jobs`` (#574, #593, #599, #601, #752). - The following Job methods: ``get_id``, ``workspace``, ``ws``, ``reset_statepoint`` (#578, #752). - The ``syncutil.copytree`` method (#581). - All Crawlers, including ``RegexFileCrawler``, ``MainCrawler``, ``MasterCrawler``, ``SignacProjectCrawler``, and ``BaseCrawler``, in addition to all associated functionality in indexing.py (#580). @@ -40,11 +40,13 @@ Removed - The ability to pass indexes to various ``Project`` methods (#599). - The following ``JobsCursor`` methods: ``groupbydoc``, ``next`` (#601, #604). - The ``Project.config`` property is no longer mutable. Use the command line ``$ signac config`` to modify configuration (#608, #246, #244). - - The following config related functions: ``get_config_file``, ``search_standard_dirs`` (#674). + - The following config related functions: ``get_config``, ``search_standard_dirs`` (#674). - ``Project`` subclasses can no longer define a ``Job`` subclass to use (#588, #693). - The ``Collection`` class (#664, #667, #683). - The ``project`` command line command (#752). - The ``workspace parameter to the command line ``job`` command (#752). + - The ability to call ``Project.workspace``, it is strictly a property now (#752). + - ``ProjectSchema.__call__``, ``ProjectSchema.detect`` (#752). Version 1 ========= From 2808c30cbbd4aaa15a48e29b326e388d8242afa3 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 5 May 2022 21:34:58 -0700 Subject: [PATCH 10/10] Address all PR comments except for renaming init_project parameter. --- changelog.txt | 4 ++-- signac/contrib/project.py | 9 +++------ tests/test_project.py | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index db061b474..623dd5e67 100644 --- a/changelog.txt +++ b/changelog.txt @@ -43,8 +43,8 @@ Removed - The following config related functions: ``get_config``, ``search_standard_dirs`` (#674). - ``Project`` subclasses can no longer define a ``Job`` subclass to use (#588, #693). - The ``Collection`` class (#664, #667, #683). - - The ``project`` command line command (#752). - - The ``workspace parameter to the command line ``job`` command (#752). + - The ``project`` CLI subcommand (#752). + - The ``--workspace`` option for the command line ``job`` subcommand (#752). - The ability to call ``Project.workspace``, it is strictly a property now (#752). - ``ProjectSchema.__call__``, ``ProjectSchema.detect`` (#752). diff --git a/signac/contrib/project.py b/signac/contrib/project.py index a1a2fb92e..1dc242527 100644 --- a/signac/contrib/project.py +++ b/signac/contrib/project.py @@ -48,9 +48,6 @@ JOB_ID_LENGTH = 32 JOB_ID_REGEX = re.compile(f"[a-f0-9]{{{JOB_ID_LENGTH}}}") -# Temporary default for project names until they are removed entirely in signac 2.0 -_DEFAULT_PROJECT_NAME = None - class _ProjectConfig(Config): r"""Extends the project config to make it immutable. @@ -128,8 +125,8 @@ def __init__(self, root=None): # Prepare root directory and workspace paths. # os.path is used instead of pathlib.Path for performance. - self._root_directory = os.path.abspath(root) - self._workspace = os.path.join(self._root_directory, "workspace") + self._path = os.path.abspath(root) + self._workspace = os.path.join(self._path, "workspace") # Prepare workspace directory. if not os.path.isdir(self.workspace): @@ -203,7 +200,7 @@ def config(self): @property def path(self): """str: The path to the project directory.""" - return self._root_directory + return self._path @property def workspace(self): diff --git a/tests/test_project.py b/tests/test_project.py index 780dbe21b..44c1437de 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -711,6 +711,7 @@ def test_schema(self): "f.f2", ): assert k in s + # The following call should not error out. s[k] repr(s) assert s.format() == str(s)