diff --git a/.github/system_tests/pytest/test_memory_leaks.py b/.github/system_tests/pytest/test_memory_leaks.py index 396793346f..cdd7a536ab 100644 --- a/.github/system_tests/pytest/test_memory_leaks.py +++ b/.github/system_tests/pytest/test_memory_leaks.py @@ -8,6 +8,10 @@ # For further information please visit http://www.aiida.net # ########################################################################### """Utilities for testing memory leakage.""" +import sys + +import pytest + from aiida import orm from aiida.engine import processes, run_get_node from aiida.plugins import CalculationFactory @@ -23,6 +27,7 @@ def run_finished_ok(*args, **kwargs): assert node.is_finished_ok, (node.exit_status, node.exit_message) +@pytest.mark.skipif(sys.version_info >= (3, 12), reason='Garbage collecting hangs on Python 3.12') def test_leak_run_process(): """Test whether running a dummy process leaks memory.""" inputs = {'a': orm.Int(2), 'b': orm.Str('test')} @@ -34,6 +39,7 @@ def test_leak_run_process(): assert not process_instances, f'Memory leak: process instances remain in memory: {process_instances}' +@pytest.mark.skipif(sys.version_info >= (3, 12), reason='Garbage collecting hangs on Python 3.12') def test_leak_local_calcjob(aiida_local_code_factory): """Test whether running a local CalcJob leaks memory.""" inputs = {'x': orm.Int(1), 'y': orm.Int(2), 'code': aiida_local_code_factory('core.arithmetic.add', '/bin/bash')} @@ -45,6 +51,7 @@ def test_leak_local_calcjob(aiida_local_code_factory): assert not process_instances, f'Memory leak: process instances remain in memory: {process_instances}' +@pytest.mark.skipif(sys.version_info >= (3, 12), reason='Garbage collecting hangs on Python 3.12') def test_leak_ssh_calcjob(): """Test whether running a CalcJob over SSH leaks memory. diff --git a/.github/workflows/ci-code.yml b/.github/workflows/ci-code.yml index 2d91760f67..cb77c2f137 100644 --- a/.github/workflows/ci-code.yml +++ b/.github/workflows/ci-code.yml @@ -23,10 +23,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up Python 3.9 + - name: Set up Python 3.12 uses: actions/setup-python@v2 with: - python-version: '3.9' + python-version: '3.12' - name: Install utils/ dependencies run: pip install -r utils/requirements.txt @@ -55,7 +55,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.11'] + python-version: ['3.9', '3.12'] services: postgres: @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.11'] + python-version: ['3.9', '3.12'] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/test-install.yml b/.github/workflows/test-install.yml index d25c6b9c24..e3d17ae742 100644 --- a/.github/workflows/test-install.yml +++ b/.github/workflows/test-install.yml @@ -58,7 +58,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12'] steps: - uses: actions/checkout@v2 @@ -144,7 +144,7 @@ jobs: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12'] # Not being able to install with conda on a specific Python version is # not sufficient to fail the run, but something we want to be aware of. @@ -195,7 +195,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12'] services: postgres: diff --git a/aiida/sphinxext/__init__.py b/aiida/sphinxext/__init__.py index 6ea2aa4cc9..8052d877c4 100644 --- a/aiida/sphinxext/__init__.py +++ b/aiida/sphinxext/__init__.py @@ -16,7 +16,6 @@ def setup(app): from . import calcjob, process, workchain - app.setup_extension('sphinxcontrib.details.directive') process.setup_extension(app) workchain.setup_extension(app) calcjob.setup_extension(app) diff --git a/aiida/sphinxext/process.py b/aiida/sphinxext/process.py index 759617f5e2..5610ab1fb9 100644 --- a/aiida/sphinxext/process.py +++ b/aiida/sphinxext/process.py @@ -20,7 +20,6 @@ from sphinx import addnodes from sphinx.ext.autodoc import ClassDocumenter from sphinx.util.docutils import SphinxDirective -from sphinxcontrib.details.directive import details, summary from aiida.common.utils import get_object_from_string from aiida.engine import Process @@ -156,12 +155,7 @@ def build_portnamespace_doctree(self, port_namespace): if port.help is not None: item += nodes.Text(' -- ') item.extend(publish_doctree(port.help)[0].children) - sub_doctree = self.build_portnamespace_doctree(port) - if sub_doctree: - sub_item = details(opened=self.EXPAND_NAMESPACES_FLAG in self.options) - sub_item += summary(text='Namespace Ports') - sub_item += sub_doctree - item += sub_item + item += self.build_portnamespace_doctree(port) else: raise NotImplementedError result += item diff --git a/pyproject.toml b/pyproject.toml index 0eaa9195b7..07823b57b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering" ] keywords = ["aiida", "workflows"] @@ -78,15 +79,14 @@ rest = [ ] docs = [ "pydata-sphinx-theme~=0.13.3", - "sphinx~=4.1", - "sphinxcontrib-details-directive~=0.1.0", + "sphinx~=7.2", "sphinx-copybutton~=0.5.0", - "sphinx-design~=0.0.13", - "sphinx-notfound-page~=0.5", + "sphinx-design~=0.5.0", + "sphinx-notfound-page~=1.0", "sphinxext-rediraffe~=0.2.4", # "sphinx-sqlalchemy~=0.1.1", "sphinx-intl~=2.1.0", - "myst-nb~=0.17.0", + "myst-nb~=1.0.0", ] atomic_tools = [ "PyCifRW~=4.4", @@ -104,7 +104,7 @@ notebook = [ ] pre-commit = [ "mypy==0.991", - "packaging~=20.9", + "packaging~=23.0", "pre-commit~=2.2", "pylint~=2.17.4", "pylint-aiida~=0.1.1", @@ -118,15 +118,15 @@ tests = [ "pgtest~=1.3,>=1.3.1", "pytest~=7.0", "pytest-asyncio~=0.12,<0.17", - "pytest-timeout~=1.3", + "pytest-timeout~=2.0", "pytest-cov~=2.7,<2.11", - "pytest-rerunfailures~=9.1,>=9.1.1", + "pytest-rerunfailures~=12.0", "pytest-benchmark~=4.0", "pytest-regressions~=2.2", "pympler~=0.9", "coverage~=6.0", - "sphinx~=4.0", - "docutils==0.16", + "sphinx~=7.2", + "docutils~=0.20", ] bpython = [ "bpython~=0.18.0" diff --git a/requirements/requirements-py-3.10.txt b/requirements/requirements-py-3.10.txt index e7231a59c3..181c516203 100644 --- a/requirements/requirements-py-3.10.txt +++ b/requirements/requirements-py-3.10.txt @@ -43,7 +43,8 @@ defusedxml==0.7.1 deprecation==2.1.0 disk-objectstore==1.0.0 docstring-parser==0.15 -docutils==0.16 +docutils==0.20.1 +emmet-core==0.57.1 exceptiongroup==1.1.1 executing==1.2.0 fastjsonschema==2.17.1 @@ -81,19 +82,19 @@ kiwisolver==1.4.4 latexcodec==2.0.1 linkify-it-py==2.0.2 mako==1.2.4 -markdown-it-py[linkify,plugins]==2.2.0 +markdown-it-py[linkify,plugins]==3.0.0 markupsafe==2.1.3 matplotlib==3.7.1 matplotlib-inline==0.1.6 -mdit-py-plugins==0.3.5 +mdit-py-plugins==0.4.0 mdurl==0.1.2 mistune==3.0.1 monty==2023.9.25 mpmath==1.3.0 msgpack==1.0.5 multidict==6.0.4 -myst-nb==0.17.2 -myst-parser==0.18.1 +myst-nb==1.0.0 +myst-parser==2.0.0 nbclassic==1.0.0 nbclient==0.7.4 nbconvert==7.6.0 @@ -146,8 +147,8 @@ pytest-benchmark==4.0.0 pytest-cov==2.10.1 pytest-datadir==1.4.1 pytest-regressions==2.4.2 -pytest-rerunfailures==9.1.1 -pytest-timeout==1.4.2 +pytest-rerunfailures==12.0.0 +pytest-timeout==2.2.0 python-dateutil==2.8.2 python-json-logger==2.0.7 python-memcached==1.59 @@ -173,18 +174,17 @@ sniffio==1.3.0 snowballstemmer==2.2.0 soupsieve==2.4.1 spglib==2.0.2 -sphinx==4.5.0 +sphinx==7.2.6 sphinx-copybutton==0.5.2 -sphinx-design==0.0.13 +sphinx-design==0.5.0 sphinx-intl==2.1.0 -sphinx-notfound-page==0.8.3 +sphinx-notfound-page==1.0.0 sphinxcontrib-applehelp==1.0.4 -sphinxcontrib-details-directive==0.1.0 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==1.1.9 sphinxext-rediraffe==0.2.7 sqlalchemy==2.0.23 stack-data==0.6.2 diff --git a/requirements/requirements-py-3.11.txt b/requirements/requirements-py-3.11.txt index bd0fe3749e..b373c77c32 100644 --- a/requirements/requirements-py-3.11.txt +++ b/requirements/requirements-py-3.11.txt @@ -43,7 +43,8 @@ defusedxml==0.7.1 deprecation==2.1.0 disk-objectstore==1.0.0 docstring-parser==0.15 -docutils==0.16 +docutils==0.20.1 +emmet-core==0.57.1 executing==1.2.0 fastjsonschema==2.17.1 flask==2.3.2 @@ -80,19 +81,19 @@ kiwisolver==1.4.4 latexcodec==2.0.1 linkify-it-py==2.0.2 mako==1.2.4 -markdown-it-py[linkify,plugins]==2.2.0 +markdown-it-py[linkify,plugins]==3.0.0 markupsafe==2.1.3 matplotlib==3.7.1 matplotlib-inline==0.1.6 -mdit-py-plugins==0.3.5 +mdit-py-plugins==0.4.0 mdurl==0.1.2 mistune==3.0.1 monty==2023.9.25 mpmath==1.3.0 msgpack==1.0.5 multidict==6.0.4 -myst-nb==0.17.2 -myst-parser==0.18.1 +myst-nb==1.0.0 +myst-parser==2.0.0 nbclassic==1.0.0 nbclient==0.7.4 nbconvert==7.6.0 @@ -145,8 +146,8 @@ pytest-benchmark==4.0.0 pytest-cov==2.10.1 pytest-datadir==1.4.1 pytest-regressions==2.4.2 -pytest-rerunfailures==9.1.1 -pytest-timeout==1.4.2 +pytest-rerunfailures==12.0.0 +pytest-timeout==2.2.0 python-dateutil==2.8.2 python-json-logger==2.0.7 python-memcached==1.59 @@ -172,18 +173,17 @@ sniffio==1.3.0 snowballstemmer==2.2.0 soupsieve==2.4.1 spglib==2.0.2 -sphinx==4.5.0 +sphinx==7.2.6 sphinx-copybutton==0.5.2 -sphinx-design==0.0.13 +sphinx-design==0.5.0 sphinx-intl==2.1.0 -sphinx-notfound-page==0.8.3 +sphinx-notfound-page==1.0.0 sphinxcontrib-applehelp==1.0.4 -sphinxcontrib-details-directive==0.1.0 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==1.1.9 sphinxext-rediraffe==0.2.7 sqlalchemy==2.0.23 stack-data==0.6.2 diff --git a/requirements/requirements-py-3.12.txt b/requirements/requirements-py-3.12.txt new file mode 100644 index 0000000000..9b4cc0a633 --- /dev/null +++ b/requirements/requirements-py-3.12.txt @@ -0,0 +1,211 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --extra=atomic_tools --extra=docs --extra=notebook --extra=rest --extra=tests --no-annotate --output-file=requirements/requirements-py-3.12.txt pyproject.toml +# +accessible-pygments==0.0.4 +aiida-export-migration-tests==0.9.0 +aio-pika==6.8.1 +aiormq==3.3.1 +alabaster==0.7.13 +alembic==1.12.0 +aniso8601==9.0.1 +anyio==4.0.0 +archive-path==0.4.2 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +ase==3.22.1 +asn1crypto==1.5.1 +asttokens==2.4.0 +async-generator==1.10 +attrs==23.1.0 +babel==2.13.1 +backcall==0.2.0 +bcrypt==4.0.1 +beautifulsoup4==4.12.2 +bleach==6.1.0 +blinker==1.6.3 +certifi==2023.7.22 +cffi==1.16.0 +charset-normalizer==3.3.1 +circus==0.18.0 +click==8.1.7 +click-spinner==0.1.10 +comm==0.1.4 +contourpy==1.1.1 +coverage==6.5.0 +cryptography==41.0.5 +cycler==0.12.1 +debugpy==1.8.0 +decorator==5.1.1 +defusedxml==0.7.1 +deprecation==2.1.0 +disk-objectstore==1.0.0 +docstring-parser==0.15 +docutils==0.20.1 +executing==2.0.0 +fastjsonschema==2.18.1 +flask==2.3.3 +flask-cors==3.0.10 +flask-restful==0.3.10 +fonttools==4.43.1 +future==0.18.3 +graphviz==0.20.1 +greenlet==3.0.0 +idna==3.4 +imagesize==1.4.1 +importlib-metadata==6.8.0 +iniconfig==2.0.0 +ipykernel==6.25.2 +ipython==8.16.1 +ipython-genutils==0.2.0 +ipywidgets==8.1.1 +itsdangerous==2.1.2 +jedi==0.19.1 +jinja2==3.1.2 +joblib==1.3.2 +jsonschema[format-nongpl]==3.2.0 +jupyter==1.0.0 +jupyter-cache==0.6.1 +jupyter-client==8.4.0 +jupyter-console==6.6.3 +jupyter-core==5.4.0 +jupyter-events==0.6.3 +jupyter-server==2.8.0 +jupyter-server-terminals==0.4.4 +jupyterlab-pygments==0.2.2 +jupyterlab-widgets==3.0.9 +kiwipy[rmq]==0.7.8 +kiwisolver==1.4.5 +latexcodec==2.0.1 +mako==1.2.4 +markdown-it-py==3.0.0 +markupsafe==2.1.3 +matplotlib==3.8.0 +matplotlib-inline==0.1.6 +mdit-py-plugins==0.4.0 +mdurl==0.1.2 +mistune==3.0.2 +monty==2023.9.25 +mpmath==1.3.0 +multidict==6.0.4 +myst-nb==1.0.0 +myst-parser==2.0.0 +nbclassic==1.0.0 +nbclient==0.7.4 +nbconvert==7.9.2 +nbformat==5.9.2 +nest-asyncio==1.5.8 +networkx==3.2 +notebook==6.5.4 +notebook-shim==0.2.3 +numpy==1.26.1 +overrides==7.4.0 +packaging==23.2 +palettable==3.3.3 +pamqp==2.3.0 +pandas==2.1.1 +pandocfilters==1.5.0 +paramiko==2.12.0 +parso==0.8.3 +pexpect==4.8.0 +pg8000==1.30.2 +pgsu==0.2.4 +pgtest==1.3.2 +pickleshare==0.7.5 +pillow==10.1.0 +platformdirs==3.11.0 +plotly==5.17.0 +pluggy==1.3.0 +plumpy==0.21.10 +prometheus-client==0.17.1 +prompt-toolkit==3.0.39 +psutil==5.9.6 +psycopg2-binary==2.9.9 +ptyprocess==0.7.0 +pure-eval==0.2.2 +py-cpuinfo==9.0.0 +pybtex==0.24.0 +pycifrw==4.4.5 +pycparser==2.21 +pydantic==2.4.0 +pydata-sphinx-theme==0.13.3 +pygments==2.16.1 +pymatgen==2023.10.11 +pympler==0.9 +pymysql==0.9.3 +pynacl==1.5.0 +pyparsing==2.4.7 +pyrsistent==0.19.3 +pytest==7.4.2 +pytest-asyncio==0.16.0 +pytest-benchmark==4.0.0 +pytest-cov==2.10.1 +pytest-datadir==1.5.0 +pytest-regressions==2.5.0 +pytest-rerunfailures==12.0.0 +pytest-timeout==2.2.0 +python-dateutil==2.8.2 +python-json-logger==2.0.7 +python-memcached==1.59 +pytray==0.3.4 +pytz==2021.3 +pyyaml==6.0.1 +pyzmq==25.1.1 +qtconsole==5.4.4 +qtpy==2.4.1 +requests==2.31.0 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +ruamel-yaml==0.18.2 +ruamel-yaml-clib==0.2.8 +scipy==1.11.3 +scramp==1.4.4 +seekpath==1.9.7 +send2trash==1.8.2 +shortuuid==1.0.11 +six==1.16.0 +sniffio==1.3.0 +snowballstemmer==2.2.0 +soupsieve==2.5 +spglib==2.1.0 +sphinx==7.2.6 +sphinx-copybutton==0.5.2 +sphinx-design==0.5.0 +sphinx-intl==2.1.0 +sphinx-notfound-page==1.0.0 +sphinxcontrib-applehelp==1.0.4 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.1 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.9 +sphinxext-rediraffe==0.2.7 +sqlalchemy==2.0.23 +sqlalchemy-utils==0.37.9 +stack-data==0.6.3 +sympy==1.12 +tabulate==0.8.10 +tenacity==8.2.3 +terminado==0.17.1 +tinycss2==1.2.1 +tornado==6.3.3 +tqdm==4.66.1 +traitlets==5.11.2 +typing-extensions==4.8.0 +tzdata==2023.3 +uncertainties==3.1.7 +upf-to-json==0.9.5 +urllib3==2.0.7 +wcwidth==0.2.8 +webencodings==0.5.1 +websocket-client==1.6.4 +werkzeug==3.0.0 +widgetsnbextension==4.0.9 +wrapt==1.15.0 +yarl==1.9.2 +zipp==3.17.0 + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/requirements-py-3.9.txt b/requirements/requirements-py-3.9.txt index 123b833a5e..552b0a5248 100644 --- a/requirements/requirements-py-3.9.txt +++ b/requirements/requirements-py-3.9.txt @@ -43,7 +43,8 @@ defusedxml==0.7.1 deprecation==2.1.0 disk-objectstore==1.0.0 docstring-parser==0.15 -docutils==0.16 +docutils==0.20.1 +emmet-core==0.57.1 exceptiongroup==1.1.1 executing==1.2.0 fastjsonschema==2.17.1 @@ -83,19 +84,19 @@ kiwisolver==1.4.4 latexcodec==2.0.1 linkify-it-py==2.0.2 mako==1.2.4 -markdown-it-py[linkify,plugins]==2.2.0 +markdown-it-py[linkify,plugins]==3.0.0 markupsafe==2.1.3 matplotlib==3.7.1 matplotlib-inline==0.1.6 -mdit-py-plugins==0.3.5 +mdit-py-plugins==0.4.0 mdurl==0.1.2 mistune==3.0.1 monty==2023.9.25 mpmath==1.3.0 msgpack==1.0.5 multidict==6.0.4 -myst-nb==0.17.2 -myst-parser==0.18.1 +myst-nb==1.0.0 +myst-parser==2.0.0 nbclassic==1.0.0 nbclient==0.7.4 nbconvert==7.6.0 @@ -148,8 +149,8 @@ pytest-benchmark==4.0.0 pytest-cov==2.10.1 pytest-datadir==1.4.1 pytest-regressions==2.4.2 -pytest-rerunfailures==9.1.1 -pytest-timeout==1.4.2 +pytest-rerunfailures==12.0.0 +pytest-timeout==2.2.0 python-dateutil==2.8.2 python-json-logger==2.0.7 python-memcached==1.59 @@ -175,18 +176,17 @@ sniffio==1.3.0 snowballstemmer==2.2.0 soupsieve==2.4.1 spglib==2.0.2 -sphinx==4.5.0 +sphinx==7.2.6 sphinx-copybutton==0.5.2 -sphinx-design==0.0.13 +sphinx-design==0.5.0 sphinx-intl==2.1.0 -sphinx-notfound-page==0.8.3 +sphinx-notfound-page==1.0.0 sphinxcontrib-applehelp==1.0.4 -sphinxcontrib-details-directive==0.1.0 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==1.1.9 sphinxext-rediraffe==0.2.7 sqlalchemy==2.0.23 stack-data==0.6.2 diff --git a/tests/sphinxext/conftest.py b/tests/sphinxext/conftest.py index da2ad97613..1cdf188a57 100644 --- a/tests/sphinxext/conftest.py +++ b/tests/sphinxext/conftest.py @@ -13,7 +13,6 @@ import sys import pytest -from sphinx.testing.path import path as sphinx_path from sphinx.testing.util import SphinxTestApp SRC_DIR = pathlib.Path(__file__).parent / 'sources' @@ -69,7 +68,7 @@ def _func(src_folder, **kwargs): filepath_source = SRC_DIR / src_folder filepath_target = tmp_path / src_folder shutil.copytree(filepath_source, filepath_target) - app = make_app(srcdir=sphinx_path(filepath_target.absolute()), **kwargs) + app = make_app(srcdir=filepath_target.absolute(), **kwargs) return SphinxBuild(app, filepath_target) yield _func diff --git a/tests/sphinxext/sources/workchain/conf.py b/tests/sphinxext/sources/workchain/conf.py index 14787e0625..2a6132749a 100644 --- a/tests/sphinxext/sources/workchain/conf.py +++ b/tests/sphinxext/sources/workchain/conf.py @@ -68,7 +68,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/tests/sphinxext/sources/workchain_broken/conf.py b/tests/sphinxext/sources/workchain_broken/conf.py index 14787e0625..2a6132749a 100644 --- a/tests/sphinxext/sources/workchain_broken/conf.py +++ b/tests/sphinxext/sources/workchain_broken/conf.py @@ -68,7 +68,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/tests/sphinxext/test_workchain/test_workchain_build.xml b/tests/sphinxext/test_workchain/test_workchain_build.xml index 3cf00c81f7..4ae9e6fa32 100644 --- a/tests/sphinxext/test_workchain/test_workchain_build.xml +++ b/tests/sphinxext/test_workchain/test_workchain_build.xml @@ -1,6 +1,6 @@ - +
sphinx-aiida demo @@ -8,12 +8,12 @@ - workchaindemo_workchain.DemoWorkChain + workchaindemo_workchain.DemoWorkChain A demo workchain to show how the workchain auto-documentation works. - Inputs:metadata, Namespace
Namespace Portscall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.
nsp, Namespace – A separate namespace, nsp.nsp2, Namespacex, Float, required – First input argument.y, Namespace
Namespace Portsnested, Namespace – A nested namespace.
Namespace Portsa, Int, required – An input in the nested namespace.
z, Int, required – Input in a separate namespace.
+ Inputs:metadata, Namespacecall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.nsp, Namespace – A separate namespace, nsp.nsp2, Namespacex, Float, required – First input argument.y, Namespacenested, Namespace – A nested namespace.a, Int, required – An input in the nested namespace.z, Int, required – Input in a separate namespace. Outputs:z, Bool, required – Output of the demoworkchain. Outline:start while(some_check) @@ -25,12 +25,12 @@ finalize
If you want to hide the inputs that are not stored as nodes in the database, use the :hide-unstored-inputs: option. - workchaindemo_workchain.DemoWorkChain + workchaindemo_workchain.DemoWorkChain A demo workchain to show how the workchain auto-documentation works. - Inputs:metadata, Namespace
Namespace Portscall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.
nsp, Namespace – A separate namespace, nsp.nsp2, Namespacex, Float, required – First input argument.y, Namespace
Namespace Portsnested, Namespace – A nested namespace.
Namespace Portsa, Int, required – An input in the nested namespace.
z, Int, required – Input in a separate namespace.
+ Inputs:metadata, Namespacecall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.nsp, Namespace – A separate namespace, nsp.nsp2, Namespacex, Float, required – First input argument.y, Namespacenested, Namespace – A nested namespace.a, Int, required – An input in the nested namespace.z, Int, required – Input in a separate namespace. Outputs:z, Bool, required – Output of the demoworkchain. Outline:start while(some_check) @@ -42,12 +42,12 @@ finalize
The namespaces can be set to expand by default, using the :expand-namespaces: option. - workchaindemo_workchain.DemoWorkChain + workchaindemo_workchain.DemoWorkChain A demo workchain to show how the workchain auto-documentation works. - Inputs:metadata, Namespace
Namespace Portscall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.
nsp, Namespace – A separate namespace, nsp.nsp2, Namespacex, Float, required – First input argument.y, Namespace
Namespace Portsnested, Namespace – A nested namespace.
Namespace Portsa, Int, required – An input in the nested namespace.
z, Int, required – Input in a separate namespace.
+ Inputs:metadata, Namespacecall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.nsp, Namespace – A separate namespace, nsp.nsp2, Namespacex, Float, required – First input argument.y, Namespacenested, Namespace – A nested namespace.a, Int, required – An input in the nested namespace.z, Int, required – Input in a separate namespace. Outputs:z, Bool, required – Output of the demoworkchain. Outline:start while(some_check) @@ -59,27 +59,27 @@ finalize
The following workchain checks that the directive works also when no outline is specified: - workchaindemo_workchain.EmptyOutlineWorkChain + workchaindemo_workchain.EmptyOutlineWorkChain Here we check that the directive works even if the outline is empty. - Inputs:metadata, Namespace
Namespace Portscall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.
x, Float, required – First input argument.
+ Inputs:metadata, Namespacecall_link_label, str, optional, is_metadata – The label to use for the CALL link if the process is called by another process.description, (str, NoneType), optional, is_metadata – Description to set on the process node.label, (str, NoneType), optional, is_metadata – Label to set on the process node.store_provenance, bool, optional, is_metadata – If set to False provenance will not be stored in the database.x, Float, required – First input argument. Outputs:None defined.
The command is also hooked into sphinx.ext.autodoc, so AiiDA processes will be properly documented using .. automodule:: as well. - - This module defines an example workchain for the aiida-workchain documentation directive. + + This module defines an example workchain for the aiida-workchain documentation directive. - - class demo_workchain.DemoWorkChain*args: Any**kwargs: Any + + class demo_workchain.DemoWorkChain*args: Any**kwargs: Any A demo workchain to show how the workchain auto-documentation works. - - classmethod definespec + + classmethod definespec Define the specification of the process, including its inputs, outputs and known exit codes. A metadata input namespace is defined, with optional ports that are not stored in the database. @@ -88,13 +88,13 @@ finalize - - class demo_workchain.EmptyOutlineWorkChain*args: Any**kwargs: Any + + class demo_workchain.EmptyOutlineWorkChain*args: Any**kwargs: Any Here we check that the directive works even if the outline is empty. - - classmethod definespec + + classmethod definespec Define the specification of the process, including its inputs, outputs and known exit codes. A metadata input namespace is defined, with optional ports that are not stored in the database. @@ -103,8 +103,8 @@ finalize - - class demo_workchain.NormalClass + + class demo_workchain.NormalClass This is here to check that we didn’t break the regular autoclass. diff --git a/utils/dependency_management.py b/utils/dependency_management.py index cb2b6dbb73..78a92c811e 100755 --- a/utils/dependency_management.py +++ b/utils/dependency_management.py @@ -17,9 +17,10 @@ import sys import click +from packaging.requirements import Requirement +from packaging.specifiers import Specifier from packaging.utils import canonicalize_name from packaging.version import parse -from pkg_resources import Requirement, parse_requirements import requests import tomli import yaml @@ -71,14 +72,14 @@ def _setuptools_to_conda(req): for pattern, replacement in SETUPTOOLS_CONDA_MAPPINGS.items(): if re.match(pattern, str(req)): - req = Requirement.parse(re.sub(pattern, replacement, str(req))) + req = Requirement(re.sub(pattern, replacement, str(req))) break # markers are not supported by conda req.marker = None # We need to parse the modified required again, to ensure consistency. - return Requirement.parse(str(req)) + return Requirement(str(req)) def _find_linenos_of_requirements_in_pyproject(requirements): @@ -101,22 +102,14 @@ def _find_linenos_of_requirements_in_pyproject(requirements): return linenos -class _Entry: - """Helper class to check whether a given distribution fulfills a requirement.""" - - def __init__(self, requirement): - self._req = requirement - - def fulfills(self, requirement): - """Returns True if this entry fullfills the requirement.""" - - return canonicalize_name(self._req.name) == canonicalize_name(requirement.name) \ - and self._req.specs[0][1] in requirement.specifier - - -def _parse_working_set(entries): - for req in parse_requirements(entries): - yield _Entry(req) +def parse_requirements(requirements): + """Parse requirements from a file or list of strings.""" + results = [] + for requirement in requirements: + stripped = requirement.strip() + if stripped and not stripped.startswith('#'): + results.append(Requirement(stripped)) + return results @click.group() @@ -137,7 +130,7 @@ def generate_environment_yml(): # Read the requirements from 'pyproject.toml' pyproject = _load_pyproject() - install_requirements = [Requirement.parse(r) for r in pyproject['project']['dependencies']] + install_requirements = [Requirement(r) for r in pyproject['project']['dependencies']] # python version cannot be overriden from outside environment.yml # (even if it is not specified at all in environment.yml) @@ -174,8 +167,8 @@ def validate_environment_yml(): # pylint: disable=too-many-branches # Read the requirements from 'pyproject.toml' and 'environment.yml'. pyproject = _load_pyproject() - install_requirements = [Requirement.parse(r) for r in pyproject['project']['dependencies']] - python_requires = Requirement.parse('python' + pyproject['project']['requires-python']) + install_requirements = [Requirement(r) for r in pyproject['project']['dependencies']] + python_requires = Requirement('python' + pyproject['project']['requires-python']) environment_yml = _load_environment_yml() try: @@ -187,7 +180,7 @@ def validate_environment_yml(): # pylint: disable=too-many-branches raise DependencySpecificationError(f"Error in 'environment.yml': {error}") try: - conda_dependencies = {Requirement.parse(d) for d in environment_yml['dependencies']} + conda_dependencies = {Requirement(d) for d in environment_yml['dependencies']} except TypeError as error: raise DependencySpecificationError(f"Error while parsing requirements from 'environment_yml': {error}") @@ -267,7 +260,7 @@ def validate_all(ctx): 'as part of a GitHub actions workflow. Note: Requires environment ' 'variable GITHUB_ACTIONS=true .' ) -def check_requirements(extras, github_annotate): # pylint disable: too-many-locals-too-many-branches +def check_requirements(extras, github_annotate): # pylint: disable=too-many-locals,too-many-branches """Check the 'requirements/*.txt' files. Checks that the environments specified in the requirements files @@ -294,13 +287,23 @@ def check_requirements(extras, github_annotate): # pylint disable: too-many-loc if not match: continue env = {'python_version': match.groups()[0]} - required = {r for r in install_requires if r.marker is None or r.marker.evaluate(env)} + requirements_abstract = {r for r in install_requires if r.marker is None or r.marker.evaluate(env)} + installed = [] with open(fn_req, encoding='utf8') as req_file: - working_set = list(_parse_working_set(req_file)) - installed = {req for req in required for entry in working_set if entry.fulfills(req)} - - for dependency in required.difference(installed): + requirements_concrete = parse_requirements(req_file) + + for requirement_abstract in requirements_abstract: + for requirement_concrete in requirements_concrete: + version = Specifier(str(requirement_concrete.specifier)).version + if ( + canonicalize_name(requirement_abstract.name) == canonicalize_name(requirement_concrete.name) and + requirement_abstract.specifier.contains(version) + ): + installed.append(requirement_abstract) + break + + for dependency in requirements_abstract.difference(set(installed)): not_installed[dependency].append(fn_req) if any(not_installed.values()): @@ -352,9 +355,9 @@ def show_requirements(extras, fmt): if 'all' in extras: extras = list(pyproject['project']['optional-dependencies']) - to_install = {Requirement.parse(r) for r in pyproject['project']['dependencies']} + to_install = {Requirement(r) for r in pyproject['project']['dependencies']} for key in extras: - to_install.update(Requirement.parse(r) for r in pyproject['project']['optional-dependencies'][key]) + to_install.update(Requirement(r) for r in pyproject['project']['optional-dependencies'][key]) if fmt == 'pip': click.echo('\n'.join(sorted(map(str, to_install)))) @@ -381,7 +384,7 @@ def pip_install_extras(extras): to_install = set() for key in extras: - to_install.update(Requirement.parse(r) for r in pyproject['project']['optional-dependencies'][key]) + to_install.update(Requirement(r) for r in pyproject['project']['optional-dependencies'][key]) cmd = [sys.executable, '-m', 'pip', 'install'] + [str(r) for r in to_install] subprocess.run(cmd, check=True) @@ -407,9 +410,9 @@ def identify_outdated(extras, pre_releases): # Read the requirements from 'pyproject.toml'' pyproject = _load_pyproject() - to_install = {Requirement.parse(r) for r in pyproject['project']['dependencies']} + to_install = {Requirement(r) for r in pyproject['project']['dependencies']} for key in extras: - to_install.update(Requirement.parse(r) for r in pyproject['project']['optional-dependencies'][key]) + to_install.update(Requirement(r) for r in pyproject['project']['optional-dependencies'][key]) def get_package_data(name): req = requests.get(f'https://pypi.python.org/pypi/{name}/json', timeout=5) diff --git a/utils/requirements.txt b/utils/requirements.txt index eb8351b949..7fb8a640c2 100644 --- a/utils/requirements.txt +++ b/utils/requirements.txt @@ -1,5 +1,5 @@ click==7.1.2 -packaging==20.3 -pyyaml==5.4.1 +packaging==23.1 +pyyaml==6.0.1 requests==2.25.1 tomli==2.0.0