From 06e39d7ab415d95a92b493a890c47fe00615a48c Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 2 Feb 2024 10:37:12 +0100 Subject: [PATCH 1/4] Dependencies: Update requirements to address deprecation warnings Following package requirements are updated: * `coverage~=7.0` * `pytest-cov~=4.1` * `pympler~=1.0` * `pyparsing~=3.0` --- pyproject.toml | 8 ++++---- requirements/requirements-py-3.10.txt | 8 ++++---- requirements/requirements-py-3.11.txt | 8 ++++---- requirements/requirements-py-3.12.txt | 8 ++++---- requirements/requirements-py-3.9.txt | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 608ffd2ec7..66084e9d23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -218,7 +218,7 @@ rest = [ 'flask-cors~=3.0', 'flask-restful~=0.3.7', 'flask~=2.2', - 'pyparsing~=2.4', + 'pyparsing~=3.0', 'python-memcached~=1.59', 'seekpath~=1.9,>=1.9.3' ] @@ -233,12 +233,12 @@ tests = [ 'pytest~=7.0', 'pytest-asyncio~=0.12,<0.17', 'pytest-timeout~=2.0', - 'pytest-cov~=2.7,<2.11', + 'pytest-cov~=4.1', 'pytest-rerunfailures~=12.0', 'pytest-benchmark~=4.0', 'pytest-regressions~=2.2', - 'pympler~=0.9', - 'coverage~=6.0', + 'pympler~=1.0', + 'coverage~=7.0', 'sphinx~=7.2', 'docutils~=0.20' ] diff --git a/requirements/requirements-py-3.10.txt b/requirements/requirements-py-3.10.txt index 49255bf99a..fed50236ae 100644 --- a/requirements/requirements-py-3.10.txt +++ b/requirements/requirements-py-3.10.txt @@ -34,7 +34,7 @@ click==8.1.3 click-spinner==0.1.10 comm==0.1.3 contourpy==1.1.0 -coverage==6.5.0 +coverage==7.4.1 cryptography==41.0.1 cycler==0.11.0 debugpy==1.6.7 @@ -136,15 +136,15 @@ pydantic==2.4.0 pydata-sphinx-theme==0.13.3 pygments==2.15.1 pymatgen==2023.9.25 -pympler==0.9 +pympler==1.0.1 pymysql==0.9.3 pynacl==1.5.0 -pyparsing==2.4.7 +pyparsing==3.1.1 pyrsistent==0.19.3 pytest==7.3.2 pytest-asyncio==0.16.0 pytest-benchmark==4.0.0 -pytest-cov==2.10.1 +pytest-cov==4.1.0 pytest-datadir==1.4.1 pytest-regressions==2.4.2 pytest-rerunfailures==12.0.0 diff --git a/requirements/requirements-py-3.11.txt b/requirements/requirements-py-3.11.txt index 67cb01cc35..b6402242f7 100644 --- a/requirements/requirements-py-3.11.txt +++ b/requirements/requirements-py-3.11.txt @@ -34,7 +34,7 @@ click==8.1.3 click-spinner==0.1.10 comm==0.1.3 contourpy==1.1.0 -coverage==6.5.0 +coverage==7.4.1 cryptography==41.0.1 cycler==0.11.0 debugpy==1.6.7 @@ -135,15 +135,15 @@ pydantic==2.4.0 pydata-sphinx-theme==0.13.3 pygments==2.15.1 pymatgen==2023.9.25 -pympler==0.9 +pympler==1.0.1 pymysql==0.9.3 pynacl==1.5.0 -pyparsing==2.4.7 +pyparsing==3.1.1 pyrsistent==0.19.3 pytest==7.3.2 pytest-asyncio==0.16.0 pytest-benchmark==4.0.0 -pytest-cov==2.10.1 +pytest-cov==4.1.0 pytest-datadir==1.4.1 pytest-regressions==2.4.2 pytest-rerunfailures==12.0.0 diff --git a/requirements/requirements-py-3.12.txt b/requirements/requirements-py-3.12.txt index 48fdbf16d8..4e634d5a09 100644 --- a/requirements/requirements-py-3.12.txt +++ b/requirements/requirements-py-3.12.txt @@ -34,7 +34,7 @@ click==8.1.7 click-spinner==0.1.10 comm==0.1.4 contourpy==1.1.1 -coverage==6.5.0 +coverage==7.4.1 cryptography==41.0.5 cycler==0.12.1 debugpy==1.8.0 @@ -133,15 +133,15 @@ pydantic==2.4.0 pydata-sphinx-theme==0.13.3 pygments==2.16.1 pymatgen==2023.10.11 -pympler==0.9 +pympler==1.0.1 pymysql==0.9.3 pynacl==1.5.0 -pyparsing==2.4.7 +pyparsing==3.1.1 pyrsistent==0.19.3 pytest==7.4.2 pytest-asyncio==0.16.0 pytest-benchmark==4.0.0 -pytest-cov==2.10.1 +pytest-cov==4.1.0 pytest-datadir==1.5.0 pytest-regressions==2.5.0 pytest-rerunfailures==12.0.0 diff --git a/requirements/requirements-py-3.9.txt b/requirements/requirements-py-3.9.txt index 8bddc77c50..2d77497e31 100644 --- a/requirements/requirements-py-3.9.txt +++ b/requirements/requirements-py-3.9.txt @@ -34,7 +34,7 @@ click==8.1.3 click-spinner==0.1.10 comm==0.1.3 contourpy==1.1.0 -coverage==6.5.0 +coverage==7.4.1 cryptography==41.0.1 cycler==0.11.0 debugpy==1.6.7 @@ -138,15 +138,15 @@ pydantic==2.4.0 pydata-sphinx-theme==0.13.3 pygments==2.15.1 pymatgen==2023.9.25 -pympler==0.9 +pympler==1.0.1 pymysql==0.9.3 pynacl==1.5.0 -pyparsing==2.4.7 +pyparsing==3.1.1 pyrsistent==0.19.3 pytest==7.3.2 pytest-asyncio==0.16.0 pytest-benchmark==4.0.0 -pytest-cov==2.10.1 +pytest-cov==4.1.0 pytest-datadir==1.4.1 pytest-regressions==2.4.2 pytest-rerunfailures==12.0.0 From 97e9f30207632e60fadbd261241334ad698ef807 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 9 Feb 2024 12:15:45 +0100 Subject: [PATCH 2/4] Runner: Close event loop in `Runner.close()` This prevents leaving open event loops which cause `ResourceWarnings` to be emitted during tests. --- src/aiida/engine/runners.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/aiida/engine/runners.py b/src/aiida/engine/runners.py index c772f0b48c..0d2fcd6d6a 100644 --- a/src/aiida/engine/runners.py +++ b/src/aiida/engine/runners.py @@ -162,6 +162,8 @@ def close(self) -> None: """Close the runner by stopping the loop.""" assert not self._closed self.stop() + if not self._loop.is_running(): + self._loop.close() reset_event_loop_policy() self._closed = True From 3fc0dfa870e3f8f38e19cac1e80a8bd5714ab34e Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Thu, 1 Feb 2024 13:34:50 +0100 Subject: [PATCH 3/4] Devops: Address internal deprecation warnings --- docs/source/topics/processes/functions.rst | 2 +- pyproject.toml | 5 +- .../engine/processes/calcjobs/calcjob.py | 2 +- .../storage/sqlite_zip/migrations/utils.py | 15 +++--- src/aiida/transports/util.py | 8 +++ tests/cmdline/commands/test_node.py | 13 +++-- tests/cmdline/params/options/test_config.py | 50 ++++++++++--------- .../params/options/test_interactive.py | 1 - .../processes/calcjobs/test_calc_job.py | 2 +- .../processes/workchains/test_restart.py | 6 ++- tests/engine/test_calcfunctions.py | 2 +- tests/engine/test_process.py | 2 +- tests/engine/test_process_function.py | 12 ++--- tests/engine/test_runners.py | 2 +- tests/manage/test_caching_config.py | 34 ++++++------- tests/orm/data/code/test_installed.py | 4 +- tests/orm/data/code/test_portable.py | 4 +- tests/orm/nodes/data/test_trajectory.py | 2 +- tests/orm/nodes/process/test_process.py | 2 +- tests/orm/test_groups.py | 18 ++++--- tests/orm/test_querybuilder.py | 2 +- tests/orm/utils/test_managers.py | 13 +++-- tests/restapi/conftest.py | 2 +- 23 files changed, 116 insertions(+), 87 deletions(-) diff --git a/docs/source/topics/processes/functions.rst b/docs/source/topics/processes/functions.rst index 9863e0092a..c03fcf074e 100644 --- a/docs/source/topics/processes/functions.rst +++ b/docs/source/topics/processes/functions.rst @@ -345,7 +345,7 @@ They can be accessed through the corresponding properties on the process node as :code: python The source code of the file in which the function is defined is also stored, but since it can be quite big, it is stored as a raw file in the repository of the process node. -It can be retrieved through the :py:meth:`~aiida.orm.utils.mixins.FunctionCalculationMixin.get_function_source_code` method. +It can be retrieved through the :py:meth:`~aiida.orm.utils.mixins.FunctionCalculationMixin.get_source_code_file` method. The attributes give some querability to the process functions stored in the provenance graph and by storing the source code of the function that was executed, there will be some reference in the future to track how the function created its output nodes. Note, however, that just storing the source file of the function does not guarantee that one can reproduce the exact result. diff --git a/pyproject.toml b/pyproject.toml index 66084e9d23..e54324e131 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -356,8 +356,11 @@ filterwarnings = [ 'ignore::DeprecationWarning:pymatgen:', 'ignore::DeprecationWarning:jsonbackend:', 'ignore::DeprecationWarning:pkg_resources:', - 'ignore:Object of type .* not in session, .* operation along .* will not proceed:sqlalchemy.exc.SAWarning', 'ignore::pytest.PytestCollectionWarning', + 'ignore:Creating AiiDA configuration folder.*:UserWarning', + 'ignore:Object of type .* not in session, .* operation along .* will not proceed:sqlalchemy.exc.SAWarning', + 'ignore:The `aiida.orm.nodes.data.upf` module is deprecated.*:aiida.common.warnings.AiidaDeprecationWarning', + 'ignore:The `Code` class is deprecated.*:aiida.common.warnings.AiidaDeprecationWarning', 'default::ResourceWarning' ] markers = [ diff --git a/src/aiida/engine/processes/calcjobs/calcjob.py b/src/aiida/engine/processes/calcjobs/calcjob.py index 9fd8969034..d51115ebe2 100644 --- a/src/aiida/engine/processes/calcjobs/calcjob.py +++ b/src/aiida/engine/processes/calcjobs/calcjob.py @@ -548,7 +548,7 @@ def run(self) -> Union[plumpy.process_states.Stop, int, plumpy.process_states.Wa # this case, the parser will not be called. The outputs will already have been added to the process node # though, so all that needs to be done here is just also assign them to the process instance. This such that # when the process returns its results, it returns the actual outputs and not an empty dictionary. - self._outputs = self.node.get_outgoing(link_type=LinkType.CREATE).nested() + self._outputs = self.node.base.links.get_outgoing(link_type=LinkType.CREATE).nested() return self.node.exit_status # Launch the upload operation diff --git a/src/aiida/storage/sqlite_zip/migrations/utils.py b/src/aiida/storage/sqlite_zip/migrations/utils.py index cbd84330f7..944fe7d429 100644 --- a/src/aiida/storage/sqlite_zip/migrations/utils.py +++ b/src/aiida/storage/sqlite_zip/migrations/utils.py @@ -143,13 +143,14 @@ def copy_tar_to_zip( temp_extracted = Path(tmpdirname) / 'extracted' with get_progress_reporter()(total=1) as progress: callback = create_callback(progress) - TarPath(inpath, mode='r:*').extract_tree( - temp_extracted, - allow_dev=False, - allow_symlink=False, - callback=callback, - cb_descript=f'{title} (extracting tar)', - ) + with TarPath(inpath, mode='r:*') as path: + path.extract_tree( + temp_extracted, + allow_dev=False, + allow_symlink=False, + callback=callback, + cb_descript=f'{title} (extracting tar)', + ) temp_archive = Path(tmpdirname) / 'archive.zip' with ZipPath(temp_archive, mode='w', compresslevel=compression, info_order=info_order) as new_path: length = sum(1 for _ in temp_extracted.glob('**/*')) diff --git a/src/aiida/transports/util.py b/src/aiida/transports/util.py index 1307220d73..12d3b3d882 100644 --- a/src/aiida/transports/util.py +++ b/src/aiida/transports/util.py @@ -64,6 +64,14 @@ def close(self): break time.sleep(0.2) + for f in [self.process.stdout, self.process.stderr, self.process.stdin]: + if f is None: + continue + try: + f.close() + except ValueError: + pass + def copy_from_remote_to_remote(transportsource, transportdestination, remotesource, remotedestination, **kwargs): """Copy files or folders from a remote computer to another remote computer. diff --git a/tests/cmdline/commands/test_node.py b/tests/cmdline/commands/test_node.py index a91fbbeb56..a3bbf2e0a1 100644 --- a/tests/cmdline/commands/test_node.py +++ b/tests/cmdline/commands/test_node.py @@ -11,6 +11,7 @@ import gzip import io import os +import warnings import pytest from aiida import orm @@ -401,11 +402,13 @@ def test_node_id_label_format(self, run_cli_command): @pytest.mark.parametrize('output_file', ('without_extension', 'without_extension.pdf')) def test_output_file(self, run_cli_command, output_file): """Test that the output file can be specified through an argument.""" - try: - run_cli_command(cmd_node.graph_generate, [str(self.node.pk), output_file]) - assert os.path.isfile(output_file) - finally: - delete_temporary_file(output_file) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + try: + run_cli_command(cmd_node.graph_generate, [str(self.node.pk), output_file]) + assert os.path.isfile(output_file) + finally: + delete_temporary_file(output_file) COMMENT = 'Well I never...' diff --git a/tests/cmdline/params/options/test_config.py b/tests/cmdline/params/options/test_config.py index c18029a4e8..d6dcd1e7e6 100644 --- a/tests/cmdline/params/options/test_config.py +++ b/tests/cmdline/params/options/test_config.py @@ -8,7 +8,6 @@ ########################################################################### """Unit tests for the :class:`aiida.cmdline.params.options.config.ConfigOption`.""" import functools -import tempfile import textwrap import click @@ -32,37 +31,40 @@ def cmd(integer, boolean): click.echo(f'Boolean: {boolean}') -def test_valid(run_cli_command): +def test_valid(run_cli_command, tmp_path): """Test the option for a valid configuration file.""" - with tempfile.NamedTemporaryFile('w+') as handle: - handle.write( - textwrap.dedent( - """ + filepath = tmp_path / 'config.yml' + filepath.write_text( + textwrap.dedent( + """ integer: 1 boolean: false - """ - ) + """ ) - handle.flush() + ) - result = run_cli_command(cmd, ['--config', handle.name]) - assert 'Integer: 1' in result.output_lines[0] - assert 'Boolean: False' in result.output_lines[1] + result = run_cli_command(cmd, ['--config', str(filepath)]) + assert 'Integer: 1' in result.output_lines[0] + assert 'Boolean: False' in result.output_lines[1] -def test_invalid_unknown_keys(run_cli_command): - """Test the option for an invalid configuration file containing unknown keys.""" - with tempfile.NamedTemporaryFile('w+') as handle: - handle.write( - textwrap.dedent( - """ +@pytest.mark.filterwarnings('ignore') +def test_invalid_unknown_keys(run_cli_command, tmp_path): + """Test the option for an invalid configuration file containing unknown keys. + + The test emits a ``ResourceWarning`` because the config file is not closed since the command errors, but this is + just a side-effect of how the test is run and doesn't apply to the real CLI command invocation. + """ + filepath = tmp_path / 'config.yml' + filepath.write_text( + textwrap.dedent( + """ integer: 1 unknown: 2.0 - """ - ) + """ ) - handle.flush() + ) - result = run_cli_command(cmd, ['--config', handle.name], raises=True) - assert "Error: Invalid value for '--config': Invalid configuration file" in result.stderr - assert "the following keys are not supported: {'unknown'}" in result.stderr + result = run_cli_command(cmd, ['--config', str(filepath)], raises=True) + assert "Error: Invalid value for '--config': Invalid configuration file" in result.stderr + assert "the following keys are not supported: {'unknown'}" in result.stderr diff --git a/tests/cmdline/params/options/test_interactive.py b/tests/cmdline/params/options/test_interactive.py index b4397c7032..6a13a7a6ca 100644 --- a/tests/cmdline/params/options/test_interactive.py +++ b/tests/cmdline/params/options/test_interactive.py @@ -295,7 +295,6 @@ def test_default_value_prompt(run_cli_command): returns.append(result) expected = 'Opt [default]: TEST\nTEST\n' assert expected in result.output - return returns def test_default_value_empty_opt(run_cli_command): diff --git a/tests/engine/processes/calcjobs/test_calc_job.py b/tests/engine/processes/calcjobs/test_calc_job.py index 817163df60..5a867df59b 100644 --- a/tests/engine/processes/calcjobs/test_calc_job.py +++ b/tests/engine/processes/calcjobs/test_calc_job.py @@ -507,7 +507,7 @@ def test_get_hash(self, get_calcjob_builder): """Test that :meth:`aiida.orm.CalcJobNode.get_hash` returns the same hash as what is stored in the extras.""" builder = get_calcjob_builder() _, node = launch.run_get_node(builder) - assert node.base.extras.get(node.base.caching._HASH_EXTRA_KEY) == node.get_hash() + assert node.base.extras.get(node.base.caching._HASH_EXTRA_KEY) == node.base.caching.get_hash() def test_process_status(self): """Test that the process status is properly reset if calculation ends successfully.""" diff --git a/tests/engine/processes/workchains/test_restart.py b/tests/engine/processes/workchains/test_restart.py index c94113a5cf..7518b7d7a5 100644 --- a/tests/engine/processes/workchains/test_restart.py +++ b/tests/engine/processes/workchains/test_restart.py @@ -7,6 +7,8 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Tests for `aiida.engine.processes.workchains.restart` module.""" +import warnings + import pytest from aiida import engine, orm from aiida.engine.processes.workchains.awaitable import Awaitable @@ -66,7 +68,9 @@ def test_get_process_handlers(): ) def test_get_process_handlers_by_priority(generate_work_chain, inputs, priorities): """Test the `BaseRestartWorkChain.get_process_handlers_by_priority` method.""" - process = generate_work_chain(SomeWorkChain, inputs) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + process = generate_work_chain(SomeWorkChain, inputs) process.setup() assert sorted([priority for priority, handler in process.get_process_handlers_by_priority()]) == priorities diff --git a/tests/engine/test_calcfunctions.py b/tests/engine/test_calcfunctions.py index 5ea6aa2512..9e4785cada 100644 --- a/tests/engine/test_calcfunctions.py +++ b/tests/engine/test_calcfunctions.py @@ -109,7 +109,7 @@ def test_calcfunction_caching_change_code(self): result_cached, cached = add_calcfunction.run_get_node(self.default_int) assert result_original != result_cached assert not cached.base.caching.is_created_from_cache - assert cached.is_valid_cache + assert cached.base.caching.is_valid_cache # Test that the locally-created calcfunction can be cached in principle result2_cached, cached2 = add_calcfunction.run_get_node(self.default_int) diff --git a/tests/engine/test_process.py b/tests/engine/test_process.py index d21d689324..87e4ffb850 100644 --- a/tests/engine/test_process.py +++ b/tests/engine/test_process.py @@ -477,7 +477,7 @@ def define(cls, spec): spec.input('any_type', required=False) -@pytest.mark.usefixtures('clear_database_before_test') +@pytest.mark.usefixtures('aiida_profile_clean') def test_not_required_accepts_none(): """Test that a port that is not required, accepts ``None``.""" from aiida.engine.utils import instantiate_process diff --git a/tests/engine/test_process_function.py b/tests/engine/test_process_function.py index 0399423938..375bc38c54 100644 --- a/tests/engine/test_process_function.py +++ b/tests/engine/test_process_function.py @@ -198,7 +198,7 @@ def test_process_function(data): _, node = test_process_function.run_get_node(data=orm.Int(5)) # Read the source file of the calculation function that should be stored in the repository - function_source_code = node.get_function_source_code().split('\n') + function_source_code = node.get_source_code_file().split('\n') # Verify that the function name is correct and the first source code linenumber is stored assert node.function_name == function_name @@ -214,8 +214,8 @@ def test_process_function(data): assert node.function_name in function_name_from_source -def test_get_function_source_code(): - """Test that ``get_function_source_code`` returns ``None`` if no source code was stored. +def test_get_source_code_file(): + """Test that ``get_source_code_file`` returns ``None`` if no source code was stored. This is the case for example for functions defined in an interactive shell, where the retrieval of the source code upon storing the node fails and nothing is stored. The function should not except in this case. @@ -227,7 +227,7 @@ def test_get_function_source_code(): # Delete the source file by going down to the ``RepositoryBackend`` to circumvent the immutability check. node.base.repository._repository.delete_object(FunctionCalculationMixin.FUNCTION_SOURCE_FILE_PATH) - assert node.get_function_source_code() is None + assert node.get_source_code_file() is None def test_function_varargs(): @@ -236,7 +236,7 @@ def test_function_varargs(): assert isinstance(result, orm.Str) assert result.value == 'a b c d' - inputs = node.get_incoming().nested() + inputs = node.base.links.get_incoming().nested() assert inputs['str_a'].value == 'a' assert inputs['str_b'].value == 'b' assert inputs['args_0'].value == 'c' @@ -648,7 +648,7 @@ def function(**kwargs): } results, node = function.run_get_node(**inputs) assert results == inputs - assert node.get_incoming().nested() == inputs + assert node.base.links.get_incoming().nested() == inputs inputs = { 'nested': { diff --git a/tests/engine/test_runners.py b/tests/engine/test_runners.py index 77e9f9f569..80463aaefe 100644 --- a/tests/engine/test_runners.py +++ b/tests/engine/test_runners.py @@ -93,7 +93,7 @@ def test_run_return_value_cached(aiida_local_code_factory): 'y': Int(-2), } results_source, node_source = launch.run_get_node(ArithmeticAddCalculation, **inputs) - assert node_source.is_valid_cache + assert node_source.base.caching.is_valid_cache with enable_caching(): results_cached, node_cached = launch.run_get_node(ArithmeticAddCalculation, **inputs) diff --git a/tests/manage/test_caching_config.py b/tests/manage/test_caching_config.py index 2010296ffa..e867802ca9 100644 --- a/tests/manage/test_caching_config.py +++ b/tests/manage/test_caching_config.py @@ -7,11 +7,9 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Tests for the functionality that reads and modifies the caching configuration file.""" - - import contextlib import json -from pathlib import Path +import pathlib import pytest import yaml @@ -60,7 +58,7 @@ def test_merge_deprecated_yaml(tmp_path): # Create a temporary folder, set it as the current config directory path settings.AIIDA_CONFIG_FOLDER = str(tmp_path) config_dictionary = json.loads( - Path(__file__) + pathlib.Path(__file__) .parent.joinpath('configuration/migrations/test_samples/reference/6.json') .read_text(encoding='utf-8') ) @@ -146,19 +144,19 @@ def test_default(configure_caching): ( { 'default_enabled': True, - 'enabled_for': ['aiida.calculations:arithmetic.add'], + 'enabled_for': ['aiida.calculations:core.arithmetic.add'], 'disabled_for': ['aiida.calculations:core.templatereplacer'], }, - ['some_identifier', 'aiida.calculations:arithmetic.add', 'aiida.calculations:TEMPLATEREPLACER'], + ['some_identifier', 'aiida.calculations:core.arithmetic.add', 'aiida.calculations:TEMPLATEREPLACER'], ['aiida.calculations:core.templatereplacer'], ), ( { 'default_enabled': False, - 'enabled_for': ['aiida.calculations:arithmetic.add'], + 'enabled_for': ['aiida.calculations:core.arithmetic.add'], 'disabled_for': ['aiida.calculations:core.templatereplacer'], }, - ['aiida.calculations:arithmetic.add'], + ['aiida.calculations:core.arithmetic.add'], ['aiida.calculations:core.templatereplacer', 'some_identifier'], ), ( @@ -166,7 +164,7 @@ def test_default(configure_caching): 'default_enabled': False, 'enabled_for': ['aiida.calculations:*'], }, - ['aiida.calculations:core.templatereplacer', 'aiida.calculations:arithmetic.add'], + ['aiida.calculations:core.templatereplacer', 'aiida.calculations:core.arithmetic.add'], ['some_identifier'], ), ( @@ -174,25 +172,25 @@ def test_default(configure_caching): 'default_enabled': False, 'enabled_for': ['aiida.calcul*'], }, - ['aiida.calculations:core.templatereplacer', 'aiida.calculations:arithmetic.add'], + ['aiida.calculations:core.templatereplacer', 'aiida.calculations:core.arithmetic.add'], ['some_identifier'], ), ( { 'default_enabled': False, 'enabled_for': ['aiida.calculations:*'], - 'disabled_for': ['aiida.calculations:arithmetic.add'], + 'disabled_for': ['aiida.calculations:core.arithmetic.add'], }, - ['aiida.calculations:core.templatereplacer', 'aiida.calculations:ARIthmetic.add'], - ['some_identifier', 'aiida.calculations:arithmetic.add'], + ['aiida.calculations:core.templatereplacer', 'aiida.calculations:core.ARIthmetic.add'], + ['some_identifier', 'aiida.calculations:core.arithmetic.add'], ), ( { 'default_enabled': False, - 'enabled_for': ['aiida.calculations:ar*thmetic.add'], + 'enabled_for': ['aiida.calculations:core.ar*thmetic.add'], 'disabled_for': ['aiida.calculations:*'], }, - ['aiida.calculations:arithmetic.add', 'aiida.calculations:arblarghthmetic.add'], + ['aiida.calculations:core.arithmetic.add', 'aiida.calculations:core.arblarghthmetic.add'], ['some_identifier', 'aiida.calculations:core.templatereplacer'], ), ], @@ -221,11 +219,11 @@ def test_configuration(configure_caching, config_dict, enabled_for, disabled_for ( { 'default_enabled': False, - 'enabled_for': ['aiida.calculations:arithmetic.add'], - 'disabled_for': ['aiida.calculations:arithmetic.add'], + 'enabled_for': ['aiida.calculations:core.arithmetic.add'], + 'disabled_for': ['aiida.calculations:core.arithmetic.add'], }, ['some_identifier', 'aiida.calculations:core.templatereplacer'], - ['aiida.calculations:arithmetic.add'], + ['aiida.calculations:core.arithmetic.add'], ), ], ) diff --git a/tests/orm/data/code/test_installed.py b/tests/orm/data/code/test_installed.py index f8f9458c5b..5081a7681b 100644 --- a/tests/orm/data/code/test_installed.py +++ b/tests/orm/data/code/test_installed.py @@ -11,6 +11,7 @@ import pytest from aiida.common.exceptions import ModificationNotAllowed, ValidationError +from aiida.common.warnings import AiidaDeprecationWarning from aiida.orm import Computer from aiida.orm.nodes.data.code.installed import InstalledCode @@ -128,4 +129,5 @@ def test_full_label(aiida_localhost): def test_get_execname(aiida_localhost): """Test the deprecated :meth:`aiida.orm.nodes.data.code.installed.InstalledCode.get_execname` method.""" code = InstalledCode(label='some-label', computer=aiida_localhost, filepath_executable='/usr/bin/bash') - assert code.get_execname() == '/usr/bin/bash' + with pytest.warns(AiidaDeprecationWarning): + assert code.get_execname() == '/usr/bin/bash' diff --git a/tests/orm/data/code/test_portable.py b/tests/orm/data/code/test_portable.py index 2881e1469c..f577de636b 100644 --- a/tests/orm/data/code/test_portable.py +++ b/tests/orm/data/code/test_portable.py @@ -12,6 +12,7 @@ import pytest from aiida.common.exceptions import ModificationNotAllowed, ValidationError +from aiida.common.warnings import AiidaDeprecationWarning from aiida.orm.nodes.data.code.portable import PortableCode @@ -92,4 +93,5 @@ def test_full_label(tmp_path): def test_get_execname(tmp_path): """Test the deprecated :meth:`aiida.orm.nodes.data.code.portable.PortableCode.get_execname` method.""" code = PortableCode(label='some-label', filepath_executable='bash', filepath_files=tmp_path) - assert code.get_execname() == 'bash' + with pytest.warns(AiidaDeprecationWarning): + assert code.get_execname() == 'bash' diff --git a/tests/orm/nodes/data/test_trajectory.py b/tests/orm/nodes/data/test_trajectory.py index c99bc9f4ea..2fc26ab258 100644 --- a/tests/orm/nodes/data/test_trajectory.py +++ b/tests/orm/nodes/data/test_trajectory.py @@ -135,7 +135,7 @@ def test_trajectory_get_step_structure(self, trajectory_data): structure.store() expected.store() - assert structure.get_hash() == expected.get_hash() + assert structure.base.caching.get_hash() == expected.base.caching.get_hash() with pytest.raises(IndexError): trajectory.get_step_structure(500) diff --git a/tests/orm/nodes/process/test_process.py b/tests/orm/nodes/process/test_process.py index c5e0d0cef9..ea31554ea1 100644 --- a/tests/orm/nodes/process/test_process.py +++ b/tests/orm/nodes/process/test_process.py @@ -68,4 +68,4 @@ def process_nodes(): def test_is_valid_cache(process_nodes): """Test the :meth:`aiida.orm.nodes.process.process.ProcessNode.is_valid_cache` property.""" for node, is_valid_cache in process_nodes: - assert node.is_valid_cache == is_valid_cache, node + assert node.base.caching.is_valid_cache == is_valid_cache, node diff --git a/tests/orm/test_groups.py b/tests/orm/test_groups.py index c5bbe90b6d..6a59ee34d7 100644 --- a/tests/orm/test_groups.py +++ b/tests/orm/test_groups.py @@ -90,7 +90,9 @@ def test_entry_point(self): class Custom(orm.Group): pass - group = Custom('label') + with pytest.warns(UserWarning, match=r'no registered entry point for .* its instances will not be storable.'): + group = Custom('label') + assert group.entry_point is None assert Custom.entry_point is None @@ -324,20 +326,20 @@ def test_loading(): def test_creation_unregistered(): """Test rules around creating `Group` subclasses without a registered entry point.""" # Defining an unregistered subclas should issue a warning and its type string should be set to `None` - with pytest.warns(UserWarning): + with pytest.warns(UserWarning, match=r'no registered entry point for .* its instances will not be storable.'): class SubGroup(orm.Group): pass assert SubGroup._type_string is None - # Creating an instance is allowed - instance = SubGroup(label=uuid.uuid4().hex) - assert instance._type_string is None + # Creating an instance is allowed + instance = SubGroup(label=uuid.uuid4().hex) + assert instance._type_string is None - # Storing the instance, however, is forbidden and should raise - with pytest.raises(exceptions.StoringNotAllowed): - instance.store() + # Storing the instance, however, is forbidden and should raise + with pytest.raises(exceptions.StoringNotAllowed): + instance.store() @staticmethod def test_loading_unregistered(): diff --git a/tests/orm/test_querybuilder.py b/tests/orm/test_querybuilder.py index a2618612ad..584ff657ef 100644 --- a/tests/orm/test_querybuilder.py +++ b/tests/orm/test_querybuilder.py @@ -1474,7 +1474,7 @@ def test_iterall_with_mutation(self): node.base.extras.set('key', 'value') for pk in pks: - assert orm.load_node(pk).get_extra('key') == 'value' + assert orm.load_node(pk).base.extras.get('key') == 'value' @pytest.mark.usefixtures('aiida_profile_clean') def test_iterall_with_store(self): diff --git a/tests/orm/utils/test_managers.py b/tests/orm/utils/test_managers.py index 1acc0dc4d3..80ae7cac52 100644 --- a/tests/orm/utils/test_managers.py +++ b/tests/orm/utils/test_managers.py @@ -7,10 +7,13 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Tests for the various node managers (.inputs, .outputs, .dict, ...).""" +import warnings + import pytest from aiida import orm from aiida.common import AttributeDict, LinkType from aiida.common.exceptions import NotExistent, NotExistentAttributeError, NotExistentKeyError +from aiida.common.warnings import AiidaDeprecationWarning def test_dot_dict_manager(): @@ -166,12 +169,12 @@ def test_link_manager_with_nested_namespaces(): assert calc.outputs.nested__sub__namespace.uuid == out1.uuid # Dunder methods should not invoke the deprecation warning - with pytest.warns(None) as record: + with warnings.catch_warnings(): + warnings.simplefilter('error') try: calc.inputs.__name__ except AttributeError: pass - assert not record, print(record.list[0].message) # Must raise a AttributeError, otherwise tab competion will not work for attribute in ['not_existent', 'not__existent__nested']: @@ -185,10 +188,12 @@ def test_link_manager_with_nested_namespaces(): # Note that `remote_folder` corresponds to an actual leaf node, but it is treated like an intermediate namespace with pytest.raises(AttributeError): - _ = calc.outputs.remote_folder__namespace + with pytest.warns(AiidaDeprecationWarning): + _ = calc.outputs.remote_folder__namespace with pytest.raises(KeyError): - _ = calc.outputs['remote_folder__namespace'] + with pytest.warns(AiidaDeprecationWarning): + _ = calc.outputs['remote_folder__namespace'] def test_link_manager_contains(): diff --git a/tests/restapi/conftest.py b/tests/restapi/conftest.py index 744f4463c3..7f53173268 100644 --- a/tests/restapi/conftest.py +++ b/tests/restapi/conftest.py @@ -80,7 +80,7 @@ def populate_restapi_database(): """Populates the database with a considerable set of nodes to test the restAPI""" from aiida import orm - struct_forcif = orm.StructureData(pbc=False).store() + struct_forcif = orm.StructureData(pbc=False, cell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]).store() orm.StructureData(pbc=False).store() orm.StructureData(pbc=False).store() From a9d7f92126cc4fbf9f1b6bbcae0c76184389c66e Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Wed, 14 Feb 2024 15:31:58 +0100 Subject: [PATCH 4/4] ORM: Undo deprecation of `Code.get_description` The `get_description` method was unjustly deprecated in favor of the `description` property. However, the latter is just a direct reference to the `description` column of the database model. This is an optional string that can be defined by the user when the instance is created. The `get_description` method rather, which is defined on the `Node` base class, is intended to return a description composed from relevant properties of the node. These are therefore not the same. The deprecation is undone and it now returns `Code.full_label`. --- src/aiida/orm/nodes/data/code/legacy.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/aiida/orm/nodes/data/code/legacy.py b/src/aiida/orm/nodes/data/code/legacy.py index 44f0bfd901..53e5e2272a 100644 --- a/src/aiida/orm/nodes/data/code/legacy.py +++ b/src/aiida/orm/nodes/data/code/legacy.py @@ -169,10 +169,7 @@ def get_description(self): :return: string description of this Code instance """ - warn_deprecation( - '`Code.get_description` method is deprecated, use the `description` property instead.', version=3 - ) - return f'{self.description}' + return self.full_label @classmethod def get_code_helper(cls, label, machinename=None, backend=None):