diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 49f6ed232..f54521805 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -217,9 +217,7 @@ jobs: pip install cirq-core==${{matrix.cirq-version}} - name: Run pytest - run: | - echo '::add-matcher::.github/problem-matchers/pytest.json' - check/pytest -m "not slow" + run: check/pytest -n auto -m "not slow" pytest-extra: if: needs.changes.outputs.python == 'true' @@ -252,9 +250,7 @@ jobs: pip install cirq-core==${{matrix.cirq-version}} - name: Run pytest - run: | - echo '::add-matcher::.github/problem-matchers/pytest.json' - check/pytest -m "not slow" src/openfermion/resource_estimates + run: check/pytest -n auto -m "not slow" src/openfermion/resource_estimates pytest-compat: if: needs.changes.outputs.python == 'true' @@ -281,9 +277,7 @@ jobs: run: pip install -r dev_tools/requirements/max_compat/pytest-max-compat.env.txt - name: Run pytest - run: | - echo '::add-matcher::.github/problem-matchers/pytest.json' - check/pytest -m "not slow" + run: check/pytest -n auto -m "not slow" coverage: if: needs.changes.outputs.python == 'true' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1289297a2..ce2dbf0c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -239,6 +239,20 @@ check/mypy Please refer to the section _Developer install_ of the [installation instructions](docs/install.md) for information about how to set up a local copy of the software for development. +### Type annotation conventions + +Code should have [type annotations](https://www.python.org/dev/peps/pep-0484/). We use +[mypy](http://mypy-lang.org/) to check that type annotations are correct, and the following script +to run it: + +```shell +check/mypy +``` + +If your computer has multiple processor cores, you can add the option `-j 0` to the command above to +make Mypy run in parallel for a substantial speed increase. + + ### Linting and formatting Code should meet common style standards for Python and be free of error-prone constructs. We use @@ -282,7 +296,9 @@ We use [pytest](https://docs.pytest.org) to run our tests and * While developing, periodically check that changes do not break anything. For fast checks, use `pytest -c dev_tools/conf/pytest.ini PATH`, where `PATH` is a directory or pytest file to test. -* After finishing a task, run `check/pytest` to test all of the OpenFermion code. +* After finishing a task, run `check/pytest` to test all of the OpenFermion code. If your system + has multiple processor cores, you can add the option `-n auto` to make it run in parallel for a + substantial speed increase. (Beware, though, that this is resource-intensive.) We don't require 100% coverage, but coverage should be very high, and any uncovered code must be annotated with `# pragma: no cover`. To ignore coverage of a single line, place `# pragma: no cover` @@ -294,9 +310,9 @@ cover` comment on its own line. Note, however, that these annotations should be After a task is finished, run each of the following to make sure everything passes all the tests: * `check/format-incremental` -* `check/pylint` +* `check/pylint -j 0` * `check/mypy` -* `check/pytest` +* `check/pytest -n auto` * `check/pytest-and-incremental-coverage` ### Pull requests and code reviews diff --git a/check/pytest-and-incremental-coverage b/check/pytest-and-incremental-coverage index c322ca79d..ed6c1e506 100755 --- a/check/pytest-and-incremental-coverage +++ b/check/pytest-and-incremental-coverage @@ -68,6 +68,7 @@ fi # Run tests while producing coverage files. check/pytest . \ + -n auto \ --actually-quiet \ --cov \ --cov-report=annotate diff --git a/dev_tools/requirements/deps/pytest.txt b/dev_tools/requirements/deps/pytest.txt index 5ee378fbf..e6d43b3d5 100644 --- a/dev_tools/requirements/deps/pytest.txt +++ b/dev_tools/requirements/deps/pytest.txt @@ -1,6 +1,7 @@ pytest pytest-asyncio pytest-cov +pytest-randomly pytest-retry pytest-xdist diff --git a/dev_tools/requirements/envs/dev.env.txt b/dev_tools/requirements/envs/dev.env.txt index 38a1d3edf..896b79d39 100644 --- a/dev_tools/requirements/envs/dev.env.txt +++ b/dev_tools/requirements/envs/dev.env.txt @@ -19,15 +19,15 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # pytest-asyncio black==26.3.1 # via -r deps/format.txt -build==1.4.2 +build==1.4.4 # via pip-tools -certifi==2026.2.25 +certifi==2026.4.22 # via requests charset-normalizer==3.4.7 # via requests cirq-core==1.5.0 # via -r deps/runtime.txt -click==8.3.1 +click==8.3.3 # via # black # pip-tools @@ -57,7 +57,7 @@ h5py==3.16.0 # via # -r deps/runtime.txt # pyscf -idna==3.11 +idna==3.13 # via requests iniconfig==2.3.0 # via pytest @@ -77,9 +77,9 @@ jupyter-core==5.9.1 # via nbformat kiwisolver==1.5.0 # via matplotlib -librt==0.8.1 +librt==0.9.0 # via mypy -matplotlib==3.10.8 +matplotlib==3.10.9 # via # ase # cirq-core @@ -91,7 +91,7 @@ ml-dtypes==0.5.4 # jaxlib mpmath==1.3.0 # via sympy -mypy==1.20.0 +mypy==1.20.2 # via -r deps/mypy.txt mypy-extensions==1.1.0 # via @@ -121,7 +121,7 @@ numpy==2.2.6 # types-networkx opt-einsum==3.4.0 # via jax -packaging==26.0 +packaging==26.2 # via # black # build @@ -133,7 +133,7 @@ pandas==2.3.3 # via cirq-core pandas-stubs==2.3.3.260113 # via -r deps/mypy.txt -pathspec==1.0.4 +pathspec==1.1.1 # via # black # mypy @@ -141,7 +141,7 @@ pillow==12.2.0 # via matplotlib pip-tools==7.5.3 # via -r deps/pip-tools.txt -platformdirs==4.9.4 +platformdirs==4.9.6 # via # black # jupyter-core @@ -162,19 +162,22 @@ pyproject-hooks==1.2.0 # via # build # pip-tools -pyscf==2.12.1 +pyscf==2.13.0 # via -r deps/resource_estimates_runtime.txt -pytest==9.0.2 +pytest==9.0.3 # via # -r deps/pytest.txt # pytest-asyncio # pytest-cov + # pytest-randomly # pytest-retry # pytest-xdist pytest-asyncio==1.3.0 # via -r deps/pytest.txt pytest-cov==7.1.0 # via -r deps/pytest.txt +pytest-randomly==4.1.0 + # via -r deps/pytest.txt pytest-retry==1.7.0 # via -r deps/pytest.txt pytest-xdist==3.8.0 @@ -230,13 +233,13 @@ traitlets==5.14.3 # via # jupyter-core # nbformat -types-networkx==3.6.1.20260402 +types-networkx==3.6.1.20260408 # via -r deps/mypy.txt -types-pytz==2026.1.1.20260402 +types-pytz==2026.1.1.20260408 # via pandas-stubs -types-requests==2.33.0.20260402 +types-requests==2.33.0.20260408 # via -r deps/mypy.txt -types-setuptools==82.0.0.20260402 +types-setuptools==82.0.0.20260408 # via -r deps/mypy.txt typing-extensions==4.15.0 # via @@ -247,13 +250,13 @@ typing-extensions==4.15.0 # mypy # pytest-asyncio # referencing -tzdata==2025.3 +tzdata==2026.2 # via pandas urllib3==2.6.3 # via # requests # types-requests -wheel==0.46.3 +wheel==0.47.0 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/dev_tools/requirements/envs/format.env.txt b/dev_tools/requirements/envs/format.env.txt index 313d35d7a..5ddf25422 100644 --- a/dev_tools/requirements/envs/format.env.txt +++ b/dev_tools/requirements/envs/format.env.txt @@ -16,7 +16,7 @@ black==26.3.1 # via # -c envs/dev.env.txt # -r deps/format.txt -certifi==2026.2.25 +certifi==2026.4.22 # via # -c envs/dev.env.txt # requests @@ -28,7 +28,7 @@ cirq-core==1.5.0 # via # -c envs/dev.env.txt # -r deps/runtime.txt -click==8.3.1 +click==8.3.3 # via # -c envs/dev.env.txt # black @@ -57,7 +57,7 @@ h5py==3.16.0 # via # -c envs/dev.env.txt # -r deps/runtime.txt -idna==3.11 +idna==3.13 # via # -c envs/dev.env.txt # requests @@ -65,7 +65,7 @@ kiwisolver==1.5.0 # via # -c envs/dev.env.txt # matplotlib -matplotlib==3.10.8 +matplotlib==3.10.9 # via # -c envs/dev.env.txt # cirq-core @@ -92,7 +92,7 @@ numpy==2.2.6 # matplotlib # pandas # scipy -packaging==26.0 +packaging==26.2 # via # -c envs/dev.env.txt # black @@ -102,7 +102,7 @@ pandas==2.3.3 # via # -c envs/dev.env.txt # cirq-core -pathspec==1.0.4 +pathspec==1.1.1 # via # -c envs/dev.env.txt # black @@ -110,7 +110,7 @@ pillow==12.2.0 # via # -c envs/dev.env.txt # matplotlib -platformdirs==4.9.4 +platformdirs==4.9.6 # via # -c envs/dev.env.txt # black @@ -170,7 +170,7 @@ typing-extensions==4.15.0 # -c envs/dev.env.txt # black # cirq-core -tzdata==2025.3 +tzdata==2026.2 # via # -c envs/dev.env.txt # pandas diff --git a/dev_tools/requirements/envs/mypy.env.txt b/dev_tools/requirements/envs/mypy.env.txt index 499ced234..9c61c6163 100644 --- a/dev_tools/requirements/envs/mypy.env.txt +++ b/dev_tools/requirements/envs/mypy.env.txt @@ -12,7 +12,7 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # via # -c envs/dev.env.txt # -r deps/runtime.txt -certifi==2026.2.25 +certifi==2026.4.22 # via # -c envs/dev.env.txt # requests @@ -49,7 +49,7 @@ h5py==3.16.0 # via # -c envs/dev.env.txt # -r deps/runtime.txt -idna==3.11 +idna==3.13 # via # -c envs/dev.env.txt # requests @@ -57,11 +57,11 @@ kiwisolver==1.5.0 # via # -c envs/dev.env.txt # matplotlib -librt==0.8.1 +librt==0.9.0 # via # -c envs/dev.env.txt # mypy -matplotlib==3.10.8 +matplotlib==3.10.9 # via # -c envs/dev.env.txt # cirq-core @@ -69,7 +69,7 @@ mpmath==1.3.0 # via # -c envs/dev.env.txt # sympy -mypy==1.20.0 +mypy==1.20.2 # via # -c envs/dev.env.txt # -r deps/mypy.txt @@ -94,7 +94,7 @@ numpy==2.2.6 # pandas-stubs # scipy # types-networkx -packaging==26.0 +packaging==26.2 # via # -c envs/dev.env.txt # deprecation @@ -107,7 +107,7 @@ pandas-stubs==2.3.3.260113 # via # -c envs/dev.env.txt # -r deps/mypy.txt -pathspec==1.0.4 +pathspec==1.1.1 # via # -c envs/dev.env.txt # mypy @@ -162,19 +162,19 @@ tqdm==4.67.3 # via # -c envs/dev.env.txt # cirq-core -types-networkx==3.6.1.20260402 +types-networkx==3.6.1.20260408 # via # -c envs/dev.env.txt # -r deps/mypy.txt -types-pytz==2026.1.1.20260402 +types-pytz==2026.1.1.20260408 # via # -c envs/dev.env.txt # pandas-stubs -types-requests==2.33.0.20260402 +types-requests==2.33.0.20260408 # via # -c envs/dev.env.txt # -r deps/mypy.txt -types-setuptools==82.0.0.20260402 +types-setuptools==82.0.0.20260408 # via # -c envs/dev.env.txt # -r deps/mypy.txt @@ -183,7 +183,7 @@ typing-extensions==4.15.0 # -c envs/dev.env.txt # cirq-core # mypy -tzdata==2025.3 +tzdata==2026.2 # via # -c envs/dev.env.txt # pandas diff --git a/dev_tools/requirements/envs/pip-tools.env.txt b/dev_tools/requirements/envs/pip-tools.env.txt index 6b7167b2a..8383cb8c0 100644 --- a/dev_tools/requirements/envs/pip-tools.env.txt +++ b/dev_tools/requirements/envs/pip-tools.env.txt @@ -4,15 +4,15 @@ # # pip-compile --constraint=envs/dev.env.txt --output-file=envs/pip-tools.env.txt deps/pip-tools.txt # -build==1.4.2 +build==1.4.4 # via # -c envs/dev.env.txt # pip-tools -click==8.3.1 +click==8.3.3 # via # -c envs/dev.env.txt # pip-tools -packaging==26.0 +packaging==26.2 # via # -c envs/dev.env.txt # build @@ -31,7 +31,7 @@ tomli==2.4.1 # -c envs/dev.env.txt # build # pip-tools -wheel==0.46.3 +wheel==0.47.0 # via # -c envs/dev.env.txt # pip-tools diff --git a/dev_tools/requirements/envs/pylint.env.txt b/dev_tools/requirements/envs/pylint.env.txt index c729dcbc9..44db3c43d 100644 --- a/dev_tools/requirements/envs/pylint.env.txt +++ b/dev_tools/requirements/envs/pylint.env.txt @@ -23,7 +23,7 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # -c envs/dev.env.txt # -r deps/runtime.txt # pytest-asyncio -certifi==2026.2.25 +certifi==2026.4.22 # via # -c envs/dev.env.txt # requests @@ -81,7 +81,7 @@ h5py==3.16.0 # -c envs/dev.env.txt # -r deps/runtime.txt # pyscf -idna==3.11 +idna==3.13 # via # -c envs/dev.env.txt # requests @@ -118,7 +118,7 @@ kiwisolver==1.5.0 # via # -c envs/dev.env.txt # matplotlib -matplotlib==3.10.8 +matplotlib==3.10.9 # via # -c envs/dev.env.txt # ase @@ -164,7 +164,7 @@ opt-einsum==3.4.0 # via # -c envs/dev.env.txt # jax -packaging==26.0 +packaging==26.2 # via # -c envs/dev.env.txt # deprecation @@ -178,7 +178,7 @@ pillow==12.2.0 # via # -c envs/dev.env.txt # matplotlib -platformdirs==4.9.4 +platformdirs==4.9.6 # via # -c envs/dev.env.txt # jupyter-core @@ -204,16 +204,17 @@ pyparsing==3.3.2 # via # -c envs/dev.env.txt # matplotlib -pyscf==2.12.1 +pyscf==2.13.0 # via # -c envs/dev.env.txt # -r deps/resource_estimates_runtime.txt -pytest==9.0.2 +pytest==9.0.3 # via # -c envs/dev.env.txt # -r deps/pytest.txt # pytest-asyncio # pytest-cov + # pytest-randomly # pytest-retry # pytest-xdist pytest-asyncio==1.3.0 @@ -224,6 +225,10 @@ pytest-cov==7.1.0 # via # -c envs/dev.env.txt # -r deps/pytest.txt +pytest-randomly==4.1.0 + # via + # -c envs/dev.env.txt + # -r deps/pytest.txt pytest-retry==1.7.0 # via # -c envs/dev.env.txt @@ -304,7 +309,7 @@ typing-extensions==4.15.0 # exceptiongroup # pytest-asyncio # referencing -tzdata==2025.3 +tzdata==2026.2 # via # -c envs/dev.env.txt # pandas diff --git a/dev_tools/requirements/envs/pytest-extra.env.txt b/dev_tools/requirements/envs/pytest-extra.env.txt index 3fd3eb5ae..83d6e6b09 100644 --- a/dev_tools/requirements/envs/pytest-extra.env.txt +++ b/dev_tools/requirements/envs/pytest-extra.env.txt @@ -19,7 +19,7 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # -c envs/dev.env.txt # -r deps/runtime.txt # pytest-asyncio -certifi==2026.2.25 +certifi==2026.4.22 # via # -c envs/dev.env.txt # requests @@ -73,7 +73,7 @@ h5py==3.16.0 # -c envs/dev.env.txt # -r deps/runtime.txt # pyscf -idna==3.11 +idna==3.13 # via # -c envs/dev.env.txt # requests @@ -106,7 +106,7 @@ kiwisolver==1.5.0 # via # -c envs/dev.env.txt # matplotlib -matplotlib==3.10.8 +matplotlib==3.10.9 # via # -c envs/dev.env.txt # ase @@ -148,7 +148,7 @@ opt-einsum==3.4.0 # via # -c envs/dev.env.txt # jax -packaging==26.0 +packaging==26.2 # via # -c envs/dev.env.txt # deprecation @@ -162,7 +162,7 @@ pillow==12.2.0 # via # -c envs/dev.env.txt # matplotlib -platformdirs==4.9.4 +platformdirs==4.9.6 # via # -c envs/dev.env.txt # jupyter-core @@ -183,16 +183,17 @@ pyparsing==3.3.2 # via # -c envs/dev.env.txt # matplotlib -pyscf==2.12.1 +pyscf==2.13.0 # via # -c envs/dev.env.txt # -r deps/resource_estimates_runtime.txt -pytest==9.0.2 +pytest==9.0.3 # via # -c envs/dev.env.txt # -r deps/pytest.txt # pytest-asyncio # pytest-cov + # pytest-randomly # pytest-retry # pytest-xdist pytest-asyncio==1.3.0 @@ -203,6 +204,10 @@ pytest-cov==7.1.0 # via # -c envs/dev.env.txt # -r deps/pytest.txt +pytest-randomly==4.1.0 + # via + # -c envs/dev.env.txt + # -r deps/pytest.txt pytest-retry==1.7.0 # via # -c envs/dev.env.txt @@ -277,7 +282,7 @@ typing-extensions==4.15.0 # exceptiongroup # pytest-asyncio # referencing -tzdata==2025.3 +tzdata==2026.2 # via # -c envs/dev.env.txt # pandas diff --git a/dev_tools/requirements/envs/pytest.env.txt b/dev_tools/requirements/envs/pytest.env.txt index 7a111ea1d..3fe3a730c 100644 --- a/dev_tools/requirements/envs/pytest.env.txt +++ b/dev_tools/requirements/envs/pytest.env.txt @@ -15,7 +15,7 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # -c envs/dev.env.txt # -r deps/runtime.txt # pytest-asyncio -certifi==2026.2.25 +certifi==2026.4.22 # via # -c envs/dev.env.txt # requests @@ -68,7 +68,7 @@ h5py==3.16.0 # via # -c envs/dev.env.txt # -r deps/runtime.txt -idna==3.11 +idna==3.13 # via # -c envs/dev.env.txt # requests @@ -92,7 +92,7 @@ kiwisolver==1.5.0 # via # -c envs/dev.env.txt # matplotlib -matplotlib==3.10.8 +matplotlib==3.10.9 # via # -c envs/dev.env.txt # cirq-core @@ -119,7 +119,7 @@ numpy==2.2.6 # matplotlib # pandas # scipy -packaging==26.0 +packaging==26.2 # via # -c envs/dev.env.txt # deprecation @@ -133,7 +133,7 @@ pillow==12.2.0 # via # -c envs/dev.env.txt # matplotlib -platformdirs==4.9.4 +platformdirs==4.9.6 # via # -c envs/dev.env.txt # jupyter-core @@ -154,12 +154,13 @@ pyparsing==3.3.2 # via # -c envs/dev.env.txt # matplotlib -pytest==9.0.2 +pytest==9.0.3 # via # -c envs/dev.env.txt # -r deps/pytest.txt # pytest-asyncio # pytest-cov + # pytest-randomly # pytest-retry # pytest-xdist pytest-asyncio==1.3.0 @@ -170,6 +171,10 @@ pytest-cov==7.1.0 # via # -c envs/dev.env.txt # -r deps/pytest.txt +pytest-randomly==4.1.0 + # via + # -c envs/dev.env.txt + # -r deps/pytest.txt pytest-retry==1.7.0 # via # -c envs/dev.env.txt @@ -240,7 +245,7 @@ typing-extensions==4.15.0 # exceptiongroup # pytest-asyncio # referencing -tzdata==2025.3 +tzdata==2026.2 # via # -c envs/dev.env.txt # pandas diff --git a/dev_tools/requirements/max_compat/dev.env.txt b/dev_tools/requirements/max_compat/dev.env.txt index 3a8cd7dc7..bec60f5cc 100644 --- a/dev_tools/requirements/max_compat/dev.env.txt +++ b/dev_tools/requirements/max_compat/dev.env.txt @@ -13,7 +13,7 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # via # -r deps/runtime.txt # pytest-asyncio -certifi==2026.2.25 +certifi==2026.4.22 # via requests charset-normalizer==3.4.7 # via requests @@ -43,7 +43,7 @@ fonttools==4.62.1 # via matplotlib h5py==3.16.0 # via -r deps/runtime.txt -idna==3.11 +idna==3.13 # via requests iniconfig==2.3.0 # via pytest @@ -55,7 +55,7 @@ jupyter-core==5.9.1 # via nbformat kiwisolver==1.5.0 # via matplotlib -matplotlib==3.10.8 +matplotlib==3.10.9 # via cirq-core mpmath==1.3.0 # via sympy @@ -74,7 +74,7 @@ numpy==1.26.4 # matplotlib # pandas # scipy -packaging==26.0 +packaging==26.2 # via # deprecation # matplotlib @@ -83,7 +83,7 @@ pandas==2.3.3 # via cirq-core pillow==12.2.0 # via matplotlib -platformdirs==4.9.4 +platformdirs==4.9.6 # via jupyter-core pluggy==1.6.0 # via @@ -95,17 +95,20 @@ pygments==2.20.0 # via pytest pyparsing==3.3.2 # via matplotlib -pytest==9.0.2 +pytest==9.0.3 # via # -r deps/pytest.txt # pytest-asyncio # pytest-cov + # pytest-randomly # pytest-retry # pytest-xdist pytest-asyncio==1.3.0 # via -r deps/pytest.txt pytest-cov==7.1.0 # via -r deps/pytest.txt +pytest-randomly==4.1.0 + # via -r deps/pytest.txt pytest-retry==1.7.0 # via -r deps/pytest.txt pytest-xdist==3.8.0 @@ -154,7 +157,7 @@ typing-extensions==4.15.0 # exceptiongroup # pytest-asyncio # referencing -tzdata==2025.3 +tzdata==2026.2 # via pandas urllib3==2.6.3 # via requests diff --git a/dev_tools/requirements/max_compat/pytest-max-compat.env.txt b/dev_tools/requirements/max_compat/pytest-max-compat.env.txt index 53ebc649d..5fc54b4e8 100644 --- a/dev_tools/requirements/max_compat/pytest-max-compat.env.txt +++ b/dev_tools/requirements/max_compat/pytest-max-compat.env.txt @@ -15,7 +15,7 @@ backports-asyncio-runner==1.2.0 ; python_full_version < "3.11" # -c max_compat/dev.env.txt # -r deps/runtime.txt # pytest-asyncio -certifi==2026.2.25 +certifi==2026.4.22 # via # -c max_compat/dev.env.txt # requests @@ -69,7 +69,7 @@ h5py==3.16.0 # via # -c max_compat/dev.env.txt # -r deps/runtime.txt -idna==3.11 +idna==3.13 # via # -c max_compat/dev.env.txt # requests @@ -93,7 +93,7 @@ kiwisolver==1.5.0 # via # -c max_compat/dev.env.txt # matplotlib -matplotlib==3.10.8 +matplotlib==3.10.9 # via # -c max_compat/dev.env.txt # cirq-core @@ -120,7 +120,7 @@ numpy==1.26.4 # matplotlib # pandas # scipy -packaging==26.0 +packaging==26.2 # via # -c max_compat/dev.env.txt # deprecation @@ -134,7 +134,7 @@ pillow==12.2.0 # via # -c max_compat/dev.env.txt # matplotlib -platformdirs==4.9.4 +platformdirs==4.9.6 # via # -c max_compat/dev.env.txt # jupyter-core @@ -155,12 +155,13 @@ pyparsing==3.3.2 # via # -c max_compat/dev.env.txt # matplotlib -pytest==9.0.2 +pytest==9.0.3 # via # -c max_compat/dev.env.txt # -r deps/pytest.txt # pytest-asyncio # pytest-cov + # pytest-randomly # pytest-retry # pytest-xdist pytest-asyncio==1.3.0 @@ -171,6 +172,10 @@ pytest-cov==7.1.0 # via # -c max_compat/dev.env.txt # -r deps/pytest.txt +pytest-randomly==4.1.0 + # via + # -c max_compat/dev.env.txt + # -r deps/pytest.txt pytest-retry==1.7.0 # via # -c max_compat/dev.env.txt @@ -241,7 +246,7 @@ typing-extensions==4.15.0 # exceptiongroup # pytest-asyncio # referencing -tzdata==2025.3 +tzdata==2026.2 # via # -c max_compat/dev.env.txt # pandas diff --git a/src/openfermion/chem/molecular_data_test.py b/src/openfermion/chem/molecular_data_test.py index de7f5afcb..d51e6937c 100644 --- a/src/openfermion/chem/molecular_data_test.py +++ b/src/openfermion/chem/molecular_data_test.py @@ -12,6 +12,7 @@ """Tests for molecular_data.""" import os +import shutil import tempfile import unittest from unittest.mock import patch @@ -40,6 +41,7 @@ class MolecularDataTest(unittest.TestCase): def setUp(self): + self.test_dir = tempfile.mkdtemp() self.geometry = [('H', (0.0, 0.0, 0.0)), ('H', (0.0, 0.0, 0.7414))] self.basis = 'sto-3g' self.multiplicity = 1 @@ -49,6 +51,9 @@ def setUp(self): ) self.molecule.load() + def tearDown(self): + shutil.rmtree(self.test_dir) + def testUnitConversion(self): """Test the unit conversion routines""" unit_angstrom = 1.0 @@ -127,7 +132,7 @@ def test_save_load(self): def test_dummy_save(self): # Make fake molecule. - filename = os.path.join(DATA_DIRECTORY, 'dummy_molecule') + filename = os.path.join(self.test_dir, 'dummy_molecule') geometry = [('H', (0.0, 0.0, 0.0)), ('H', (0.0, 0.0, 0.7414))] basis = '6-31g*' multiplicity = 7 @@ -195,7 +200,8 @@ def test_dummy_save(self): self.assertAlmostEqual(new_molecule.ccsd_energy, molecule.ccsd_energy) self.assertAlmostEqual(molecule.ccsd_energy, 88.0) finally: - os.remove(filename + '.hdf5') + if os.path.isfile(filename + '.hdf5'): + os.remove(filename + '.hdf5') def test_file_loads(self): """Test different filename specs""" @@ -285,6 +291,7 @@ def test_abstract_molecule(self): basis="PlaneWave22", multiplicity=1, n_electrons=4, + data_directory=self.test_dir, ) jellium_filename = jellium_molecule.filename @@ -292,7 +299,8 @@ def test_abstract_molecule(self): jellium_molecule.load() correct_name = "Jellium_PlaneWave22_singlet" self.assertEqual(jellium_molecule.name, correct_name) - os.remove("{}.hdf5".format(jellium_filename)) + if os.path.isfile("{}.hdf5".format(jellium_filename)): + os.remove("{}.hdf5".format(jellium_filename)) def test_load_molecular_hamiltonian(self): bond_length = 1.45 diff --git a/src/openfermion/conftest.py b/src/openfermion/conftest.py index ac3ed7d30..b99547e0e 100644 --- a/src/openfermion/conftest.py +++ b/src/openfermion/conftest.py @@ -25,4 +25,4 @@ def pytest_configure(config): def set_random_seed(): """Set a fixed random seed when testing.""" random.seed(0) - np.random.seed(0) + np.random.default_rng(0) diff --git a/src/openfermion/utils/operator_utils_test.py b/src/openfermion/utils/operator_utils_test.py index 95b7d32cb..015cb0cfc 100644 --- a/src/openfermion/utils/operator_utils_test.py +++ b/src/openfermion/utils/operator_utils_test.py @@ -14,7 +14,8 @@ import os import itertools - +import shutil +import tempfile import unittest import numpy @@ -458,6 +459,7 @@ def test_exceptions(self): class SaveLoadOperatorTest(unittest.TestCase): def setUp(self): + self.test_dir = tempfile.mkdtemp() self.n_qubits = 5 self.fermion_term = FermionOperator('1^ 2^ 3 4', -3.17) self.fermion_operator = self.fermion_term + hermitian_conjugated(self.fermion_term) @@ -470,30 +472,27 @@ def setUp(self): self.bad_operator_filename = 'bad_file.data' bad_op = "A:\nB" - with open(os.path.join(DATA_DIRECTORY, self.bad_operator_filename), 'w') as fid: + with open(os.path.join(self.test_dir, self.bad_operator_filename), 'w') as fid: fid.write(bad_op) + shutil.copy(os.path.join(DATA_DIRECTORY, 'bad_type_operator.data'), self.test_dir) + def tearDown(self): - file_path = os.path.join(DATA_DIRECTORY, self.file_name + '.data') - if os.path.isfile(file_path): - os.remove(file_path) - file_path = os.path.join(DATA_DIRECTORY, self.bad_operator_filename) - if os.path.isfile(file_path): - os.remove(file_path) + shutil.rmtree(self.test_dir) def test_save_sympy_plaintext(self): operator = FermionOperator('1^', sympy.Symbol('x')) with self.assertRaises(TypeError): - save_operator(operator, self.file_name, plain_text=True) + save_operator(operator, self.file_name, data_directory=self.test_dir, plain_text=True) def test_raises_error_sympy(self): operator = FermionOperator('1^', sympy.Symbol('x')) with self.assertRaises(TypeError): - save_operator(operator, self.file_name, plain_text=False) + save_operator(operator, self.file_name, data_directory=self.test_dir, plain_text=False) def test_save_and_load_fermion_operators(self): - save_operator(self.fermion_operator, self.file_name) - loaded_fermion_operator = load_operator(self.file_name) + save_operator(self.fermion_operator, self.file_name, data_directory=self.test_dir) + loaded_fermion_operator = load_operator(self.file_name, data_directory=self.test_dir) self.assertEqual( self.fermion_operator, loaded_fermion_operator, @@ -501,13 +500,17 @@ def test_save_and_load_fermion_operators(self): ) def test_save_and_load_fermion_operators_readably(self): - save_operator(self.fermion_operator, self.file_name, plain_text=True) - loaded_fermion_operator = load_operator(self.file_name, plain_text=True) + save_operator( + self.fermion_operator, self.file_name, data_directory=self.test_dir, plain_text=True + ) + loaded_fermion_operator = load_operator( + self.file_name, data_directory=self.test_dir, plain_text=True + ) self.assertTrue(self.fermion_operator == loaded_fermion_operator) def test_save_and_load_boson_operators(self): - save_operator(self.boson_operator, self.file_name) - loaded_boson_operator = load_operator(self.file_name) + save_operator(self.boson_operator, self.file_name, data_directory=self.test_dir) + loaded_boson_operator = load_operator(self.file_name, data_directory=self.test_dir) self.assertEqual( self.boson_operator.terms, loaded_boson_operator.terms, @@ -515,37 +518,51 @@ def test_save_and_load_boson_operators(self): ) def test_save_and_load_boson_operators_readably(self): - save_operator(self.boson_operator, self.file_name, plain_text=True) - loaded_boson_operator = load_operator(self.file_name, plain_text=True) + save_operator( + self.boson_operator, self.file_name, data_directory=self.test_dir, plain_text=True + ) + loaded_boson_operator = load_operator( + self.file_name, data_directory=self.test_dir, plain_text=True + ) self.assertTrue(self.boson_operator == loaded_boson_operator) def test_save_and_load_quad_operators(self): - save_operator(self.quad_operator, self.file_name) - loaded_quad_operator = load_operator(self.file_name) + save_operator(self.quad_operator, self.file_name, data_directory=self.test_dir) + loaded_quad_operator = load_operator(self.file_name, data_directory=self.test_dir) self.assertEqual(self.quad_operator.terms, loaded_quad_operator.terms) def test_save_and_load_quad_operators_readably(self): - save_operator(self.quad_operator, self.file_name, plain_text=True) - loaded_quad_operator = load_operator(self.file_name, plain_text=True) + save_operator( + self.quad_operator, self.file_name, data_directory=self.test_dir, plain_text=True + ) + loaded_quad_operator = load_operator( + self.file_name, data_directory=self.test_dir, plain_text=True + ) self.assertTrue(self.quad_operator == loaded_quad_operator) def test_save_and_load_qubit_operators(self): - save_operator(self.qubit_operator, self.file_name) - loaded_qubit_operator = load_operator(self.file_name) + save_operator(self.qubit_operator, self.file_name, data_directory=self.test_dir) + loaded_qubit_operator = load_operator(self.file_name, data_directory=self.test_dir) self.assertTrue(self.qubit_operator == loaded_qubit_operator) def test_save_and_load_qubit_operators_readably(self): - save_operator(self.qubit_operator, self.file_name, plain_text=True) - loaded_qubit_operator = load_operator(self.file_name, plain_text=True) + save_operator( + self.qubit_operator, self.file_name, data_directory=self.test_dir, plain_text=True + ) + loaded_qubit_operator = load_operator( + self.file_name, data_directory=self.test_dir, plain_text=True + ) self.assertEqual(self.qubit_operator, loaded_qubit_operator) def test_load_bad_operator(self): with self.assertRaises(TypeError): - load_operator(self.bad_operator_filename, plain_text=True) + load_operator(self.bad_operator_filename, data_directory=self.test_dir, plain_text=True) def test_save_readably(self): - save_operator(self.fermion_operator, self.file_name, plain_text=True) - file_path = os.path.join(DATA_DIRECTORY, self.file_name + '.data') + save_operator( + self.fermion_operator, self.file_name, data_directory=self.test_dir, plain_text=True + ) + file_path = os.path.join(self.test_dir, self.file_name + '.data') with open(file_path, "r") as f: self.assertEqual( f.read(), @@ -557,7 +574,7 @@ def test_save_no_filename_operator_utils_error(self): save_operator(self.fermion_operator) def test_basic_save(self): - save_operator(self.fermion_operator, self.file_name) + save_operator(self.fermion_operator, self.file_name, data_directory=self.test_dir) def test_save_interaction_operator_not_implemented(self): constant = 100.0 @@ -567,32 +584,42 @@ def test_save_interaction_operator_not_implemented(self): two_body[1, 2, 3, 4] = 12.0 interaction_operator = InteractionOperator(constant, one_body, two_body) with self.assertRaises(NotImplementedError): - save_operator(interaction_operator, self.file_name) + save_operator(interaction_operator, self.file_name, data_directory=self.test_dir) def test_save_on_top_of_existing_operator_utils_error(self): - save_operator(self.fermion_operator, self.file_name) + save_operator(self.fermion_operator, self.file_name, data_directory=self.test_dir) with self.assertRaises(OperatorUtilsError): - save_operator(self.fermion_operator, self.file_name) + save_operator(self.fermion_operator, self.file_name, data_directory=self.test_dir) def test_save_on_top_of_existing_operator_error_with_explicit_flag(self): - save_operator(self.fermion_operator, self.file_name) + save_operator(self.fermion_operator, self.file_name, data_directory=self.test_dir) with self.assertRaises(OperatorUtilsError): - save_operator(self.fermion_operator, self.file_name, allow_overwrite=False) + save_operator( + self.fermion_operator, + self.file_name, + data_directory=self.test_dir, + allow_overwrite=False, + ) def test_overwrite_flag_save_on_top_of_existing_operator(self): - save_operator(self.fermion_operator, self.file_name) - save_operator(self.fermion_operator, self.file_name, allow_overwrite=True) - fermion_operator = load_operator(self.file_name) + save_operator(self.fermion_operator, self.file_name, data_directory=self.test_dir) + save_operator( + self.fermion_operator, + self.file_name, + data_directory=self.test_dir, + allow_overwrite=True, + ) + fermion_operator = load_operator(self.file_name, data_directory=self.test_dir) self.assertEqual(fermion_operator, self.fermion_operator) def test_load_bad_type(self): with self.assertRaises(TypeError): - _ = load_operator('bad_type_operator') + _ = load_operator('bad_type_operator', data_directory=self.test_dir) def test_save_bad_type(self): with self.assertRaises(TypeError): - save_operator('ping', 'somewhere') + save_operator('ping', 'somewhere', data_directory=self.test_dir) class GetFileDirTest(unittest.TestCase):