diff --git a/.circleci/config.yml b/.circleci/config.yml index 17f0b9fbf..49f2f4078 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,30 +57,12 @@ jobs: path: test-reports destination: test-reports - linux-python-310-signac-16: - <<: *test-template - environment: - DEPENDENCIES: "NEWEST" - SIGNAC_VERSION: "signac~=1.6.0" - PYTHON: python - linux-python-310-signac-15: - <<: *test-template - environment: - DEPENDENCIES: "NEWEST" - SIGNAC_VERSION: "signac~=1.5.0" - PYTHON: python linux-python-310-signac-latest: <<: *test-template environment: DEPENDENCIES: "NEWEST" SIGNAC_VERSION: "git+ssh://git@github.com/glotzerlab/signac.git" PYTHON: python - linux-python-310-signac-next: - <<: *test-template - environment: - DEPENDENCIES: "NEWEST" - SIGNAC_VERSION: "git+ssh://git@github.com/glotzerlab/signac.git@next" - PYTHON: python linux-python-39: <<: *test-template docker: @@ -95,7 +77,7 @@ jobs: - image: cimg/python:3.8 environment: DEPENDENCIES: "OLDEST" - SIGNAC_VERSION: "signac==1.3.0" + SIGNAC_VERSION: "signac==1.8.0" PYTHON: python test-install-pip-python-310: &test-install-pip @@ -225,16 +207,6 @@ workflows: - linux-python-38-oldest: post-steps: - codecov/upload - - linux-python-310-signac-16: - requires: - - linux-python-310 - post-steps: - - codecov/upload - - linux-python-310-signac-15: - requires: - - linux-python-310 - post-steps: - - codecov/upload - check-metadata: filters: branches: @@ -248,8 +220,6 @@ workflows: - linux-python-39 - linux-python-38 - linux-python-38-oldest - - linux-python-310-signac-16 - - linux-python-310-signac-15 nightly: triggers: - schedule: @@ -260,7 +230,6 @@ workflows: - master jobs: - linux-python-310-signac-latest -# - linux-python-310-signac-next - test-install-pip-python-310 - test-install-pip-python-39 - test-install-pip-python-38 diff --git a/changelog.txt b/changelog.txt index ad6eed1a6..f4c8abeed 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,12 @@ Version 0.23 [0.23.0] -- 20xx-xx-xx +Changed ++++++++ + +- Require ``signac`` version 1.8.0 (#693). +- Deprecated ``alias`` CLI argument to ``flow init`` (#693). + Fixed +++++ diff --git a/doc/doc-project.py b/doc/doc-project.py index 24f0957f8..1a76d9c81 100644 --- a/doc/doc-project.py +++ b/doc/doc-project.py @@ -6,4 +6,4 @@ class DocumentationProject(flow.FlowProject): if __name__ == "__main__": - DocumentationProject.init_project("DocumentationProject").main() + DocumentationProject.init_project().main() diff --git a/flow/__main__.py b/flow/__main__.py index 8c55de530..ce0f0c7c9 100644 --- a/flow/__main__.py +++ b/flow/__main__.py @@ -19,6 +19,7 @@ from signac import get_project, init_project from . import __version__, environment, template +from .util.misc import _deprecated_warning logger = logging.getLogger(__name__) @@ -28,22 +29,20 @@ def main_init(args): The available templates are defined in the template module. """ - if not args.alias.isidentifier(): - raise ValueError( - "The alias '{}' is not a valid Python identifier and can therefore " - "not be used as a FlowProject alias.".format(args.alias) - ) try: get_project() except LookupError: - init_project(name=args.alias) - print( - "Initialized signac project with name '{}' in " - "current directory.".format(args.alias), - file=sys.stderr, - ) + if args.alias != "": + _deprecated_warning( + deprecation="alias", + alternative="", + deprecated_in="0.23.0", + removed_in="0.24.0", + ) + init_project() + print("Initialized signac project in current directory.", file=sys.stderr) try: - return template.init(alias=args.alias, template=args.template) + return template.init(template=args.template) except OSError as error: raise RuntimeError( f"Error occurred while trying to initialize a flow project: {error}" @@ -120,11 +119,8 @@ def main(): "alias", type=str, nargs="?", - default="project", - help="Name of the FlowProject module to initialize. " - "This name will also be used to initialize a signac project if " - "no signac project was initialized prior to calling 'init'. " - "Default value: 'project'.", + default="", + help="Unused, will be removed in flow 0.24.0.", ) parser_init.add_argument( "-t", diff --git a/flow/project.py b/flow/project.py index b55e04a33..9c57d645d 100644 --- a/flow/project.py +++ b/flow/project.py @@ -89,7 +89,7 @@ {template_dir} All template variables can be placed within a template using the standard jinja2 -syntax, e.g., the project root directory can be written as: {{{{ project.root_directory() }}}}. +syntax, e.g., the project root directory can be written as: {{{{ project.path }}}}. The available template variables are: {template_vars} @@ -984,9 +984,8 @@ def _generate_id(self, aggregate, operation_name=None): else: op_string = operation_name - root_directory = project.root_directory() aggregate_id = get_aggregate_id(aggregate) - full_name = f"{root_directory}%{aggregate_id}%{op_string}" + full_name = f"{project.path}%{aggregate_id}%{op_string}" # The job_op_id is a hash computed from the unique full name. job_op_id = md5(full_name.encode("utf-8")).hexdigest() @@ -1569,7 +1568,7 @@ def decorated(*jobs): with jobs[0] as job: if getattr(func, "_flow_cmd", False): return ( - f'trap "cd $(pwd)" EXIT && cd {job.ws} && {func(job)}' + f'trap "cd $(pwd)" EXIT && cd {job.path} && {func(job)}' ) else: return func(job) @@ -1761,7 +1760,7 @@ def __init__(self, config=None, environment=None, entrypoint=None): # the project root directory. This directory may be specified with the 'template_dir' # configuration variable. self._template_dir = os.path.join( - self.root_directory(), self._config.get("template_dir", "templates") + self.path, self._config.get("template_dir", "templates") ) self._template_environment_ = {} @@ -2134,7 +2133,7 @@ def _alias(cls, name): def _fn_bundle(self, bundle_id): """Return the canonical name to store bundle information.""" - return os.path.join(self.root_directory(), ".bundles", bundle_id) + return os.path.join(self.path, ".bundles", bundle_id) def _store_bundled(self, operations): """Store operation-ids as part of a bundle and return bundle id. @@ -4838,7 +4837,7 @@ def _main_run(self, args): if args.switch_to_project_root: with _add_cwd_to_environment_pythonpath(): - with _switch_to_directory(self.root_directory()): + with _switch_to_directory(self.path): run() else: run() diff --git a/flow/template.py b/flow/template.py index 12f0a613e..65e98a01a 100644 --- a/flow/template.py +++ b/flow/template.py @@ -18,13 +18,13 @@ TEMPLATES = { "minimal": [ - ("{alias}.py", "project_minimal.pyt"), + ("project.py", "project_minimal.pyt"), ], "example": [ - ("{alias}.py", "project_example.pyt"), + ("project.py", "project_example.pyt"), ], "testing": [ - ("{alias}.py", "project_testing.pyt"), + ("project.py", "project_testing.pyt"), ], } diff --git a/requirements.txt b/requirements.txt index 4fe3e9b31..6a6696092 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -signac>=1.3.0 +signac>=1.8.0 jinja2>=3.0.0 cloudpickle>=1.6.0 deprecation>=2.0.0 diff --git a/setup.py b/setup.py index 6df7d4164..4145d1240 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ requirements = [ # The core package. - "signac>=1.3.0", + "signac>=1.8.0", # For the templated generation of (submission) scripts. "jinja2>=3.0.0", # To enable the parallelized execution of operations across processes. diff --git a/tests/conftest.py b/tests/conftest.py index 96c1e1770..c5c015181 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -90,9 +90,7 @@ def setUp(self, request): MockScheduler.reset() self._tmp_dir = tempfile.TemporaryDirectory(prefix="signac-flow_") request.addfinalizer(self._tmp_dir.cleanup) - self.project = self.project_class.init_project( - name="FlowTestProject", root=self._tmp_dir.name - ) + self.project = self.project_class.init_project(root=self._tmp_dir.name) self.cwd = os.getcwd() def switch_to_cwd(self): @@ -134,7 +132,7 @@ def call_subcmd(self, subcmd, stderr=subprocess.DEVNULL): _cmd = f"python {fn_script} {subcmd}" try: with _add_path_to_environment_pythonpath(os.path.abspath(self.cwd)): - with _switch_to_directory(self.project.root_directory()): + with _switch_to_directory(self.project.path): return subprocess.check_output(_cmd.split(), stderr=stderr) except subprocess.CalledProcessError as error: print(error, file=sys.stderr) diff --git a/tests/define_status_test_project.py b/tests/define_status_test_project.py index 6cb57ff54..0fee7332a 100644 --- a/tests/define_status_test_project.py +++ b/tests/define_status_test_project.py @@ -39,7 +39,7 @@ def b_is_even(job): @_TestProject.pre(b_is_even) @_TestProject.post.isfile("world.txt") def op1(job): - return f'echo "hello" > {job.ws}/world.txt' + return f'echo "hello" > {job.path}/world.txt' @group1 diff --git a/tests/define_test_project.py b/tests/define_test_project.py index 8fbb64fca..6a836b1ae 100644 --- a/tests/define_test_project.py +++ b/tests/define_test_project.py @@ -48,7 +48,7 @@ def b_is_even(job): @_TestProject.pre(b_is_even) @_TestProject.post.isfile("world.txt") def op1(job): - return f'echo "hello" > {job.ws}/world.txt' + return f'echo "hello" > {job.path}/world.txt' def _need_to_fork(job): diff --git a/tests/extract_status.py b/tests/extract_status.py index 7585260f2..2223f6725 100755 --- a/tests/extract_status.py +++ b/tests/extract_status.py @@ -24,7 +24,7 @@ def main(args): else: return - p = signac.init_project(name=gen.STATUS_OPTIONS_PROJECT_NAME, root=PROJECT_DIR) + p = signac.init_project(root=PROJECT_DIR) p.import_from(origin=gen.ARCHIVE_PATH) diff --git a/tests/extract_templates.py b/tests/extract_templates.py index f7c1d0557..5b28168dd 100755 --- a/tests/extract_templates.py +++ b/tests/extract_templates.py @@ -24,7 +24,7 @@ def main(args): else: return - p = signac.init_project(name=gen.PROJECT_NAME, root=PROJECT_DIR) + p = signac.init_project(root=PROJECT_DIR) p.import_from(origin=gen.ARCHIVE_DIR) diff --git a/tests/generate_status_reference_data.py b/tests/generate_status_reference_data.py index 459396fb4..e65ea902e 100755 --- a/tests/generate_status_reference_data.py +++ b/tests/generate_status_reference_data.py @@ -75,7 +75,7 @@ def main(args): ) as status_pr: init(p) init_status_options(status_pr) - fp = _TestProject.get_project(root=p.root_directory()) + fp = _TestProject.get_project(root=p.path) env = flow.environment.TestEnvironment # We need to set the scheduler manually. The FakeScheduler # won't try to call any cluster executable (e.g. squeue) diff --git a/tests/generate_template_reference_data.py b/tests/generate_template_reference_data.py index fd1da3f2e..d178eb026 100755 --- a/tests/generate_template_reference_data.py +++ b/tests/generate_template_reference_data.py @@ -172,11 +172,11 @@ def _store_bundled(self, operations): def get_masked_flowproject(p, environment=None): """Mock environment-dependent attributes and functions. Need to mock sys.executable before the FlowProject is instantiated, and then modify the - root_directory and project_dir elements after creation.""" + path and project_dir elements after creation.""" try: old_executable = sys.executable sys.executable = MOCK_EXECUTABLE - fp = TestProject.get_project(root=p.root_directory()) + fp = TestProject.get_project(root=p.path) if environment is not None: fp._environment = environment fp._entrypoint.setdefault("path", "generate_template_reference_data.py") @@ -190,10 +190,10 @@ def wrapped_generate_id(self, aggregate, *args, **kwargs): mocking has to happen within this method to avoid affecting other methods called during the test that access the project root directory. """ - old_root_directory = fp.root_directory - fp.root_directory = lambda: PROJECT_DIRECTORY + old_path = fp.path + fp._path = PROJECT_DIRECTORY operation_id = old_generate_id(self, aggregate, *args, **kwargs) - fp.root_directory = old_root_directory + fp._path = old_path return operation_id flow.project.FlowGroup._generate_id = wrapped_generate_id diff --git a/tests/interactive_template_test.py b/tests/interactive_template_test.py index 66b715ded..9931ed8d6 100755 --- a/tests/interactive_template_test.py +++ b/tests/interactive_template_test.py @@ -80,7 +80,7 @@ class Project(flow.FlowProject): with signac.TemporaryProject() as tmp_project: for i in range(num_jobs): tmp_project.open_job(dict(foo=i)).init() - flow_project = Project.get_project(root=tmp_project.root_directory()) + flow_project = Project.get_project(root=tmp_project.path) flow_project._entrypoint.setdefault("path", entrypoint) partition = "" diff --git a/tests/test_directives.py b/tests/test_directives.py index 42de5ddad..46e79c335 100644 --- a/tests/test_directives.py +++ b/tests/test_directives.py @@ -321,7 +321,7 @@ def test_evaluate_directive_valid_job( self, available_directives_list, non_default_directive_values ): _tmp_dir = TemporaryDirectory(prefix="flow-directives_") - FlowProject.init_project(name="DirectivesTest", root=_tmp_dir.name) + FlowProject.init_project(root=_tmp_dir.name) project = FlowProject.get_project(root=_tmp_dir.name) for i in range(5): project.open_job(dict(i=i)).init() diff --git a/tests/test_project.py b/tests/test_project.py index 044147874..ef1a605ea 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -55,7 +55,7 @@ def setup_project_subprocess_execution(project, stderr_output=sys.stderr): Optionally capture stderr with a passed in output or by default output to stderr like normal. """ with _add_cwd_to_environment_pythonpath(), _switch_to_directory( - project.root_directory() + project.path ), redirect_stderr(stderr_output): yield @@ -349,7 +349,7 @@ class A(FlowProject): @A.operation(with_job=True) def test_context(job): - assert os.path.realpath(os.getcwd()) == os.path.realpath(job.ws) + assert os.path.realpath(os.getcwd()) == os.path.realpath(job.path) project = self.mock_project(A) with setup_project_subprocess_execution(project): @@ -2297,7 +2297,7 @@ def call_subcmd(self, subcmd, stderr=subprocess.DEVNULL): _cmd = f"python {fn_script} {subcmd} --debug" with _add_path_to_environment_pythonpath(os.path.abspath(self.cwd)): try: - with _switch_to_directory(self.project.root_directory()): + with _switch_to_directory(self.project.path): return subprocess.check_output(_cmd.split(), stderr=stderr) except subprocess.CalledProcessError as error: print(error, file=sys.stderr) @@ -2452,7 +2452,7 @@ def call_subcmd(self, subcmd, stderr=subprocess.STDOUT): _cmd = f"python {fn_script} {subcmd} --debug" with _add_path_to_environment_pythonpath(os.path.abspath(self.cwd)): try: - with _switch_to_directory(self.project.root_directory()): + with _switch_to_directory(self.project.path): return subprocess.check_output(_cmd.split(), stderr=stderr) except subprocess.CalledProcessError as error: return str(error.output) diff --git a/tests/test_shell.py b/tests/test_shell.py index a84cfca94..9fca3b79d 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -69,17 +69,14 @@ def test_help(self): def test_init_flowproject(self): self.call("python -m flow init".split()) - assert str(signac.get_project()) == "project" assert os.path.exists("project.py") def test_init_flowproject_alias(self): - self.call("python -m flow init my_project".split()) - assert str(signac.get_project()) == "my_project" - assert os.path.exists("my_project.py") + self.call("python -m flow init".split()) + assert os.path.exists("project.py") def test_init_flowproject_fail_if_exists(self): self.call("python -m flow init".split()) - assert str(signac.get_project()) == "project" assert os.path.exists("project.py") with pytest.raises(ExitCodeError): self.call("python -m flow init".split()) @@ -87,7 +84,6 @@ def test_init_flowproject_fail_if_exists(self): @pytest.mark.parametrize("template", flow.template.TEMPLATES) def test_init_flowproject_template(self, template): self.call(f"python -m flow init -t {template}".split()) - assert str(signac.get_project()) == "project" assert os.path.exists("project.py") @pytest.mark.parametrize( diff --git a/tests/test_status.py b/tests/test_status.py index 7f6540da8..6d195257f 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -16,7 +16,7 @@ def test_print_status(): name=gen.STATUS_OPTIONS_PROJECT_NAME ) as status_pr: gen.init(p) - fp = gen._TestProject.get_project(root=p.root_directory()) + fp = gen._TestProject.get_project(root=p.path) status_pr.import_from(origin=gen.ARCHIVE_PATH) for job in status_pr: kwargs = job.statepoint()