From 7624b17134409cbb81bc15d2a3211efaa1335f52 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Sun, 16 Jun 2024 08:18:23 -0700 Subject: [PATCH 01/54] Np2.0 support. Fixes #3881. --- pymatgen/util/coord_cython.pyx | 2 ++ pyproject.toml | 1 + requirements.txt | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pymatgen/util/coord_cython.pyx b/pymatgen/util/coord_cython.pyx index 54c72e92508..3e553ebe80a 100644 --- a/pymatgen/util/coord_cython.pyx +++ b/pymatgen/util/coord_cython.pyx @@ -20,6 +20,8 @@ cimport numpy as np from libc.math cimport fabs, round from libc.stdlib cimport free, malloc +np.import_array() + #create images, 2d array of all length 3 combinations of [-1,0,1] rng = np.arange(-1, 2, dtype=np.float_) arange = rng[:, None] * np.array([1, 0, 0])[None, :] diff --git a/pyproject.toml b/pyproject.toml index bc9f398c4e5..6024ddac12d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -197,6 +197,7 @@ select = [ "I", # isort "ICN", # flake8-import-conventions "ISC", # flake8-implicit-str-concat + "NPY201", # numpy 2.0 "PD", # pandas-vet "PERF", # perflint "PIE", # flake8-pie diff --git a/requirements.txt b/requirements.txt index 110920a9994..36129880bec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,11 @@ -numpy==1.26.4 +numpy==2.0.0 sympy==1.12 requests==2.32.3 monty==2024.5.24 ruamel.yaml==0.18.6 scipy==1.13.1 tabulate==0.9.0 -matplotlib==3.8.0 +matplotlib==3.9.0 palettable==3.3.3 spglib==2.1.0 pandas==2.1.1 From 5003be3d7f0488aba949ce77d6f3522175fec8b4 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Sun, 16 Jun 2024 08:22:33 -0700 Subject: [PATCH 02/54] Bump min ruff version. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6024ddac12d..5e1f254c09e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ dev = [ "pytest-cov>=4", "pytest-split>=0.8", "pytest>8", - "ruff>=0.4", + "ruff>=0.4.8", ] ci = [ "pytest>=8", From 6b43f5fb4f628b0bc97353c74ea38c246abf8f5d Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Sun, 16 Jun 2024 08:24:25 -0700 Subject: [PATCH 03/54] Remove defunct doc2dash req. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5e1f254c09e..b027b1f5ff6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,7 +108,6 @@ ci = [ docs = [ "sphinx", "sphinx_rtd_theme", - "doc2dash", ] optional = [ "ase>=3.23.0", From dac543fe79b4a9eac067002e6b1a01ca783e73a5 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Sun, 16 Jun 2024 12:55:17 -0700 Subject: [PATCH 04/54] Try to resolve build error on windows. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 377fe28e21a..2cc748a9718 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -79,7 +79,7 @@ jobs: # track https://github.com/astral-sh/uv/issues/1921 for resolution pip install torch - uv pip install numpy cython + uv pip install --upgrade numpy cython uv pip install --editable '.[${{ matrix.config.extras }}]' --resolution=${{ matrix.config.resolution }} - name: pytest split ${{ matrix.split }} From fc938677107841054bf127b62041c3b4f6affba0 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Sun, 16 Jun 2024 13:35:59 -0700 Subject: [PATCH 05/54] Add np import. --- pymatgen/optimization/linear_assignment.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pymatgen/optimization/linear_assignment.pyx b/pymatgen/optimization/linear_assignment.pyx index 9c7f28896ee..ae3e0a89125 100644 --- a/pymatgen/optimization/linear_assignment.pyx +++ b/pymatgen/optimization/linear_assignment.pyx @@ -12,6 +12,8 @@ cimport numpy as np from libc.math cimport fabs from libc.stdlib cimport free, malloc +np.import_array() + __author__ = "Will Richards" __copyright__ = "Copyright 2011, The Materials Project" __version__ = "1.0" From ed5814abe6acc50d9ecd82cab5497c884453b25a Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Sun, 16 Jun 2024 13:50:52 -0700 Subject: [PATCH 06/54] Peg to np<2.0 first. --- .github/workflows/test.yml | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2cc748a9718..377fe28e21a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -79,7 +79,7 @@ jobs: # track https://github.com/astral-sh/uv/issues/1921 for resolution pip install torch - uv pip install --upgrade numpy cython + uv pip install numpy cython uv pip install --editable '.[${{ matrix.config.extras }}]' --resolution=${{ matrix.config.resolution }} - name: pytest split ${{ matrix.split }} diff --git a/pyproject.toml b/pyproject.toml index b027b1f5ff6..e3c8bf388ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ dependencies = [ "matplotlib>=3.8", "monty>=2024.5.24", "networkx>=2.2", - "numpy>=1.25.0", + "numpy>=1.25.0,<2.0.0", "palettable>=3.1.1", "pandas>=2", "plotly>=4.5.0", diff --git a/requirements.txt b/requirements.txt index 36129880bec..ef6df118680 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==2.0.0 +numpy==1.26.4 sympy==1.12 requests==2.32.3 monty==2024.5.24 From 5b84828215730872872c2a882ddd1e65d72c859b Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Mon, 17 Jun 2024 07:52:27 -0700 Subject: [PATCH 07/54] Skip from_id tests in PRs. Fixes #3883. --- tests/core/test_structure.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/core/test_structure.py b/tests/core/test_structure.py index c5a939079a0..e1d911ad40c 100644 --- a/tests/core/test_structure.py +++ b/tests/core/test_structure.py @@ -14,7 +14,7 @@ from numpy.testing import assert_allclose, assert_array_equal from pytest import approx -from pymatgen.core import Composition, Element, Lattice, Species +from pymatgen.core import SETTINGS, Composition, Element, Lattice, Species from pymatgen.core.operations import SymmOp from pymatgen.core.structure import ( IMolecule, @@ -924,6 +924,10 @@ def setUp(self): self.disordered = Structure.from_spacegroup("Im-3m", Lattice.cubic(3), [Composition("Fe0.5Mn0.5")], [[0, 0, 0]]) self.labeled_structure = Structure(lattice, ["Si", "Si"], coords, labels=["Si1", "Si2"]) + @pytest.mark.skipif( + SETTINGS.get("PMG_MAPI_KEY", "") == "", + reason="PMG_MAPI_KEY environment variable not set or MP API is down. This is also the case in a PR.", + ) def test_from_id(self): s = Structure.from_id("mp-1143") assert isinstance(s, Structure) From 9719845b1b449741c8ec661d6c09a443c982213a Mon Sep 17 00:00:00 2001 From: "Haoyu (Daniel)" Date: Mon, 17 Jun 2024 23:25:36 +0800 Subject: [PATCH 08/54] [Deprecation] Correct cases for memory units in `core.units` and fix `unit_type` detection of `FloatWithUnit.from_str` (#3838) * fix memory unit case * fix case in comments * handle white space * remove debug change * maintain case sensitivity for memory * simplify white space removal * add a grace period till 2025-01-01 * use safer strip * add test for bad string * make msg more descriptive * remove unnecessary type cast * extend test coverage --------- Co-authored-by: Janosh Riebesell Co-authored-by: Shyue Ping Ong --- pymatgen/core/units.py | 28 +++++++++++++++++----------- tests/core/test_units.py | 30 +++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/pymatgen/core/units.py b/pymatgen/core/units.py index 6b0d8071b27..9e6b44b9de3 100644 --- a/pymatgen/core/units.py +++ b/pymatgen/core/units.py @@ -12,6 +12,7 @@ import collections import re +import warnings from collections import defaultdict from functools import partial from numbers import Number @@ -78,16 +79,13 @@ "intensity": {"cd": 1}, "memory": { "byte": 1, - "Kb": 1024, - "Mb": 1024**2, - "Gb": 1024**3, - "Tb": 1024**4, + "KB": 1024, + "MB": 1024**2, + "GB": 1024**3, + "TB": 1024**4, }, } -# Accept kb, mb, gb ... as well. -BASE_UNITS["memory"].update({k.lower(): v for k, v in BASE_UNITS["memory"].items()}) - # This current list are supported derived units defined in terms of powers of # SI base units and constants. DERIVED_UNITS: dict[str, dict] = { @@ -312,6 +310,14 @@ def __init__( unit (str | Unit): A unit. e.g. "C". unit_type (str): A type of unit. e.g. "charge" """ + # Check deprecated memory unit + # TODO: remove after 2025-01-01 + if unit_type == "memory" and str(unit) in {"Kb", "kb", "Mb", "mb", "Gb", "gb", "Tb", "tb"}: + warnings.warn( + f"Unit {unit!s} is deprecated, please use {str(unit).upper()} instead", DeprecationWarning, stacklevel=2 + ) + unit = str(unit).upper() + if unit_type is not None and str(unit) not in ALL_UNITS[unit_type]: raise UnitError(f"{unit} is not a supported unit for {unit_type}") @@ -440,16 +446,16 @@ def from_str(cls, string: str) -> Self: """Convert string to FloatWithUnit. Example usage: - Memory.from_str("1. Mb"). + Memory.from_str("1. MB"). """ - # Extract num and unit string. + # Extract num and unit string string = string.strip() for _idx, char in enumerate(string): if char.isalpha() or char.isspace(): break else: raise ValueError(f"Unit is missing in string {string}") - num, unit = float(string[:_idx]), string[_idx:] + num, unit = float(string[:_idx]), string[_idx:].strip() # Find unit type (set it to None if it cannot be detected) for unit_type, dct in BASE_UNITS.items(): @@ -763,7 +769,7 @@ def _my_partial(func, *args, **kwargs): Args: val (float): Value - unit (Unit): e.g. Kb, Mb, Gb, Tb. Must be valid unit or UnitError + unit (Unit): e.g. KB, MB, GB, TB. Must be valid unit or UnitError is raised. """ diff --git a/tests/core/test_units.py b/tests/core/test_units.py index ae785b20f7a..2abfd5df8f0 100644 --- a/tests/core/test_units.py +++ b/tests/core/test_units.py @@ -1,5 +1,7 @@ from __future__ import annotations +import warnings + import pytest from numpy.testing import assert_array_equal from pytest import approx @@ -89,20 +91,34 @@ def test_length(self): assert x.to("cm") == approx(4.2e-08) assert x.to("pm") == 420 assert str(x / 2) == "2.1 ang" + y = x**3 assert y == approx(74.088) assert str(y.unit) == "ang^3" def test_memory(self): - mega = Memory(1, "Mb") - assert mega.to("byte") == 1024**2 - assert mega == Memory(1, "mb") + mega_0 = Memory(1, "MB") + assert mega_0.to("byte") == 1024**2 + + mega_1 = Memory.from_str("1 MB") + assert mega_1.unit_type == "memory" + + mega_2 = Memory.from_str("1MB") + assert mega_2.unit_type == "memory" + + mega_3 = Memory.from_str("+1.0 MB") + assert mega_0 == mega_1 == mega_2 == mega_3 - same_mega = Memory.from_str("1Mb") - assert same_mega.unit_type == "memory" + def test_deprecated_memory(self): + # TODO: remove after 2025-01-01 + for unit in ("Kb", "kb", "Mb", "mb", "Gb", "gb", "Tb", "tb"): + with pytest.warns(DeprecationWarning, match=f"Unit {unit} is deprecated"): + Memory(1, unit) - other_mega = Memory.from_str("+1.0 mb") - assert mega == other_mega + with warnings.catch_warnings(): + warnings.simplefilter("error") + for unit in ("KB", "MB", "GB", "TB"): + Memory(1, unit) def test_unitized(self): @unitized("eV") From 91f34b53b633084e6f44c165e8374d6ff0df61c9 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 09:40:34 -0700 Subject: [PATCH 09/54] Update pyproject.toml Try platform specific support for NP2. --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e3c8bf388ff..450c475615e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,8 @@ dependencies = [ "matplotlib>=3.8", "monty>=2024.5.24", "networkx>=2.2", - "numpy>=1.25.0,<2.0.0", + 'numpy>=1.25.0,<2.0.0; platform_system == "Windows"', + 'numpy>=1.25.0; platform_system != "Windows"', "palettable>=3.1.1", "pandas>=2", "plotly>=4.5.0", From 47fc9c8e401514199e73d731793299e781d54848 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 12:50:05 -0700 Subject: [PATCH 10/54] Update pyproject.toml Remove platform dependence since it seems like np2.0 works. --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 450c475615e..b027b1f5ff6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,8 +60,7 @@ dependencies = [ "matplotlib>=3.8", "monty>=2024.5.24", "networkx>=2.2", - 'numpy>=1.25.0,<2.0.0; platform_system == "Windows"', - 'numpy>=1.25.0; platform_system != "Windows"', + "numpy>=1.25.0", "palettable>=3.1.1", "pandas>=2", "plotly>=4.5.0", From aba5fe3d92f600c97e1fbdad9717ebb64ac87871 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 13:55:43 -0700 Subject: [PATCH 11/54] Update pyproject.toml Guess still need platform specific np2 --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b027b1f5ff6..0cc1e59cf37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,8 @@ dependencies = [ "matplotlib>=3.8", "monty>=2024.5.24", "networkx>=2.2", - "numpy>=1.25.0", + 'numpy>=1.25.0,<2.0 ; platform_system == "Windows"', + 'numpy>=1.25.0 ; platform_system != "Windows"', "palettable>=3.1.1", "pandas>=2", "plotly>=4.5.0", From 2a67b23afd87598fa27ced58aa63b2c1865f1a15 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 16:50:14 -0700 Subject: [PATCH 12/54] Add editorconfig. --- .editorconfig | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..c34fd617ee6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Matches multiple files with brace expansion notation +# Set default charset +[*.py] +charset = utf-8 + +# 4 space indentation +[*.py] +indent_style = space +indent_size = 4 + +# Matches the exact files either package.json or .travis.yml +[{*.{json,yml,yaml}] +indent_style = space +indent_size = 2 From 17f61ff63506f7c063b81106a1c4b9f9796f960f Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 17:03:59 -0700 Subject: [PATCH 13/54] Update torch. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 377fe28e21a..baa912a8a3d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -77,7 +77,7 @@ jobs: micromamba activate pmg # TODO remove temporary fix. added since uv install torch is flaky. # track https://github.com/astral-sh/uv/issues/1921 for resolution - pip install torch + pip install torch --upgrade uv pip install numpy cython uv pip install --editable '.[${{ matrix.config.extras }}]' --resolution=${{ matrix.config.resolution }} From a24254a4726e0f1df232809b1a384bcf9efa3dbe Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 17:17:34 -0700 Subject: [PATCH 14/54] Fix .editorconfig. --- .editorconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index c34fd617ee6..32a321393a5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,10 +5,6 @@ root = true [*] end_of_line = lf insert_final_newline = true - -# Matches multiple files with brace expansion notation -# Set default charset -[*.py] charset = utf-8 # 4 space indentation @@ -17,6 +13,6 @@ indent_style = space indent_size = 4 # Matches the exact files either package.json or .travis.yml -[{*.{json,yml,yaml}] +[*.{json,yml,yaml}] indent_style = space indent_size = 2 From 2b53fb1cdf08d5022894c0cb4e6960f3c4edcf81 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 17:22:40 -0700 Subject: [PATCH 15/54] Minor yaml formatting. --- pymatgen/vis/ElementColorSchemes.yaml | 436 +++++++++++++------------- 1 file changed, 218 insertions(+), 218 deletions(-) diff --git a/pymatgen/vis/ElementColorSchemes.yaml b/pymatgen/vis/ElementColorSchemes.yaml index 1480a741d64..c9896d6c732 100644 --- a/pymatgen/vis/ElementColorSchemes.yaml +++ b/pymatgen/vis/ElementColorSchemes.yaml @@ -1,220 +1,220 @@ Jmol: - Ac: [112, 171, 250] - Ag: [192, 192, 192] - Al: [191, 166, 166] - Am: [84, 92, 242] - Ar: [128, 209, 227] - As: [189, 128, 227] - At: [117, 79, 69] - Au: [255, 209, 35] - B: [255, 181, 181] - Ba: [0, 201, 0] - Be: [194, 255, 0] - Bh: [224, 0, 56] - Bi: [158, 79, 181] - Bk: [138, 79, 227] - Br: [166, 41, 41] - C: [144, 144, 144] - Ca: [61, 255, 0] - Cd: [255, 217, 143] - Ce: [255, 255, 199] - Cf: [161, 54, 212] - Cl: [31, 240, 31] - Cm: [120, 92, 227] - Co: [240, 144, 160] - Cr: [138, 153, 199] - Cs: [87, 23, 143] - Cu: [200, 128, 51] - Db: [209, 0, 79] - Dy: [31, 255, 199] - Er: [0, 230, 117] - Es: [179, 31, 212] - Eu: [97, 255, 199] - F: [144, 224, 80] - Fe: [224, 102, 51] - Fm: [179, 31, 186] - Fr: [66, 0, 102] - Ga: [194, 143, 143] - Gd: [69, 255, 199] - Ge: [102, 143, 143] - H: [255, 255, 255] - He: [217, 255, 255] - Hf: [77, 194, 255] - Hg: [184, 184, 208] - Ho: [0, 255, 156] - Hs: [230, 0, 46] - I: [148, 0, 148] - In: [166, 117, 115] - Ir: [23, 84, 135] - K: [143, 64, 212] - Kr: [92, 184, 209] - La: [112, 212, 255] - Li: [204, 128, 255] - Lr: [199, 0, 102] - Lu: [0, 171, 36] - Md: [179, 13, 166] - Mg: [138, 255, 0] - Mn: [156, 122, 199] - Mo: [84, 181, 181] - Mt: [235, 0, 38] - N: [48, 80, 248] - Na: [171, 92, 242] - Nb: [115, 194, 201] - Nd: [199, 255, 199] - Ne: [179, 227, 245] - Ni: [80, 208, 80] - 'No': [189, 13, 135] - Np: [0, 128, 255] - O: [255, 13, 13] - Os: [38, 102, 150] - P: [255, 128, 0] - Pa: [0, 161, 255] - Pb: [87, 89, 97] - Pd: [0, 105, 133] - Pm: [163, 255, 199] - Po: [171, 92, 0] - Pr: [217, 255, 199] - Pt: [208, 208, 224] - Pu: [0, 107, 255] - Ra: [0, 125, 0] - Rb: [112, 46, 176] - Re: [38, 125, 171] - Rf: [204, 0, 89] - Rh: [10, 125, 140] - Rn: [66, 130, 150] - Ru: [36, 143, 143] - S: [255, 255, 48] - Sb: [158, 99, 181] - Sc: [230, 230, 230] - Se: [255, 161, 0] - Sg: [217, 0, 69] - Si: [240, 200, 160] - Sm: [143, 255, 199] - Sn: [102, 128, 128] - Sr: [0, 255, 0] - Ta: [77, 166, 255] - Tb: [48, 255, 199] - Tc: [59, 158, 158] - Te: [212, 122, 0] - Th: [0, 186, 255] - Ti: [191, 194, 199] - Tl: [166, 84, 77] - Tm: [0, 212, 82] - U: [0, 143, 255] - V: [166, 166, 171] - W: [33, 148, 214] - Xe: [66, 158, 176] - Y: [148, 255, 255] - Yb: [0, 191, 56] - Zn: [125, 128, 176] - Zr: [148, 224, 224] + Ac: [ 112, 171, 250 ] + Ag: [ 192, 192, 192 ] + Al: [ 191, 166, 166 ] + Am: [ 84, 92, 242 ] + Ar: [ 128, 209, 227 ] + As: [ 189, 128, 227 ] + At: [ 117, 79, 69 ] + Au: [ 255, 209, 35 ] + B: [ 255, 181, 181 ] + Ba: [ 0, 201, 0 ] + Be: [ 194, 255, 0 ] + Bh: [ 224, 0, 56 ] + Bi: [ 158, 79, 181 ] + Bk: [ 138, 79, 227 ] + Br: [ 166, 41, 41 ] + C: [ 144, 144, 144 ] + Ca: [ 61, 255, 0 ] + Cd: [ 255, 217, 143 ] + Ce: [ 255, 255, 199 ] + Cf: [ 161, 54, 212 ] + Cl: [ 31, 240, 31 ] + Cm: [ 120, 92, 227 ] + Co: [ 240, 144, 160 ] + Cr: [ 138, 153, 199 ] + Cs: [ 87, 23, 143 ] + Cu: [ 200, 128, 51 ] + Db: [ 209, 0, 79 ] + Dy: [ 31, 255, 199 ] + Er: [ 0, 230, 117 ] + Es: [ 179, 31, 212 ] + Eu: [ 97, 255, 199 ] + F: [ 144, 224, 80 ] + Fe: [ 224, 102, 51 ] + Fm: [ 179, 31, 186 ] + Fr: [ 66, 0, 102 ] + Ga: [ 194, 143, 143 ] + Gd: [ 69, 255, 199 ] + Ge: [ 102, 143, 143 ] + H: [ 255, 255, 255 ] + He: [ 217, 255, 255 ] + Hf: [ 77, 194, 255 ] + Hg: [ 184, 184, 208 ] + Ho: [ 0, 255, 156 ] + Hs: [ 230, 0, 46 ] + I: [ 148, 0, 148 ] + In: [ 166, 117, 115 ] + Ir: [ 23, 84, 135 ] + K: [ 143, 64, 212 ] + Kr: [ 92, 184, 209 ] + La: [ 112, 212, 255 ] + Li: [ 204, 128, 255 ] + Lr: [ 199, 0, 102 ] + Lu: [ 0, 171, 36 ] + Md: [ 179, 13, 166 ] + Mg: [ 138, 255, 0 ] + Mn: [ 156, 122, 199 ] + Mo: [ 84, 181, 181 ] + Mt: [ 235, 0, 38 ] + N: [ 48, 80, 248 ] + Na: [ 171, 92, 242 ] + Nb: [ 115, 194, 201 ] + Nd: [ 199, 255, 199 ] + Ne: [ 179, 227, 245 ] + Ni: [ 80, 208, 80 ] + 'No': [ 189, 13, 135 ] + Np: [ 0, 128, 255 ] + O: [ 255, 13, 13 ] + Os: [ 38, 102, 150 ] + P: [ 255, 128, 0 ] + Pa: [ 0, 161, 255 ] + Pb: [ 87, 89, 97 ] + Pd: [ 0, 105, 133 ] + Pm: [ 163, 255, 199 ] + Po: [ 171, 92, 0 ] + Pr: [ 217, 255, 199 ] + Pt: [ 208, 208, 224 ] + Pu: [ 0, 107, 255 ] + Ra: [ 0, 125, 0 ] + Rb: [ 112, 46, 176 ] + Re: [ 38, 125, 171 ] + Rf: [ 204, 0, 89 ] + Rh: [ 10, 125, 140 ] + Rn: [ 66, 130, 150 ] + Ru: [ 36, 143, 143 ] + S: [ 255, 255, 48 ] + Sb: [ 158, 99, 181 ] + Sc: [ 230, 230, 230 ] + Se: [ 255, 161, 0 ] + Sg: [ 217, 0, 69 ] + Si: [ 240, 200, 160 ] + Sm: [ 143, 255, 199 ] + Sn: [ 102, 128, 128 ] + Sr: [ 0, 255, 0 ] + Ta: [ 77, 166, 255 ] + Tb: [ 48, 255, 199 ] + Tc: [ 59, 158, 158 ] + Te: [ 212, 122, 0 ] + Th: [ 0, 186, 255 ] + Ti: [ 191, 194, 199 ] + Tl: [ 166, 84, 77 ] + Tm: [ 0, 212, 82 ] + U: [ 0, 143, 255 ] + V: [ 166, 166, 171 ] + W: [ 33, 148, 214 ] + Xe: [ 66, 158, 176 ] + Y: [ 148, 255, 255 ] + Yb: [ 0, 191, 56 ] + Zn: [ 125, 128, 176 ] + Zr: [ 148, 224, 224 ] VESTA: - Ac: [112, 171, 250] - Ag: [192, 192, 192] - Al: [129, 178, 214] - Am: [84, 92, 242] - Ar: [207, 254, 196] - As: [116, 208, 87] - At: [117, 79, 69] - Au: [255, 209, 35] - B: [31, 162, 15] - Ba: [0, 201, 0] - Be: [94, 215, 123] - Bh: [224, 0, 56] - Bi: [158, 79, 181] - Bk: [138, 79, 227] - Br: [126, 49, 2] - C: [76, 76, 76] - Ca: [90, 150, 189] - Cd: [255, 217, 143] - Ce: [255, 255, 199] - Cf: [161, 54, 212] - Cl: [49, 252, 2] - Cm: [120, 92, 227] - Co: [0, 0, 175] - Cr: [0, 0, 158] - Cs: [87, 23, 143] - Cu: [34, 71, 220] - Db: [209, 0, 79] - Dy: [31, 255, 199] - Er: [0, 230, 117] - Es: [179, 31, 212] - Eu: [97, 255, 199] - F: [176, 185, 230] - Fe: [181, 113, 0] - Fm: [179, 31, 186] - Fr: [66, 0, 102] - Ga: [158, 227, 115] - Gd: [69, 255, 199] - Ge: [126, 110, 166] - H: [255, 204, 204] - He: [252, 232, 206] - Hf: [77, 194, 255] - Hg: [184, 184, 208] - Ho: [0, 255, 156] - Hs: [230, 0, 46] - I: [148, 0, 148] - In: [166, 117, 115] - Ir: [23, 84, 135] - K: [161, 33, 246] - Kr: [250, 193, 243] - La: [90, 196, 73] - Li: [134, 223, 115] - Lr: [199, 0, 102] - Lu: [0, 171, 36] - Md: [179, 13, 166] - Mg: [251, 123, 21] - Mn: [167, 8, 157] - Mo: [84, 181, 181] - Mt: [235, 0, 38] - N: [176, 185, 230] - Na: [249, 220, 60] - Nb: [115, 194, 201] - Nd: [199, 255, 199] - Ne: [254, 55, 181] - Ni: [183, 187, 189] - 'No': [189, 13, 135] - Np: [0, 128, 255] - O: [254, 3, 0] - Os: [38, 102, 150] - P: [192, 156, 194] - Pa: [0, 161, 255] - Pb: [87, 89, 97] - Pd: [0, 105, 133] - Pm: [163, 255, 199] - Po: [171, 92, 0] - Pr: [217, 255, 199] - Pt: [208, 208, 224] - Pu: [0, 107, 255] - Ra: [0, 125, 0] - Rb: [112, 46, 176] - Re: [38, 125, 171] - Rf: [204, 0, 89] - Rh: [10, 125, 140] - Rn: [66, 130, 150] - Ru: [36, 143, 143] - S: [255, 250, 0] - Sb: [158, 99, 181] - Sc: [181, 99, 171] - Se: [154, 239, 15] - Sg: [217, 0, 69] - Si: [27, 59, 250] - Sm: [143, 255, 199] - Sn: [154, 142, 185] - Sr: [0, 255, 0] - Ta: [77, 166, 255] - Tb: [48, 255, 199] - Tc: [59, 158, 158] - Te: [212, 122, 0] - Th: [0, 186, 255] - Ti: [120, 202, 255] - Tl: [166, 84, 77] - Tm: [0, 212, 82] - U: [0, 143, 255] - V: [229, 25, 0] - W: [33, 148, 214] - Xe: [66, 158, 176] - Y: [148, 255, 255] - Yb: [0, 191, 56] - Zn: [143, 143, 129] - Zr: [0, 255, 0] + Ac: [ 112, 171, 250 ] + Ag: [ 192, 192, 192 ] + Al: [ 129, 178, 214 ] + Am: [ 84, 92, 242 ] + Ar: [ 207, 254, 196 ] + As: [ 116, 208, 87 ] + At: [ 117, 79, 69 ] + Au: [ 255, 209, 35 ] + B: [ 31, 162, 15 ] + Ba: [ 0, 201, 0 ] + Be: [ 94, 215, 123 ] + Bh: [ 224, 0, 56 ] + Bi: [ 158, 79, 181 ] + Bk: [ 138, 79, 227 ] + Br: [ 126, 49, 2 ] + C: [ 76, 76, 76 ] + Ca: [ 90, 150, 189 ] + Cd: [ 255, 217, 143 ] + Ce: [ 255, 255, 199 ] + Cf: [ 161, 54, 212 ] + Cl: [ 49, 252, 2 ] + Cm: [ 120, 92, 227 ] + Co: [ 0, 0, 175 ] + Cr: [ 0, 0, 158 ] + Cs: [ 87, 23, 143 ] + Cu: [ 34, 71, 220 ] + Db: [ 209, 0, 79 ] + Dy: [ 31, 255, 199 ] + Er: [ 0, 230, 117 ] + Es: [ 179, 31, 212 ] + Eu: [ 97, 255, 199 ] + F: [ 176, 185, 230 ] + Fe: [ 181, 113, 0 ] + Fm: [ 179, 31, 186 ] + Fr: [ 66, 0, 102 ] + Ga: [ 158, 227, 115 ] + Gd: [ 69, 255, 199 ] + Ge: [ 126, 110, 166 ] + H: [ 255, 204, 204 ] + He: [ 252, 232, 206 ] + Hf: [ 77, 194, 255 ] + Hg: [ 184, 184, 208 ] + Ho: [ 0, 255, 156 ] + Hs: [ 230, 0, 46 ] + I: [ 148, 0, 148 ] + In: [ 166, 117, 115 ] + Ir: [ 23, 84, 135 ] + K: [ 161, 33, 246 ] + Kr: [ 250, 193, 243 ] + La: [ 90, 196, 73 ] + Li: [ 134, 223, 115 ] + Lr: [ 199, 0, 102 ] + Lu: [ 0, 171, 36 ] + Md: [ 179, 13, 166 ] + Mg: [ 251, 123, 21 ] + Mn: [ 167, 8, 157 ] + Mo: [ 84, 181, 181 ] + Mt: [ 235, 0, 38 ] + N: [ 176, 185, 230 ] + Na: [ 249, 220, 60 ] + Nb: [ 115, 194, 201 ] + Nd: [ 199, 255, 199 ] + Ne: [ 254, 55, 181 ] + Ni: [ 183, 187, 189 ] + 'No': [ 189, 13, 135 ] + Np: [ 0, 128, 255 ] + O: [ 254, 3, 0 ] + Os: [ 38, 102, 150 ] + P: [ 192, 156, 194 ] + Pa: [ 0, 161, 255 ] + Pb: [ 87, 89, 97 ] + Pd: [ 0, 105, 133 ] + Pm: [ 163, 255, 199 ] + Po: [ 171, 92, 0 ] + Pr: [ 217, 255, 199 ] + Pt: [ 208, 208, 224 ] + Pu: [ 0, 107, 255 ] + Ra: [ 0, 125, 0 ] + Rb: [ 112, 46, 176 ] + Re: [ 38, 125, 171 ] + Rf: [ 204, 0, 89 ] + Rh: [ 10, 125, 140 ] + Rn: [ 66, 130, 150 ] + Ru: [ 36, 143, 143 ] + S: [ 255, 250, 0 ] + Sb: [ 158, 99, 181 ] + Sc: [ 181, 99, 171 ] + Se: [ 154, 239, 15 ] + Sg: [ 217, 0, 69 ] + Si: [ 27, 59, 250 ] + Sm: [ 143, 255, 199 ] + Sn: [ 154, 142, 185 ] + Sr: [ 0, 255, 0 ] + Ta: [ 77, 166, 255 ] + Tb: [ 48, 255, 199 ] + Tc: [ 59, 158, 158 ] + Te: [ 212, 122, 0 ] + Th: [ 0, 186, 255 ] + Ti: [ 120, 202, 255 ] + Tl: [ 166, 84, 77 ] + Tm: [ 0, 212, 82 ] + U: [ 0, 143, 255 ] + V: [ 229, 25, 0 ] + W: [ 33, 148, 214 ] + Xe: [ 66, 158, 176 ] + Y: [ 148, 255, 255 ] + Yb: [ 0, 191, 56 ] + Zn: [ 143, 143, 129 ] + Zr: [ 0, 255, 0 ] From e176836a65e26642b8835ebc69edf8b509cbad23 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 22:26:33 -0700 Subject: [PATCH 16/54] Update editorconfig. --- .editorconfig | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index 32a321393a5..6cf8a243c21 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# top-most EditorConfig file +# https://editorconfig.org/ root = true # Unix-style newlines with a newline ending every file @@ -6,13 +6,11 @@ root = true end_of_line = lf insert_final_newline = true charset = utf-8 - -# 4 space indentation -[*.py] indent_style = space indent_size = 4 +trim_trailing_whitespace = true +max_line_length = 120 # Matches the exact files either package.json or .travis.yml [*.{json,yml,yaml}] -indent_style = space indent_size = 2 From a1060fa0b2dd3049280052e5b7af4e0ca1ba8274 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 22:30:04 -0700 Subject: [PATCH 17/54] Clean up comments on editorxonfig. --- .editorconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6cf8a243c21..aae2702499b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,7 @@ # https://editorconfig.org/ root = true -# Unix-style newlines with a newline ending every file +# Default settings for all files. [*] end_of_line = lf insert_final_newline = true @@ -11,6 +11,6 @@ indent_size = 4 trim_trailing_whitespace = true max_line_length = 120 -# Matches the exact files either package.json or .travis.yml +# Set indent size for json and YAML files. [*.{json,yml,yaml}] indent_size = 2 From 11e5c61faa747f211e8d69ddc7a53e65cb9ef214 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Tue, 18 Jun 2024 22:38:16 -0700 Subject: [PATCH 18/54] More cleanup. --- .pre-commit-config.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0c66fbd86bf..f6b3337836f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ exclude: ^(docs|tests/files|tasks.py) ci: autoupdate_schedule: monthly - skip: [mypy, pyright] + skip: [ mypy, pyright ] autofix_commit_msg: pre-commit auto-fixes autoupdate_commit_msg: pre-commit autoupdate @@ -11,7 +11,7 @@ repos: rev: v0.4.8 hooks: - id: ruff - args: [--fix, --unsafe-fixes] + args: [ --fix, --unsafe-fixes ] - id: ruff-format - repo: https://github.com/pre-commit/pre-commit-hooks @@ -30,15 +30,15 @@ repos: rev: v2.3.0 hooks: - id: codespell - stages: [commit, commit-msg] - exclude_types: [html] - additional_dependencies: [tomli] # needed to read pyproject.toml below py3.11 + stages: [ commit, commit-msg ] + exclude_types: [ html ] + additional_dependencies: [ tomli ] # needed to read pyproject.toml below py3.11 - repo: https://github.com/MarcoGorelli/cython-lint rev: v0.16.2 hooks: - id: cython-lint - args: [--no-pycodestyle] + args: [ --no-pycodestyle ] - id: double-quote-cython-strings - repo: https://github.com/adamchainz/blacken-docs @@ -55,13 +55,13 @@ repos: # MD033: no inline HTML # MD041: first line in a file should be a top-level heading # MD025: single title - args: [--disable, MD013, MD024, MD025, MD033, MD041, "--"] + args: [ --disable, MD013, MD024, MD025, MD033, MD041, "--" ] - repo: https://github.com/kynan/nbstripout rev: 0.7.1 hooks: - id: nbstripout - args: [--drop-empty-cells, --keep-output] + args: [ --drop-empty-cells, --keep-output ] - repo: https://github.com/RobertCraigie/pyright-python rev: v1.1.366 From 4a385f9cbaedefd578282a14dcbd82dbf12960e1 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Thu, 20 Jun 2024 16:37:20 +0200 Subject: [PATCH 19/54] Accounting for FHI-aims species' defaults (#3877) * Added species file class * SAdded a list of species' defaults * Added a test on species_defaults * Added new species defaults to AimsControlIn input * AIMS tests changed to account for new species' defaults object --- pymatgen/io/aims/inputs.py | 210 ++++++++++++++++-- tests/io/aims/conftest.py | 9 +- tests/io/aims/test_aims_inputs.py | 50 ++--- .../io/aims/test_sets/test_relax_generator.py | 16 +- .../aims/test_sets/test_static_generator.py | 19 +- 5 files changed, 228 insertions(+), 76 deletions(-) diff --git a/pymatgen/io/aims/inputs.py b/pymatgen/io/aims/inputs.py index fda6aba8a75..77ce214c437 100644 --- a/pymatgen/io/aims/inputs.py +++ b/pymatgen/io/aims/inputs.py @@ -5,8 +5,8 @@ from __future__ import annotations -import gzip import os +import re import time from copy import deepcopy from dataclasses import dataclass, field @@ -16,8 +16,9 @@ import numpy as np from monty.io import zopen from monty.json import MontyDecoder, MSONable +from monty.os.path import zpath -from pymatgen.core import Lattice, Molecule, Structure +from pymatgen.core import SETTINGS, Element, Lattice, Molecule, Structure if TYPE_CHECKING: from collections.abc import Sequence @@ -544,8 +545,10 @@ def get_content( content += cube.control_block content += f"{lim}\n\n" - species_dir = self._parameters.get("species_dir", os.environ.get("AIMS_SPECIES_DIR")) - content += self.get_species_block(structure, species_dir) + species_defaults = self._parameters.get("species_dir", "") + if not species_defaults: + raise KeyError("Species' defaults not specified in the parameters") + content += self.get_species_block(structure, species_defaults) return content @@ -591,12 +594,15 @@ def write_file( file.write(content) - def get_species_block(self, structure: Structure | Molecule, species_dir: str | Path) -> str: + def get_species_block(self, structure: Structure | Molecule, basis_set: str | dict[str, str]) -> str: """Get the basis set information for a structure Args: structure (Molecule or Structure): The structure to get the basis set information for - species_dir (str or Pat:): The directory to find the species files in + basis_set (str | dict[str, str]): + a name of a basis set (`light`, `tight`...) or a mapping from site labels to basis set names. + The name of a basis set can either correspond to the subfolder in `defaults_2020` folder + or be a full path from the `FHI-aims/species_defaults` directory. Returns: The block to add to the control.in file for the species @@ -604,20 +610,8 @@ def get_species_block(self, structure: Structure | Molecule, species_dir: str | Raises: ValueError: If a file for the species is not found """ - block = "" - species = np.unique(structure.species) - for sp in species: - filename = f"{species_dir}/{sp.Z:02d}_{sp.symbol}_default" - if Path(filename).exists(): - with open(filename) as sf: - block += "".join(sf.readlines()) - elif Path(f"{filename}.gz").exists(): - with gzip.open(f"{filename}.gz", mode="rt") as sf: - block += "".join(sf.readlines()) - else: - raise ValueError(f"Species file for {sp.symbol} not found.") - - return block + species_defaults = SpeciesDefaults.from_structure(structure, basis_set) + return str(species_defaults) def as_dict(self) -> dict[str, Any]: """Get a dictionary representation of the geometry.in file.""" @@ -640,3 +634,179 @@ def from_dict(cls, dct: dict[str, Any]) -> Self: decoded = {key: MontyDecoder().process_decoded(val) for key, val in dct.items() if not key.startswith("@")} return cls(_parameters=decoded["parameters"]) + + +class AimsSpeciesFile: + """An FHI-aims single species' defaults file.""" + + def __init__(self, data: str, label: str | None = None) -> None: + """ + Args: + data (str): A string of the complete species defaults file + label (str): A string representing the name of species + """ + self.data = data + self.label = label + if self.label is None: + for line in data.splitlines(): + if "species" in line: + self.label = line.split()[1] + + @classmethod + def from_file(cls, filename: str, label: str | None = None) -> AimsSpeciesFile: + """Initialize from file. + + Args: + filename (str): The filename of the species' defaults file + label (str): A string representing the name of species + + Returns: + The AimsSpeciesFile instance + """ + with zopen(filename, mode="rt") as file: + return cls(file.read(), label) + + @classmethod + def from_element_and_basis_name(cls, element: str, basis: str, *, label: str | None = None) -> AimsSpeciesFile: + """Initialize from element and basis names. + + Args: + element (str): the element name (not to confuse with the species) + basis (str): the directory in which the species' defaults file is located relative to the + root `species_defaults` (or `species_defaults/defaults_2020`) directory.`. + label (str): A string representing the name of species. If not specified, + then equal to element + + Returns: + an AimsSpeciesFile instance + """ + # check if element is in the Periodic Table (+ Emptium) + if element != "Emptium": + if not hasattr(Element, element): + raise ValueError(f"{element} is not a valid element name.") + el_obj = Element(element) + species_file_name = f"{el_obj.Z:02}_{element}_default" + else: + species_file_name = "00_Emptium_default" + + aims_species_dir = SETTINGS.get("AIMS_SPECIES_DIR") + if aims_species_dir is None: + raise ValueError( + "No AIMS_SPECIES_DIR variable found in the config file. " + "Please set the variable in ~/.config/.pmgrc.yaml to the root of `species_defaults` " + "folder in FHIaims/ directory." + ) + paths_to_try = [ + (Path(aims_species_dir) / basis / species_file_name).expanduser().as_posix(), + (Path(aims_species_dir) / "defaults_2020" / basis / species_file_name).expanduser().as_posix(), + ] + for path in paths_to_try: + path = zpath(path) + if os.path.isfile(path): + return cls.from_file(path, label) + + raise RuntimeError( + f"Can't find the species' defaults file for {element} in {basis} basis set. Paths tried: {paths_to_try}" + ) + + def __str__(self): + """String representation of the species' defaults file""" + return re.sub(r"^ *species +\w+", f" species {self.label}", self.data, flags=re.MULTILINE) + + @property + def element(self) -> str: + match = re.search(r"^ *species +(\w+)", self.data, flags=re.MULTILINE) + if match is None: + raise ValueError("Can't find element in species' defaults file") + return match.group(1) + + def as_dict(self) -> dict[str, Any]: + """Dictionary representation of the species' defaults file.""" + return {"label": self.label, "data": self.data, "@module": type(self).__module__, "@class": type(self).__name__} + + @classmethod + def from_dict(cls, dct: dict[str, Any]) -> AimsSpeciesFile: + """Deserialization of the AimsSpeciesFile object""" + return AimsSpeciesFile(data=dct["data"], label=dct["label"]) + + +class SpeciesDefaults(list, MSONable): + """A list containing a set of species' defaults objects with + methods to read and write them to files + """ + + def __init__( + self, + labels: Sequence[str], + basis_set: str | dict[str, str], + *, + elements: dict[str, str] | None = None, + ) -> None: + """ + Args: + labels (list[str]): a list of labels, for which to build species' defaults + basis_set (str | dict[str, str]): + a name of a basis set (`light`, `tight`...) or a mapping from site labels to basis set names. + The name of a basis set can either correspond to the subfolder in `defaults_2020` folder + or be a full path from the `FHI-aims/species_defaults` directory. + elements (dict[str, str] | None): + a mapping from site labels to elements. If some label is not in this mapping, + it coincides with an element. + """ + super().__init__() + self.labels = labels + self.basis_set = basis_set + if elements is None: + elements = {} + self.elements = {} + for label in self.labels: + self.elements[label] = elements.get(label, label) + self._set_species() + + def _set_species(self) -> None: + """Initialize species defaults from the instance data""" + del self[:] + + for label in self.labels: + el = self.elements[label] + if isinstance(self.basis_set, dict): + basis_set = self.basis_set.get(label, None) + if basis_set is None: + raise ValueError(f"Basis set not found for specie {label} (represented by element {el})") + else: + basis_set = self.basis_set + self.append(AimsSpeciesFile.from_element_and_basis_name(el, basis_set, label=label)) + + def __str__(self): + """String representation of the species' defaults""" + return "".join([str(x) for x in self]) + + @classmethod + def from_structure(cls, struct: Structure | Molecule, basis_set: str | dict[str, str]): + """Initialize species defaults from a structure.""" + labels = [] + elements = {} + for label, el in sorted(zip(struct.labels, struct.species)): + if not isinstance(el, Element): + raise TypeError("FHI-aims does not support fractional compositions") + if (label is None) or (el is None): + raise ValueError("Something is terribly wrong with the structure") + if label not in labels: + labels.append(label) + elements[label] = el.name + return SpeciesDefaults(labels, basis_set, elements=elements) + + def to_dict(self): + """Dictionary representation of the species' defaults""" + return { + "labels": self.labels, + "elements": self.elements, + "basis_set": self.basis_set, + "@module": type(self).__module__, + "@class": type(self).__name__, + } + + @classmethod + def from_dict(cls, dct: dict[str, Any]) -> SpeciesDefaults: + """Deserialization of the SpeciesDefaults object""" + return SpeciesDefaults(dct["labels"], dct["basis_set"], elements=dct["elements"]) diff --git a/tests/io/aims/conftest.py b/tests/io/aims/conftest.py index 9d13f62dc56..5060ba4b259 100644 --- a/tests/io/aims/conftest.py +++ b/tests/io/aims/conftest.py @@ -4,9 +4,16 @@ import pytest +from pymatgen.core import SETTINGS + module_dir = os.path.dirname(__file__) @pytest.fixture(autouse=True) def _set_aims_species_dir_env_var(monkeypatch: pytest.MonkeyPatch) -> None: - monkeypatch.setenv("AIMS_SPECIES_DIR", f"{module_dir}/species_directory/light") + monkeypatch.setenv("AIMS_SPECIES_DIR", f"{module_dir}/species_directory") + + +@pytest.fixture(autouse=True) +def _set_aims_species_dir_settings(monkeypatch: pytest.MonkeyPatch): + monkeypatch.setitem(SETTINGS, "AIMS_SPECIES_DIR", f"{module_dir}/species_directory") diff --git a/tests/io/aims/test_aims_inputs.py b/tests/io/aims/test_aims_inputs.py index d0b0d5a30c4..47c0f59d792 100644 --- a/tests/io/aims/test_aims_inputs.py +++ b/tests/io/aims/test_aims_inputs.py @@ -9,12 +9,15 @@ from monty.json import MontyDecoder, MontyEncoder from numpy.testing import assert_allclose +from pymatgen.core import SETTINGS from pymatgen.io.aims.inputs import ( ALLOWED_AIMS_CUBE_TYPES, ALLOWED_AIMS_CUBE_TYPES_STATE, AimsControlIn, AimsCube, AimsGeometryIn, + AimsSpeciesFile, + SpeciesDefaults, ) from pymatgen.util.testing.aims import compare_single_files as compare_files @@ -164,7 +167,7 @@ def test_aims_control_in(tmp_path: Path): "compute_forces": True, "relax_geometry": ["trm", "1e-3"], "batch_size_limit": 200, - "species_dir": str(TEST_DIR.parent / "species_directory/light"), + "species_dir": "light", } aims_control = AimsControlIn(parameters.copy()) @@ -204,30 +207,27 @@ def test_aims_control_in(tmp_path: Path): compare_files(TEST_DIR / "control.in.si", f"{tmp_path}/control.in") -def test_aims_control_in_default_species_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): - monkeypatch.setenv("AIMS_SPECIES_DIR", str(TEST_DIR.parent / "species_directory/light")) +def test_species_file(monkeypatch: pytest.MonkeyPatch): + """Tests an AimsSpeciesFile class""" + monkeypatch.setitem(SETTINGS, "AIMS_SPECIES_DIR", str(TEST_DIR.parent / "species_directory")) + species_file = AimsSpeciesFile.from_element_and_basis_name("Si", "light", label="Si_surface") + assert species_file.label == "Si_surface" + assert species_file.element == "Si" - parameters = { - "cubes": [ - AimsCube(type="eigenstate 1", points=[10, 10, 10]), - AimsCube(type="total_density", points=[10, 10, 10]), - ], - "xc": "LDA", - "smearing": ["fermi-dirac", 0.01], - "vdw_correction_hirshfeld": True, - "compute_forces": True, - "relax_geometry": ["trm", "1e-3"], - "batch_size_limit": 200, - "output": ["band 0 0 0 0.5 0 0.5 10 G X", "band 0 0 0 0.5 0.5 0.5 10 G L"], - "k_grid": [1, 1, 1], - } - - aims_control = AimsControlIn(parameters.copy()) - - for key, val in parameters.items(): - assert aims_control[key] == val +def test_species_defaults(monkeypatch: pytest.MonkeyPatch): + """Tests an AimsSpeciesDefaults class""" + monkeypatch.setitem(SETTINGS, "AIMS_SPECIES_DIR", str(TEST_DIR.parent / "species_directory")) si = AimsGeometryIn.from_file(TEST_DIR / "geometry.in.si.gz").structure - - aims_control.write_file(si, directory=tmp_path, verbose_header=True, overwrite=True) - compare_files(TEST_DIR / "control.in.si.no_sd", f"{tmp_path}/control.in") + species_defaults = SpeciesDefaults.from_structure(si, "light") + assert species_defaults.labels == [ + "Si", + ] + assert species_defaults.elements == {"Si": "Si"} + + si.relabel_sites() + species_defaults = SpeciesDefaults.from_structure(si, "light") + assert species_defaults.labels == ["Si_1", "Si_2"] + assert species_defaults.elements == {"Si_1": "Si", "Si_2": "Si"} + assert "Si_1" in str(species_defaults) + assert "Si_2" in str(species_defaults) diff --git a/tests/io/aims/test_sets/test_relax_generator.py b/tests/io/aims/test_sets/test_relax_generator.py index 93fdfca329b..1f2798c1514 100644 --- a/tests/io/aims/test_sets/test_relax_generator.py +++ b/tests/io/aims/test_sets/test_relax_generator.py @@ -12,29 +12,17 @@ def test_relax_si(tmp_path): params = { - "species_dir": str(species_dir / "light"), + "species_dir": "light", "k_grid": [2, 2, 2], } comp_system(Si, params, "relax-si/", tmp_path, ref_path, RelaxSetGenerator) def test_relax_si_no_kgrid(tmp_path): - params = {"species_dir": str(species_dir / "light")} + params = {"species_dir": "light"} comp_system(Si, params, "relax-no-kgrid-si", tmp_path, ref_path, RelaxSetGenerator) -def test_relax_default_species_dir(tmp_path): - params = {"k_grid": [2, 2, 2]} - - comp_system(Si, params, "relax-si", tmp_path, ref_path, RelaxSetGenerator) - - def test_relax_o2(tmp_path): params = {"species_dir": str(species_dir / "light")} comp_system(O2, params, "relax-o2", tmp_path, ref_path, RelaxSetGenerator) - - -def test_relax_default_species_dir_o2(tmp_path): - params = {"k_grid": [2, 2, 2]} - - comp_system(O2, params, "relax-o2", tmp_path, ref_path, RelaxSetGenerator) diff --git a/tests/io/aims/test_sets/test_static_generator.py b/tests/io/aims/test_sets/test_static_generator.py index 4dd5c5879fa..39415758b1e 100644 --- a/tests/io/aims/test_sets/test_static_generator.py +++ b/tests/io/aims/test_sets/test_static_generator.py @@ -6,35 +6,22 @@ from pymatgen.util.testing.aims import O2, Si, comp_system module_dir = Path(__file__).resolve().parents[1] -species_dir = module_dir / "species_directory" ref_path = (module_dir / "aims_input_generator_ref").resolve() def test_static_si(tmp_path): parameters = { - "species_dir": str(species_dir / "light"), + "species_dir": "light", "k_grid": [2, 2, 2], } comp_system(Si, parameters, "static-si", tmp_path, ref_path, StaticSetGenerator) def test_static_si_no_kgrid(tmp_path): - parameters = {"species_dir": str(species_dir / "light")} + parameters = {"species_dir": "light"} comp_system(Si, parameters, "static-no-kgrid-si", tmp_path, ref_path, StaticSetGenerator) -def test_static_default_species_dir(tmp_path): - parameters = {"k_grid": [2, 2, 2]} - - comp_system(Si, parameters, "static-si", tmp_path, ref_path, StaticSetGenerator) - - def test_static_o2(tmp_path): - parameters = {"species_dir": str(species_dir / "light")} - comp_system(O2, parameters, "static-o2", tmp_path, ref_path, StaticSetGenerator) - - -def test_static_default_species_dir_o2(tmp_path): - parameters = {"k_grid": [2, 2, 2]} - + parameters = {"species_dir": "light"} comp_system(O2, parameters, "static-o2", tmp_path, ref_path, StaticSetGenerator) From 247666d37206a284cfb5271c7966b7acf59df2c9 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Thu, 20 Jun 2024 07:53:18 -0700 Subject: [PATCH 20/54] Add pdm.lock. --- pdm.lock | 1360 ++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 15 + 2 files changed, 1375 insertions(+) create mode 100644 pdm.lock diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 00000000000..05be24ec608 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,1360 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "test"] +strategy = ["cross_platform", "inherit_metadata"] +lock_version = "4.4.1" +content_hash = "sha256:2177bd2d7ed222eed37f88bcf669fcf82be6bd35d3cf2c5f9e11dfc4e4ce776f" + +[[package]] +name = "certifi" +version = "2024.6.2" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["default"] +files = [ + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +requires_python = ">=3.8" +summary = "Validate configuration and produce human readable error messages." +groups = ["test"] +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["default"] +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["default", "test"] +marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "contourpy" +version = "1.2.1" +requires_python = ">=3.9" +summary = "Python library for calculating contours of 2D quadrilateral grids" +groups = ["default"] +dependencies = [ + "numpy>=1.20", +] +files = [ + {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, + {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, + {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, + {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, + {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, + {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, + {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, + {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, + {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, + {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, + {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, +] + +[[package]] +name = "coverage" +version = "7.5.3" +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" +groups = ["test"] +files = [ + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, + {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, + {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, +] + +[[package]] +name = "coverage" +version = "7.5.3" +extras = ["toml"] +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" +groups = ["test"] +dependencies = [ + "coverage==7.5.3", + "tomli; python_full_version <= \"3.11.0a6\"", +] +files = [ + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, + {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, + {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, +] + +[[package]] +name = "cycler" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Composable style cycles" +groups = ["default"] +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[[package]] +name = "distlib" +version = "0.3.8" +summary = "Distribution utilities" +groups = ["test"] +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.1" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +groups = ["test"] +marker = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, +] + +[[package]] +name = "filelock" +version = "3.15.3" +requires_python = ">=3.8" +summary = "A platform independent file lock." +groups = ["test"] +files = [ + {file = "filelock-3.15.3-py3-none-any.whl", hash = "sha256:0151273e5b5d6cf753a61ec83b3a9b7d8821c39ae9af9d7ecf2f9e2f17404103"}, + {file = "filelock-3.15.3.tar.gz", hash = "sha256:e1199bf5194a2277273dacd50269f0d87d0682088a3c561c15674ea9005d8635"}, +] + +[[package]] +name = "fonttools" +version = "4.53.0" +requires_python = ">=3.8" +summary = "Tools to manipulate font files" +groups = ["default"] +files = [ + {file = "fonttools-4.53.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20"}, + {file = "fonttools-4.53.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d"}, + {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6"}, + {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5"}, + {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9"}, + {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca"}, + {file = "fonttools-4.53.0-cp310-cp310-win32.whl", hash = "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068"}, + {file = "fonttools-4.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68"}, + {file = "fonttools-4.53.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec"}, + {file = "fonttools-4.53.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749"}, + {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161"}, + {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee"}, + {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6"}, + {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e"}, + {file = "fonttools-4.53.0-cp311-cp311-win32.whl", hash = "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005"}, + {file = "fonttools-4.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796"}, + {file = "fonttools-4.53.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a"}, + {file = "fonttools-4.53.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4"}, + {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06"}, + {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d"}, + {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109"}, + {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2"}, + {file = "fonttools-4.53.0-cp312-cp312-win32.whl", hash = "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea"}, + {file = "fonttools-4.53.0-cp312-cp312-win_amd64.whl", hash = "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380"}, + {file = "fonttools-4.53.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac"}, + {file = "fonttools-4.53.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d"}, + {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1"}, + {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f"}, + {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64"}, + {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0"}, + {file = "fonttools-4.53.0-cp39-cp39-win32.whl", hash = "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9"}, + {file = "fonttools-4.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2"}, + {file = "fonttools-4.53.0-py3-none-any.whl", hash = "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4"}, + {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, +] + +[[package]] +name = "identify" +version = "2.5.36" +requires_python = ">=3.8" +summary = "File identification library for Python" +groups = ["test"] +files = [ + {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, +] + +[[package]] +name = "idna" +version = "3.7" +requires_python = ">=3.5" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "importlib-resources" +version = "6.4.0" +requires_python = ">=3.8" +summary = "Read resources from Python packages" +groups = ["default"] +marker = "python_version < \"3.10\"" +dependencies = [ + "zipp>=3.1.0; python_version < \"3.10\"", +] +files = [ + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +groups = ["test"] +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "joblib" +version = "1.4.2" +requires_python = ">=3.8" +summary = "Lightweight pipelining with Python functions" +groups = ["default"] +files = [ + {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, + {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, +] + +[[package]] +name = "kiwisolver" +version = "1.4.5" +requires_python = ">=3.7" +summary = "A fast implementation of the Cassowary constraint solver" +groups = ["default"] +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + +[[package]] +name = "latexcodec" +version = "3.0.0" +requires_python = ">=3.7" +summary = "A lexer and codec to work with LaTeX code in Python." +groups = ["default"] +files = [ + {file = "latexcodec-3.0.0-py3-none-any.whl", hash = "sha256:6f3477ad5e61a0a99bd31a6a370c34e88733a6bad9c921a3ffcfacada12f41a7"}, + {file = "latexcodec-3.0.0.tar.gz", hash = "sha256:917dc5fe242762cc19d963e6548b42d63a118028cdd3361d62397e3b638b6bc5"}, +] + +[[package]] +name = "matplotlib" +version = "3.9.0" +requires_python = ">=3.9" +summary = "Python plotting package" +groups = ["default"] +dependencies = [ + "contourpy>=1.0.1", + "cycler>=0.10", + "fonttools>=4.22.0", + "importlib-resources>=3.2.0; python_version < \"3.10\"", + "kiwisolver>=1.3.1", + "numpy>=1.23", + "packaging>=20.0", + "pillow>=8", + "pyparsing>=2.3.1", + "python-dateutil>=2.7", +] +files = [ + {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, + {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, + {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, + {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, + {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, + {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, + {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, + {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, + {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, + {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, + {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, +] + +[[package]] +name = "monty" +version = "2024.5.24" +requires_python = ">=3.9" +summary = "Monty is the missing complement to Python." +groups = ["default"] +files = [ + {file = "monty-2024.5.24-py3-none-any.whl", hash = "sha256:0627fe55beb84e2ded247adcb5785933b7e123852eaa7c2da16ff96d96c0819c"}, + {file = "monty-2024.5.24.tar.gz", hash = "sha256:b9fa94892f7070d50ea14ac8c5c271a71d65105832a448f495d586444f9fdefa"}, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +summary = "Python library for arbitrary-precision floating-point arithmetic" +groups = ["default"] +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[[package]] +name = "mypy" +version = "1.10.0" +requires_python = ">=3.8" +summary = "Optional static typing for Python" +groups = ["test"] +dependencies = [ + "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.1.0", +] +files = [ + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["test"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "networkx" +version = "3.2.1" +requires_python = ">=3.9" +summary = "Python package for creating and manipulating graphs and networks" +groups = ["default"] +files = [ + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Node.js virtual environment builder" +groups = ["test"] +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + +[[package]] +name = "numpy" +version = "2.0.0" +requires_python = ">=3.9" +summary = "Fundamental package for array computing in Python" +groups = ["default"] +files = [ + {file = "numpy-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:04494f6ec467ccb5369d1808570ae55f6ed9b5809d7f035059000a37b8d7e86f"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2635dbd200c2d6faf2ef9a0d04f0ecc6b13b3cad54f7c67c61155138835515d2"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:0a43f0974d501842866cc83471bdb0116ba0dffdbaac33ec05e6afed5b615238"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:8d83bb187fb647643bd56e1ae43f273c7f4dbcdf94550d7938cfc32566756514"}, + {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e843d186c8fb1b102bef3e2bc35ef81160ffef3194646a7fdd6a73c6b97196"}, + {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7696c615765091cc5093f76fd1fa069870304beaccfd58b5dcc69e55ef49c1"}, + {file = "numpy-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b4c76e3d4c56f145d41b7b6751255feefae92edbc9a61e1758a98204200f30fc"}, + {file = "numpy-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd3a644e4807e73b4e1867b769fbf1ce8c5d80e7caaef0d90dcdc640dfc9787"}, + {file = "numpy-2.0.0-cp310-cp310-win32.whl", hash = "sha256:cee6cc0584f71adefe2c908856ccc98702baf95ff80092e4ca46061538a2ba98"}, + {file = "numpy-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed08d2703b5972ec736451b818c2eb9da80d66c3e84aed1deeb0c345fefe461b"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad0c86f3455fbd0de6c31a3056eb822fc939f81b1618f10ff3406971893b62a5"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7f387600d424f91576af20518334df3d97bc76a300a755f9a8d6e4f5cadd289"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:34f003cb88b1ba38cb9a9a4a3161c1604973d7f9d5552c38bc2f04f829536609"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b6f6a8f45d0313db07d6d1d37bd0b112f887e1369758a5419c0370ba915b3871"}, + {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f64641b42b2429f56ee08b4f427a4d2daf916ec59686061de751a55aafa22e4"}, + {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7039a136017eaa92c1848152827e1424701532ca8e8967fe480fe1569dae581"}, + {file = "numpy-2.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46e161722e0f619749d1cd892167039015b2c2817296104487cd03ed4a955995"}, + {file = "numpy-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0e50842b2295ba8414c8c1d9d957083d5dfe9e16828b37de883f51fc53c4016f"}, + {file = "numpy-2.0.0-cp311-cp311-win32.whl", hash = "sha256:2ce46fd0b8a0c947ae047d222f7136fc4d55538741373107574271bc00e20e8f"}, + {file = "numpy-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd6acc766814ea6443628f4e6751d0da6593dae29c08c0b2606164db026970c"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:354f373279768fa5a584bac997de6a6c9bc535c482592d7a813bb0c09be6c76f"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d2f62e55a4cd9c58c1d9a1c9edaedcd857a73cb6fda875bf79093f9d9086f85"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:1e72728e7501a450288fc8e1f9ebc73d90cfd4671ebbd631f3e7857c39bd16f2"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:84554fc53daa8f6abf8e8a66e076aff6ece62de68523d9f665f32d2fc50fd66e"}, + {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73aafd1afca80afecb22718f8700b40ac7cab927b8abab3c3e337d70e10e5a2"}, + {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d9f7d256fbc804391a7f72d4a617302b1afac1112fac19b6c6cec63fe7fe8a"}, + {file = "numpy-2.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0ec84b9ba0654f3b962802edc91424331f423dcf5d5f926676e0150789cb3d95"}, + {file = "numpy-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:feff59f27338135776f6d4e2ec7aeeac5d5f7a08a83e80869121ef8164b74af9"}, + {file = "numpy-2.0.0-cp312-cp312-win32.whl", hash = "sha256:c5a59996dc61835133b56a32ebe4ef3740ea5bc19b3983ac60cc32be5a665d54"}, + {file = "numpy-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a356364941fb0593bb899a1076b92dfa2029f6f5b8ba88a14fd0984aaf76d0df"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e61155fae27570692ad1d327e81c6cf27d535a5d7ef97648a17d922224b216de"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4554eb96f0fd263041baf16cf0881b3f5dafae7a59b1049acb9540c4d57bc8cb"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:903703372d46bce88b6920a0cd86c3ad82dae2dbef157b5fc01b70ea1cfc430f"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:3e8e01233d57639b2e30966c63d36fcea099d17c53bf424d77f088b0f4babd86"}, + {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cde1753efe513705a0c6d28f5884e22bdc30438bf0085c5c486cdaff40cd67a"}, + {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821eedb7165ead9eebdb569986968b541f9908979c2da8a4967ecac4439bae3d"}, + {file = "numpy-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a1712c015831da583b21c5bfe15e8684137097969c6d22e8316ba66b5baabe4"}, + {file = "numpy-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9c27f0946a3536403efb0e1c28def1ae6730a72cd0d5878db38824855e3afc44"}, + {file = "numpy-2.0.0-cp39-cp39-win32.whl", hash = "sha256:63b92c512d9dbcc37f9d81b123dec99fdb318ba38c8059afc78086fe73820275"}, + {file = "numpy-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f6bed7f840d44c08ebdb73b1825282b801799e325bcbdfa6bc5c370e5aecc65"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9416a5c2e92ace094e9f0082c5fd473502c91651fb896bc17690d6fc475128d6"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:17067d097ed036636fa79f6a869ac26df7db1ba22039d962422506640314933a"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ecb5b0582cd125f67a629072fed6f83562d9dd04d7e03256c9829bdec027ad"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cef04d068f5fb0518a77857953193b6bb94809a806bd0a14983a8f12ada060c9"}, + {file = "numpy-2.0.0.tar.gz", hash = "sha256:cf5d1c9e6837f8af9f92b6bd3e86d513cdc11f60fd62185cc49ec7d1aba34864"}, +] + +[[package]] +name = "packaging" +version = "24.1" +requires_python = ">=3.8" +summary = "Core utilities for Python packages" +groups = ["default", "test"] +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "palettable" +version = "3.3.3" +requires_python = ">=3.7" +summary = "Color palettes for Python" +groups = ["default"] +files = [ + {file = "palettable-3.3.3-py2.py3-none-any.whl", hash = "sha256:74e9e7d7fe5a9be065e02397558ed1777b2df0b793a6f4ce1a5ee74f74fb0caa"}, + {file = "palettable-3.3.3.tar.gz", hash = "sha256:094dd7d9a5fc1cca4854773e5c1fc6a315b33bd5b3a8f47064928facaf0490a8"}, +] + +[[package]] +name = "pandas" +version = "2.2.2" +requires_python = ">=3.9" +summary = "Powerful data structures for data analysis, time series, and statistics" +groups = ["default"] +dependencies = [ + "numpy>=1.22.4; python_version < \"3.11\"", + "numpy>=1.23.2; python_version == \"3.11\"", + "numpy>=1.26.0; python_version >= \"3.12\"", + "python-dateutil>=2.8.2", + "pytz>=2020.1", + "tzdata>=2022.7", +] +files = [ + {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"}, + {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"}, + {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"}, + {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"}, + {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"}, + {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"}, + {file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"}, + {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"}, + {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"}, + {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"}, + {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"}, + {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"}, + {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"}, + {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"}, + {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"}, + {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"}, + {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"}, + {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"}, + {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"}, + {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, + {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, + {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"}, + {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"}, + {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"}, + {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"}, + {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"}, + {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"}, + {file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"}, + {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"}, +] + +[[package]] +name = "pillow" +version = "10.3.0" +requires_python = ">=3.8" +summary = "Python Imaging Library (Fork)" +groups = ["default"] +files = [ + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["test"] +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[[package]] +name = "plotly" +version = "5.22.0" +requires_python = ">=3.8" +summary = "An open-source, interactive data visualization library for Python" +groups = ["default"] +dependencies = [ + "packaging", + "tenacity>=6.2.0", +] +files = [ + {file = "plotly-5.22.0-py3-none-any.whl", hash = "sha256:68fc1901f098daeb233cc3dd44ec9dc31fb3ca4f4e53189344199c43496ed006"}, + {file = "plotly-5.22.0.tar.gz", hash = "sha256:859fdadbd86b5770ae2466e542b761b247d1c6b49daed765b95bb8c7063e7469"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" +groups = ["test"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[[package]] +name = "pre-commit" +version = "3.7.1" +requires_python = ">=3.9" +summary = "A framework for managing and maintaining multi-language pre-commit hooks." +groups = ["test"] +dependencies = [ + "cfgv>=2.0.0", + "identify>=1.0.0", + "nodeenv>=0.11.1", + "pyyaml>=5.1", + "virtualenv>=20.10.0", +] +files = [ + {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, + {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, +] + +[[package]] +name = "pybtex" +version = "0.24.0" +requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" +summary = "A BibTeX-compatible bibliography processor in Python" +groups = ["default"] +dependencies = [ + "PyYAML>=3.01", + "latexcodec>=1.0.4", + "six", +] +files = [ + {file = "pybtex-0.24.0-py2.py3-none-any.whl", hash = "sha256:e1e0c8c69998452fea90e9179aa2a98ab103f3eed894405b7264e517cc2fcc0f"}, + {file = "pybtex-0.24.0.tar.gz", hash = "sha256:818eae35b61733e5c007c3fcd2cfb75ed1bc8b4173c1f70b56cc4c0802d34755"}, +] + +[[package]] +name = "pyparsing" +version = "3.1.2" +requires_python = ">=3.6.8" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" +groups = ["default"] +files = [ + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, +] + +[[package]] +name = "pytest" +version = "8.2.2" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +groups = ["test"] +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=1.5", + "tomli>=1; python_version < \"3.11\"", +] +files = [ + {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, +] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +requires_python = ">=3.8" +summary = "Pytest plugin for measuring coverage." +groups = ["test"] +dependencies = [ + "coverage[toml]>=5.2.1", + "pytest>=4.6", +] +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[[package]] +name = "pytest-split" +version = "0.9.0" +requires_python = "<4.0,>=3.8.1" +summary = "Pytest plugin which splits the test suite to equally sized sub suites based on test execution time." +groups = ["test"] +dependencies = [ + "pytest<9,>=5", +] +files = [ + {file = "pytest_split-0.9.0-py3-none-any.whl", hash = "sha256:9e197df601828d76a1ab615158d9c6253ec9f96e46c1d3ea27187aa5ac0ef9de"}, + {file = "pytest_split-0.9.0.tar.gz", hash = "sha256:ca52527e4d9024f6ec3aba723527bd276d12096024999b1f5b8445a38da1e81c"}, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["default"] +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[[package]] +name = "pytz" +version = "2024.1" +summary = "World timezone definitions, modern and historical" +groups = ["default"] +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +requires_python = ">=3.6" +summary = "YAML parser and emitter for Python" +groups = ["default", "test"] +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +requires_python = ">=3.8" +summary = "Python HTTP for Humans." +groups = ["default"] +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[[package]] +name = "ruamel-yaml" +version = "0.18.6" +requires_python = ">=3.7" +summary = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +groups = ["default"] +dependencies = [ + "ruamel-yaml-clib>=0.2.7; platform_python_implementation == \"CPython\" and python_version < \"3.13\"", +] +files = [ + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +requires_python = ">=3.6" +summary = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +groups = ["default"] +marker = "platform_python_implementation == \"CPython\" and python_version < \"3.13\"" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + +[[package]] +name = "ruff" +version = "0.4.9" +requires_python = ">=3.7" +summary = "An extremely fast Python linter and code formatter, written in Rust." +groups = ["test"] +files = [ + {file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"}, + {file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"}, + {file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"}, + {file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"}, + {file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"}, + {file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"}, +] + +[[package]] +name = "scipy" +version = "1.13.1" +requires_python = ">=3.9" +summary = "Fundamental algorithms for scientific computing in Python" +groups = ["default"] +dependencies = [ + "numpy<2.3,>=1.22.4", +] +files = [ + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" +groups = ["default"] +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "spglib" +version = "2.4.0" +requires_python = ">=3.8" +summary = "This is the spglib module." +groups = ["default"] +dependencies = [ + "importlib-resources; python_version < \"3.10\"", + "numpy>=1.20", +] +files = [ + {file = "spglib-2.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2112fa02d30bea4ba288ec1a1df544b309ee0f9b8f3462be364110cb56e2c3a1"}, + {file = "spglib-2.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7713f62595b3a9b0d1a189d1f076079384a6a96749ab90533ee250427ddc51cb"}, + {file = "spglib-2.4.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:43e6a51f4fee7ef38b8597396da28c8093a8d48a6fd54bae72ebc20caa3d7f43"}, + {file = "spglib-2.4.0-cp310-cp310-manylinux_2_17_x86_64.whl", hash = "sha256:1b49cf92ba08a9c67161306cb05c612b9d87fd62f8ce719a8ea69079f43c0f4d"}, + {file = "spglib-2.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:0ba8b17cafffb3a3f475ebc45647ad1ec700cf7fae3abafd77d5c49d1c94c89b"}, + {file = "spglib-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ccba8367d8bd31ca344b989ea18f8ac0a1263f9d038012494c8eb736b8205044"}, + {file = "spglib-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce84df7a43889d13cacac8121632a4ad661b940755f50479a707d8f1f213efe8"}, + {file = "spglib-2.4.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:70ee7de6b769350f1e568324a5a6fdd34df89f95f8bfe0b21b6dc2fc56207169"}, + {file = "spglib-2.4.0-cp311-cp311-manylinux_2_17_x86_64.whl", hash = "sha256:70f341a14d3ca464a1bb1c3eb86ae5c8252ece186f7af039a01705ed4624d5c2"}, + {file = "spglib-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:f4548c3e34317ea81a94c235f07242964a36ace08e807a0a99c659b4c969e577"}, + {file = "spglib-2.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:595c5d189b82dce2a529e6653536e817871000b42e837d492862708d3c0087ee"}, + {file = "spglib-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5fe22552895f5cb065f5cdef1a3f49c3e975528eb2169e17b0b46e5158870db9"}, + {file = "spglib-2.4.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:3144974186697e547e407512abffea09c628195509981ce5da3d10dcfbc55988"}, + {file = "spglib-2.4.0-cp312-cp312-manylinux_2_17_x86_64.whl", hash = "sha256:da4a6160bdad3cd5c8dff40d8062e041703d097545caa06d23f116bc5819be27"}, + {file = "spglib-2.4.0-cp312-cp312-manylinux_2_35_x86_64.whl", hash = "sha256:463947c1d1426414d4c5bdb6e6dba6b520ef8db55534dab3959648d65f68915f"}, + {file = "spglib-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:763d7e316215976737a12319e18f830b0a1428b79c1f61a41846fe2b4d041e4f"}, + {file = "spglib-2.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:809c442db2ad9b23b3292c30bf3bea38e04dc7a179d399572d4b21ef3a8fec02"}, + {file = "spglib-2.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5564ac416e21ad7ef9cd3326912e4d2b1a22438ed60efd08e83cdebbd876e55c"}, + {file = "spglib-2.4.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:8ef0e83e9a30a456939783a01e6fcee8c4465371551ee225613d42ec292652d2"}, + {file = "spglib-2.4.0-cp39-cp39-manylinux_2_17_x86_64.whl", hash = "sha256:27648486e280ff3e69596725e4cbfe4920942c73eae193e1b9e6637661cbbada"}, + {file = "spglib-2.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:50783e71dfde8a48ceec40164feeaad932df14759ab17a3a8a02b4847cd3ca9e"}, + {file = "spglib-2.4.0.tar.gz", hash = "sha256:6e63f9ee61b70f153a22d3b550b183da531f890475917fce203bad4597aac243"}, +] + +[[package]] +name = "sympy" +version = "1.12.1" +requires_python = ">=3.8" +summary = "Computer algebra system (CAS) in Python" +groups = ["default"] +dependencies = [ + "mpmath<1.4.0,>=1.1.0", +] +files = [ + {file = "sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515"}, + {file = "sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88"}, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +requires_python = ">=3.7" +summary = "Pretty-print tabular data" +groups = ["default"] +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[[package]] +name = "tenacity" +version = "8.4.1" +requires_python = ">=3.8" +summary = "Retry code until it succeeds" +groups = ["default"] +files = [ + {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, + {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" +groups = ["test"] +marker = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tqdm" +version = "4.66.4" +requires_python = ">=3.7" +summary = "Fast, Extensible Progress Meter" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", +] +files = [ + {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, + {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["test"] +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +requires_python = ">=2" +summary = "Provider of IANA time zone data" +groups = ["default"] +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "uncertainties" +version = "3.2.1" +requires_python = ">=3.8" +summary = "calculations with values with uncertainties, error propagation" +groups = ["default"] +files = [ + {file = "uncertainties-3.2.1-py3-none-any.whl", hash = "sha256:80dea7f0c2fe37c9de6893b2352311b5f332be60060cbd6387f88050f7ec345d"}, + {file = "uncertainties-3.2.1.tar.gz", hash = "sha256:b05417b58bdef236c20e711fb2fee18e4db7348a92edcec01318b32aab34925e"}, +] + +[[package]] +name = "urllib3" +version = "2.2.2" +requires_python = ">=3.8" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["default"] +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + +[[package]] +name = "virtualenv" +version = "20.26.2" +requires_python = ">=3.7" +summary = "Virtual Python Environment builder" +groups = ["test"] +dependencies = [ + "distlib<1,>=0.3.7", + "filelock<4,>=3.12.2", + "platformdirs<5,>=3.9.1", +] +files = [ + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, +] + +[[package]] +name = "zipp" +version = "3.19.2" +requires_python = ">=3.8" +summary = "Backport of pathlib-compatible object wrapper for zip files" +groups = ["default"] +marker = "python_version < \"3.10\"" +files = [ + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, +] diff --git a/pyproject.toml b/pyproject.toml index 0cc1e59cf37..6a4936952c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -161,6 +161,21 @@ include = ["pymatgen.*"] "pymatgen.io.lammps" = ["CoeffsDataType.yaml", "templates/*.template"] "pymatgen.symmetry" = ["*.yaml", "*.json", "*.sqlite"] + + + + +[tool.pdm.dev-dependencies] +lint = [ + "mypy>=1.10.0", + "ruff>=0.4.9", + "pre-commit>=3.7.1", +] +test = [ + "pytest>=8.2.2", + "pytest-cov>=5.0.0", + "pytest-split>=0.9.0", +] [project.scripts] pmg = "pymatgen.cli.pmg:main" feff_plot_cross_section = "pymatgen.cli.feff_plot_cross_section:main" From 59f357dc7048e7b0d720c1d1d204ea914c9873a8 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Thu, 20 Jun 2024 08:02:52 -0700 Subject: [PATCH 21/54] Updated pdm.lock --- .gitignore | 1 + pdm.lock | 187 +------------------------------------------------ pyproject.toml | 4 -- 3 files changed, 3 insertions(+), 189 deletions(-) diff --git a/.gitignore b/.gitignore index 21e0621b8fb..2ac37aea6df 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ venv/ ENV/ env.bak/ venv.bak/ +.pdm-python diff --git a/pdm.lock b/pdm.lock index 05be24ec608..67992d17e4c 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "test"] strategy = ["cross_platform", "inherit_metadata"] lock_version = "4.4.1" -content_hash = "sha256:2177bd2d7ed222eed37f88bcf669fcf82be6bd35d3cf2c5f9e11dfc4e4ce776f" +content_hash = "sha256:5c459bad2140359cc50e14a830374e93763f3e1aaac83f843db335a613c7195d" [[package]] name = "certifi" @@ -18,17 +18,6 @@ files = [ {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] -[[package]] -name = "cfgv" -version = "3.4.0" -requires_python = ">=3.8" -summary = "Validate configuration and produce human readable error messages." -groups = ["test"] -files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, -] - [[package]] name = "charset-normalizer" version = "3.3.2" @@ -286,16 +275,6 @@ files = [ {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, ] -[[package]] -name = "distlib" -version = "0.3.8" -summary = "Distribution utilities" -groups = ["test"] -files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, -] - [[package]] name = "exceptiongroup" version = "1.2.1" @@ -308,17 +287,6 @@ files = [ {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] -[[package]] -name = "filelock" -version = "3.15.3" -requires_python = ">=3.8" -summary = "A platform independent file lock." -groups = ["test"] -files = [ - {file = "filelock-3.15.3-py3-none-any.whl", hash = "sha256:0151273e5b5d6cf753a61ec83b3a9b7d8821c39ae9af9d7ecf2f9e2f17404103"}, - {file = "filelock-3.15.3.tar.gz", hash = "sha256:e1199bf5194a2277273dacd50269f0d87d0682088a3c561c15674ea9005d8635"}, -] - [[package]] name = "fonttools" version = "4.53.0" @@ -362,17 +330,6 @@ files = [ {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, ] -[[package]] -name = "identify" -version = "2.5.36" -requires_python = ">=3.8" -summary = "File identification library for Python" -groups = ["test"] -files = [ - {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, - {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, -] - [[package]] name = "idna" version = "3.7" @@ -588,53 +545,6 @@ files = [ {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, ] -[[package]] -name = "mypy" -version = "1.10.0" -requires_python = ">=3.8" -summary = "Optional static typing for Python" -groups = ["test"] -dependencies = [ - "mypy-extensions>=1.0.0", - "tomli>=1.1.0; python_version < \"3.11\"", - "typing-extensions>=4.1.0", -] -files = [ - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -requires_python = ">=3.5" -summary = "Type system extensions for programs checked with the mypy type checker." -groups = ["test"] -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - [[package]] name = "networkx" version = "3.2.1" @@ -646,17 +556,6 @@ files = [ {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, ] -[[package]] -name = "nodeenv" -version = "1.9.1" -requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -summary = "Node.js virtual environment builder" -groups = ["test"] -files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, -] - [[package]] name = "numpy" version = "2.0.0" @@ -847,17 +746,6 @@ files = [ {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] -[[package]] -name = "platformdirs" -version = "4.2.2" -requires_python = ">=3.8" -summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -groups = ["test"] -files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, -] - [[package]] name = "plotly" version = "5.22.0" @@ -884,24 +772,6 @@ files = [ {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] -[[package]] -name = "pre-commit" -version = "3.7.1" -requires_python = ">=3.9" -summary = "A framework for managing and maintaining multi-language pre-commit hooks." -groups = ["test"] -dependencies = [ - "cfgv>=2.0.0", - "identify>=1.0.0", - "nodeenv>=0.11.1", - "pyyaml>=5.1", - "virtualenv>=20.10.0", -] -files = [ - {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, - {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, -] - [[package]] name = "pybtex" version = "0.24.0" @@ -1006,7 +876,7 @@ name = "pyyaml" version = "6.0.1" requires_python = ">=3.6" summary = "YAML parser and emitter for Python" -groups = ["default", "test"] +groups = ["default"] files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, @@ -1116,32 +986,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, ] -[[package]] -name = "ruff" -version = "0.4.9" -requires_python = ">=3.7" -summary = "An extremely fast Python linter and code formatter, written in Rust." -groups = ["test"] -files = [ - {file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"}, - {file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"}, - {file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"}, - {file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"}, - {file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"}, - {file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"}, -] - [[package]] name = "scipy" version = "1.13.1" @@ -1287,17 +1131,6 @@ files = [ {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, ] -[[package]] -name = "typing-extensions" -version = "4.12.2" -requires_python = ">=3.8" -summary = "Backported and Experimental Type Hints for Python 3.8+" -groups = ["test"] -files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, -] - [[package]] name = "tzdata" version = "2024.1" @@ -1331,22 +1164,6 @@ files = [ {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] -[[package]] -name = "virtualenv" -version = "20.26.2" -requires_python = ">=3.7" -summary = "Virtual Python Environment builder" -groups = ["test"] -dependencies = [ - "distlib<1,>=0.3.7", - "filelock<4,>=3.12.2", - "platformdirs<5,>=3.9.1", -] -files = [ - {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, - {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, -] - [[package]] name = "zipp" version = "3.19.2" diff --git a/pyproject.toml b/pyproject.toml index 6a4936952c8..b0665d8c3e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -161,10 +161,6 @@ include = ["pymatgen.*"] "pymatgen.io.lammps" = ["CoeffsDataType.yaml", "templates/*.template"] "pymatgen.symmetry" = ["*.yaml", "*.json", "*.sqlite"] - - - - [tool.pdm.dev-dependencies] lint = [ "mypy>=1.10.0", From 7a8feda0ff4af3a18d934dbb71546231b3415be4 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Thu, 20 Jun 2024 14:07:24 -0700 Subject: [PATCH 22/54] Remove defunct req.txt files. --- requirements-optional.txt | 15 --------------- requirements.txt | 18 ------------------ 2 files changed, 33 deletions(-) delete mode 100644 requirements-optional.txt delete mode 100644 requirements.txt diff --git a/requirements-optional.txt b/requirements-optional.txt deleted file mode 100644 index 96ecc8da1af..00000000000 --- a/requirements-optional.txt +++ /dev/null @@ -1,15 +0,0 @@ -ase>=3.23.0 -beautifulsoup4==4.12.2 -BoltzTraP2>=22.3.2 -chemview>=0.6 -f90nml>=1.4.3 -fdint>=2.0.2 -galore>=0.7.0 -h5py==3.11.0 -# hiphive>=0.6 -icet>=2.2 -jarvis-tools>=2022.9.16 -matgl==1.1.2 -netCDF4>=1.5.8 -phonopy==2.23.1 -seekpath>=2.0.1 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index ef6df118680..00000000000 --- a/requirements.txt +++ /dev/null @@ -1,18 +0,0 @@ -numpy==1.26.4 -sympy==1.12 -requests==2.32.3 -monty==2024.5.24 -ruamel.yaml==0.18.6 -scipy==1.13.1 -tabulate==0.9.0 -matplotlib==3.9.0 -palettable==3.3.3 -spglib==2.1.0 -pandas==2.1.1 -networkx==3.3 -plotly==5.17.0 -uncertainties==3.1.7 -Cython==3.0.10 -pybtex==0.24.0 -tqdm==4.66.4 -joblib==1.3.2 From 61a65e540d610b26f8d234949f048f643b70a53d Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Thu, 20 Jun 2024 14:12:37 -0700 Subject: [PATCH 23/54] Remvoe dev from project.dependencies. --- pyproject.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b0665d8c3e0..ff1dd48ffd1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,14 +93,6 @@ vis = ["vtk>=6.0.0"] abinit = ["netcdf4>=1.6.5"] mlp = ["matgl>=1.1.1", "chgnet>=0.3.8"] electronic_structure = ["fdint>=2.0.2"] -dev = [ - "mypy>=1.10.0", - "pre-commit>=3", - "pytest-cov>=4", - "pytest-split>=0.8", - "pytest>8", - "ruff>=0.4.8", -] ci = [ "pytest>=8", "pytest-cov>=4", From 15926b0ada13f58145f5d8928aede06ff4066807 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Thu, 20 Jun 2024 14:31:32 -0700 Subject: [PATCH 24/54] Minor reorganization of pyproject.toml. --- pyproject.toml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ff1dd48ffd1..0fbc3fe9d70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,6 +125,12 @@ optional = [ ] numba = ["numba>=0.55"] +[project.scripts] +pmg = "pymatgen.cli.pmg:main" +feff_plot_cross_section = "pymatgen.cli.feff_plot_cross_section:main" +feff_plot_dos = "pymatgen.cli.feff_plot_dos:main" +get_environment = "pymatgen.cli.get_environment:main" + [tool.setuptools.packages.find] where = ["."] include = ["pymatgen.*"] @@ -164,11 +170,6 @@ test = [ "pytest-cov>=5.0.0", "pytest-split>=0.9.0", ] -[project.scripts] -pmg = "pymatgen.cli.pmg:main" -feff_plot_cross_section = "pymatgen.cli.feff_plot_cross_section:main" -feff_plot_dos = "pymatgen.cli.feff_plot_dos:main" -get_environment = "pymatgen.cli.get_environment:main" [tool.versioningit.vcs] method = "git" From 24f7ae09125b115fdf13cb643ba5c3023c08e0d7 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Thu, 20 Jun 2024 14:45:08 -0700 Subject: [PATCH 25/54] Update pdm.lock. --- pdm.lock | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 4 deletions(-) diff --git a/pdm.lock b/pdm.lock index 67992d17e4c..56fc38e8adb 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,10 +2,10 @@ # It is not intended for manual editing. [metadata] -groups = ["default", "test"] +groups = ["default", "lint", "test"] strategy = ["cross_platform", "inherit_metadata"] lock_version = "4.4.1" -content_hash = "sha256:5c459bad2140359cc50e14a830374e93763f3e1aaac83f843db335a613c7195d" +content_hash = "sha256:a104ee3d7de5e6dc9fc1dce3e03b5240ef3c5fd76ce700cd67a3ea51614b429a" [[package]] name = "certifi" @@ -18,6 +18,17 @@ files = [ {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] +[[package]] +name = "cfgv" +version = "3.4.0" +requires_python = ">=3.8" +summary = "Validate configuration and produce human readable error messages." +groups = ["lint"] +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + [[package]] name = "charset-normalizer" version = "3.3.2" @@ -275,6 +286,16 @@ files = [ {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, ] +[[package]] +name = "distlib" +version = "0.3.8" +summary = "Distribution utilities" +groups = ["lint"] +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -287,6 +308,17 @@ files = [ {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] +[[package]] +name = "filelock" +version = "3.15.3" +requires_python = ">=3.8" +summary = "A platform independent file lock." +groups = ["lint"] +files = [ + {file = "filelock-3.15.3-py3-none-any.whl", hash = "sha256:0151273e5b5d6cf753a61ec83b3a9b7d8821c39ae9af9d7ecf2f9e2f17404103"}, + {file = "filelock-3.15.3.tar.gz", hash = "sha256:e1199bf5194a2277273dacd50269f0d87d0682088a3c561c15674ea9005d8635"}, +] + [[package]] name = "fonttools" version = "4.53.0" @@ -330,6 +362,17 @@ files = [ {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, ] +[[package]] +name = "identify" +version = "2.5.36" +requires_python = ">=3.8" +summary = "File identification library for Python" +groups = ["lint"] +files = [ + {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, +] + [[package]] name = "idna" version = "3.7" @@ -545,6 +588,53 @@ files = [ {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, ] +[[package]] +name = "mypy" +version = "1.10.0" +requires_python = ">=3.8" +summary = "Optional static typing for Python" +groups = ["lint"] +dependencies = [ + "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.1.0", +] +files = [ + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["lint"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "networkx" version = "3.2.1" @@ -556,6 +646,17 @@ files = [ {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, ] +[[package]] +name = "nodeenv" +version = "1.9.1" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Node.js virtual environment builder" +groups = ["lint"] +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + [[package]] name = "numpy" version = "2.0.0" @@ -746,6 +847,17 @@ files = [ {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] +[[package]] +name = "platformdirs" +version = "4.2.2" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["lint"] +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + [[package]] name = "plotly" version = "5.22.0" @@ -772,6 +884,24 @@ files = [ {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] +[[package]] +name = "pre-commit" +version = "3.7.1" +requires_python = ">=3.9" +summary = "A framework for managing and maintaining multi-language pre-commit hooks." +groups = ["lint"] +dependencies = [ + "cfgv>=2.0.0", + "identify>=1.0.0", + "nodeenv>=0.11.1", + "pyyaml>=5.1", + "virtualenv>=20.10.0", +] +files = [ + {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, + {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, +] + [[package]] name = "pybtex" version = "0.24.0" @@ -876,7 +1006,7 @@ name = "pyyaml" version = "6.0.1" requires_python = ">=3.6" summary = "YAML parser and emitter for Python" -groups = ["default"] +groups = ["default", "lint"] files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, @@ -986,6 +1116,32 @@ files = [ {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, ] +[[package]] +name = "ruff" +version = "0.4.10" +requires_python = ">=3.7" +summary = "An extremely fast Python linter and code formatter, written in Rust." +groups = ["lint"] +files = [ + {file = "ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac"}, + {file = "ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695"}, + {file = "ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca"}, + {file = "ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7"}, + {file = "ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0"}, + {file = "ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804"}, +] + [[package]] name = "scipy" version = "1.13.1" @@ -1110,7 +1266,7 @@ name = "tomli" version = "2.0.1" requires_python = ">=3.7" summary = "A lil' TOML parser" -groups = ["test"] +groups = ["lint", "test"] marker = "python_version < \"3.11\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, @@ -1131,6 +1287,17 @@ files = [ {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, ] +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["lint"] +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + [[package]] name = "tzdata" version = "2024.1" @@ -1164,6 +1331,22 @@ files = [ {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] +[[package]] +name = "virtualenv" +version = "20.26.2" +requires_python = ">=3.7" +summary = "Virtual Python Environment builder" +groups = ["lint"] +dependencies = [ + "distlib<1,>=0.3.7", + "filelock<4,>=3.12.2", + "platformdirs<5,>=3.9.1", +] +files = [ + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, +] + [[package]] name = "zipp" version = "3.19.2" From cb177f4f56700d2bbbc8b3f5ce88a6769eccf55e Mon Sep 17 00:00:00 2001 From: "Haoyu (Daniel)" Date: Fri, 21 Jun 2024 23:11:33 +0800 Subject: [PATCH 26/54] Enable more ruff rules including `A`, `DTZ`, `PGH` and more (#3871) * enable ruff rule `PGH` * revert change in lobster.inputs test * fix some PathLike-related issues * more PGH003 fixes * more PGH003 fixes * fix unit test * more fixes for analysis module * finish all PGH * add more ruff rules * fix some `DTZ` datetime errors * fix `A001` * fix `TRY004` * fix more `TRY` errors * tweak format * tweak rule selections * tweak pyproject.toml * disable NPY rule for this PR * revert datetime utc replacement for now * pre-commit auto-fixes * reapply DTZ005 fixes * fix DTZ007 * fix PLR0124: compare with itself * fix unit test * suppress or fix `A002` * fix errors that don't show locally * replace `match.group(x)` with `match[x]` * correct err code * more group(x) changes * relocate no planned ruff families * reverse rule selection * enable rule family `D` for `pymatgen/viz` * restore assert x == x in __eq__ tests and ignore ruff PLR0124 in test files * cif -> CIF in doc str * snake_case var names * revert deletion of test for __eq__ * replace `[0:x]` slicing with `[:x]` * replace one more [0:x] slicing * replace multi-line `dict()` with `{}` * split xcfunc tests --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Janosh Riebesell --- .../get_plane_permutations_optimized.py | 6 +- dev_scripts/update_pt_data.py | 22 +- docs/apidoc/conf.py | 4 +- pymatgen/alchemy/filters.py | 2 +- pymatgen/alchemy/materials.py | 8 +- pymatgen/alchemy/transmuters.py | 16 +- .../connectivity/connected_components.py | 6 +- .../chemenv_strategies.py | 126 +++++------ .../coordination_geometries.py | 4 +- .../coordination_geometry_finder.py | 12 +- .../analysis/chemenv/utils/chemenv_config.py | 8 +- pymatgen/analysis/chemenv/utils/func_utils.py | 38 ++-- .../analysis/chemenv/utils/scripts_utils.py | 13 +- pymatgen/analysis/chempot_diagram.py | 6 +- pymatgen/analysis/diffraction/neutron.py | 20 +- pymatgen/analysis/diffraction/tem.py | 6 +- pymatgen/analysis/diffraction/xrd.py | 22 +- pymatgen/analysis/disorder.py | 8 +- pymatgen/analysis/elasticity/elastic.py | 14 +- pymatgen/analysis/eos.py | 18 +- pymatgen/analysis/functional_groups.py | 2 +- pymatgen/analysis/graphs.py | 4 +- pymatgen/analysis/interface_reactions.py | 15 +- pymatgen/analysis/local_env.py | 43 ++-- pymatgen/analysis/magnetism/analyzer.py | 4 +- pymatgen/analysis/magnetism/jahnteller.py | 2 +- .../analysis/molecule_structure_comparator.py | 196 +++++++++--------- pymatgen/analysis/nmr.py | 2 +- pymatgen/analysis/phase_diagram.py | 2 +- pymatgen/analysis/piezo_sensitivity.py | 2 +- pymatgen/analysis/reaction_calculator.py | 4 +- pymatgen/analysis/structure_matcher.py | 2 +- pymatgen/analysis/surface_analysis.py | 4 +- pymatgen/cli/pmg_analyze.py | 6 +- pymatgen/cli/pmg_config.py | 20 +- pymatgen/command_line/bader_caller.py | 8 - pymatgen/command_line/critic2_caller.py | 2 +- pymatgen/command_line/enumlib_caller.py | 8 +- pymatgen/command_line/mcsqs_caller.py | 8 +- pymatgen/core/bonds.py | 2 +- pymatgen/core/composition.py | 28 +-- pymatgen/core/interface.py | 2 +- pymatgen/core/lattice.py | 16 +- pymatgen/core/operations.py | 4 +- pymatgen/core/periodic_table.py | 26 +-- pymatgen/core/structure.py | 4 +- pymatgen/core/tensors.py | 4 +- pymatgen/electronic_structure/boltztrap.py | 17 +- pymatgen/electronic_structure/cohp.py | 4 +- pymatgen/electronic_structure/dos.py | 35 ++-- pymatgen/electronic_structure/plotter.py | 29 +-- pymatgen/entries/compatibility.py | 6 +- pymatgen/entries/correction_calculator.py | 2 +- pymatgen/entries/entry_tools.py | 10 +- pymatgen/ext/cod.py | 2 +- pymatgen/ext/matproj.py | 2 +- pymatgen/ext/matproj_legacy.py | 6 +- pymatgen/ext/optimade.py | 8 +- pymatgen/io/abinit/abiobjects.py | 120 +++++------ pymatgen/io/abinit/abitimer.py | 7 +- pymatgen/io/abinit/inputs.py | 2 +- pymatgen/io/abinit/netcdf.py | 6 +- pymatgen/io/abinit/pseudos.py | 68 +++--- pymatgen/io/adf.py | 44 ++-- pymatgen/io/aims/parsers.py | 2 +- pymatgen/io/aims/sets/base.py | 25 ++- pymatgen/io/aims/sets/bs.py | 2 +- pymatgen/io/babel.py | 2 +- pymatgen/io/cif.py | 28 +-- pymatgen/io/core.py | 49 +++-- pymatgen/io/cp2k/utils.py | 2 +- pymatgen/io/cssr.py | 4 +- pymatgen/io/feff/inputs.py | 2 +- pymatgen/io/gaussian.py | 60 +++--- pymatgen/io/lammps/data.py | 14 +- pymatgen/io/lammps/inputs.py | 8 +- pymatgen/io/lammps/sets.py | 14 +- pymatgen/io/lammps/utils.py | 8 +- pymatgen/io/lmto.py | 2 +- pymatgen/io/lobster/outputs.py | 126 ++++++----- pymatgen/io/nwchem.py | 22 +- pymatgen/io/openff.py | 8 +- pymatgen/io/packmol.py | 24 ++- pymatgen/io/pwscf.py | 24 +-- pymatgen/io/qchem/inputs.py | 26 +-- pymatgen/io/qchem/outputs.py | 2 +- pymatgen/io/qchem/sets.py | 52 ++--- pymatgen/io/res.py | 2 +- pymatgen/io/shengbte.py | 2 +- pymatgen/io/template.py | 19 +- pymatgen/io/vasp/inputs.py | 4 +- pymatgen/io/vasp/optics.py | 4 +- pymatgen/io/vasp/outputs.py | 20 +- pymatgen/io/vasp/sets.py | 30 +-- pymatgen/io/xr.py | 6 +- pymatgen/io/xyz.py | 4 +- pymatgen/io/zeopp.py | 14 +- pymatgen/phonon/gruneisen.py | 2 +- pymatgen/phonon/plotter.py | 8 +- pymatgen/phonon/thermal_displacements.py | 42 ++-- pymatgen/symmetry/groups.py | 6 +- pymatgen/symmetry/kpath.py | 6 +- .../advanced_transformations.py | 54 +++-- .../transformations/site_transformations.py | 2 +- .../standard_transformations.py | 8 +- pymatgen/util/due.py | 2 +- pymatgen/util/provenance.py | 2 +- pymatgen/util/string.py | 14 +- pymatgen/vis/plotters.py | 8 +- pymatgen/vis/structure_vtk.py | 31 +-- pyproject.toml | 100 +++++---- tasks.py | 22 +- tests/analysis/test_interface_reactions.py | 4 +- tests/core/test_composition.py | 2 +- tests/core/test_tensors.py | 2 +- tests/core/test_xcfunc.py | 29 ++- tests/io/aims/test_aims_inputs.py | 10 +- tests/io/lobster/test_inputs.py | 4 +- tests/io/test_cif.py | 2 +- tests/io/vasp/test_sets.py | 5 +- tests/symmetry/test_analyzer.py | 77 ++++--- tests/util/test_provenance.py | 14 +- 122 files changed, 1117 insertions(+), 1097 deletions(-) diff --git a/dev_scripts/chemenv/get_plane_permutations_optimized.py b/dev_scripts/chemenv/get_plane_permutations_optimized.py index ef92a27e63e..1244d13e487 100644 --- a/dev_scripts/chemenv/get_plane_permutations_optimized.py +++ b/dev_scripts/chemenv/get_plane_permutations_optimized.py @@ -236,7 +236,7 @@ def random_permutations_iterator(initial_permutation, n_permutations): sym_measures = [c["symmetry_measure"] for c in csms] prt1(string="Continuous symmetry measures", printing_volume=printing_volume) prt1(string=sym_measures, printing_volume=printing_volume) - csms_with_recorded_permutation = [] # type: ignore + csms_with_recorded_permutation: list = [] explicit_permutations = [] for icsm, csm in enumerate(csms): found = False @@ -308,7 +308,6 @@ def random_permutations_iterator(initial_permutation, n_permutations): all_planes_point_indices += algo.other_plane_points # Setup of the permutations to be used for this algorithm - indices = list(range(cg.coordination_number)) if permutations_setup_type == "all": perms_iterator = itertools.permutations(indices) @@ -400,7 +399,8 @@ def random_permutations_iterator(initial_permutation, n_permutations): else: perms_used[some_perm] = 1 tcurrent = time.process_time() - time_left = (n_permutations - idx_perm) * (tcurrent - t0) / idx_perm # type: ignore + assert n_permutations is not None + time_left = (n_permutations - idx_perm) * (tcurrent - t0) / idx_perm time_left = f"{time_left:.1f}" idx_perm += 1 print( diff --git a/dev_scripts/update_pt_data.py b/dev_scripts/update_pt_data.py index 09dcad5dd44..88f321ed712 100644 --- a/dev_scripts/update_pt_data.py +++ b/dev_scripts/update_pt_data.py @@ -30,8 +30,8 @@ def parse_oxi_state(): oxi_data = re.sub("[\n\r]", "", oxi_data) patt = re.compile("(.*?)", re.MULTILINE) - for m in patt.finditer(oxi_data): - line = m.group(1) + for match in patt.finditer(oxi_data): + line = match[1] line = re.sub("", "", line) line = re.sub("()+", "", line) line = re.sub("]*>", "", line) @@ -39,15 +39,15 @@ def parse_oxi_state(): oxi_states = [] common_oxi = [] for tok in re.split("", line.strip()): - m2 = re.match(r"([A-Z][a-z]*)", tok) - if m2: - el = m2.group(1) + match2 = re.match(r"([A-Z][a-z]*)", tok) + if match2: + el = match2[1] else: - m3 = re.match(r"()*([\+\-]\d)()*", tok) - if m3: - oxi_states += [int(m3.group(2))] - if m3.group(1): - common_oxi += [int(m3.group(2))] + match3 = re.match(r"()*([\+\-]\d)()*", tok) + if match3: + oxi_states += [int(match3[2])] + if match3[1]: + common_oxi += [int(match3[2])] if el in data: del data[el]["Max oxidation state"] del data[el]["Min oxidation state"] @@ -79,7 +79,7 @@ def parse_ionic_radii(): ionic_radii = {} for tok_idx in range(3, len(tokens)): if match := re.match(r"^\s*([0-9\.]+)", tokens[tok_idx]): - ionic_radii[int(header[tok_idx])] = float(match.group(1)) + ionic_radii[int(header[tok_idx])] = float(match[1]) if el in data: data[el][f"Ionic_radii{suffix}"] = ionic_radii diff --git a/docs/apidoc/conf.py b/docs/apidoc/conf.py index 9e5eb5577f1..fe33a4e80b8 100644 --- a/docs/apidoc/conf.py +++ b/docs/apidoc/conf.py @@ -19,7 +19,7 @@ from pymatgen.core import __author__, __file__, __version__ project = "pymatgen" -copyright = "2011, Materials Project" +copyright = "2011, Materials Project" # noqa: A001 author = __author__ @@ -64,7 +64,7 @@ # General information about the project. project = "pymatgen" -copyright = f"2011, {__author__}" +copyright = f"2011, {__author__}" # noqa: A001 # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/pymatgen/alchemy/filters.py b/pymatgen/alchemy/filters.py index 97dedf80919..d133c0289e3 100644 --- a/pymatgen/alchemy/filters.py +++ b/pymatgen/alchemy/filters.py @@ -179,7 +179,7 @@ def __init__(self, structure_matcher: dict | StructureMatcher | None = None, sym self.symprec = symprec self.structure_list: dict[str, list[Structure]] = defaultdict(list) if not isinstance(structure_matcher, (dict, StructureMatcher, type(None))): - raise ValueError(f"{structure_matcher=} must be a dict, StructureMatcher or None") + raise TypeError(f"{structure_matcher=} must be a dict, StructureMatcher or None") if isinstance(structure_matcher, dict): self.structure_matcher = StructureMatcher.from_dict(structure_matcher) else: diff --git a/pymatgen/alchemy/materials.py b/pymatgen/alchemy/materials.py index de3338e183f..2fa8b754721 100644 --- a/pymatgen/alchemy/materials.py +++ b/pymatgen/alchemy/materials.py @@ -270,10 +270,10 @@ def from_cif_str( primitive: bool = True, occupancy_tolerance: float = 1.0, ) -> Self: - """Generate TransformedStructure from a cif string. + """Generate TransformedStructure from a CIF string. Args: - cif_string (str): Input cif string. Should contain only one + cif_string (str): Input CIF string. Should contain only one structure. For CIFs containing multiple structures, please use CifTransmuter. transformations (list[Transformation]): Sequence of transformations @@ -302,7 +302,7 @@ def from_cif_str( source = "uploaded cif" source_info = { "source": source, - "datetime": str(datetime.datetime.now()), + "datetime": str(datetime.datetime.now(tz=datetime.timezone.utc)), "original_file": raw_str, "cif_data": cif_dict[cif_keys[0]], } @@ -330,7 +330,7 @@ def from_poscar_str( struct = poscar.structure source_info = { "source": "POSCAR", - "datetime": str(datetime.datetime.now()), + "datetime": str(datetime.datetime.now(tz=datetime.timezone.utc)), "original_file": raw_str, } return cls(struct, transformations, history=[source_info]) diff --git a/pymatgen/alchemy/transmuters.py b/pymatgen/alchemy/transmuters.py index 545876d53e1..802716520fc 100644 --- a/pymatgen/alchemy/transmuters.py +++ b/pymatgen/alchemy/transmuters.py @@ -121,10 +121,10 @@ def append_transformation(self, transformation, extend_collection=False, clear_r describes whether the transformation altered the structure """ if self.ncores and transformation.use_multiprocessing: - with Pool(self.ncores) as p: + with Pool(self.ncores) as pool: # need to condense arguments into single tuple to use map z = ((ts, transformation, extend_collection, clear_redo) for ts in self.transformed_structures) - trafo_new_structs = p.map(_apply_transformation, z, 1) + trafo_new_structs = pool.map(_apply_transformation, z, 1) self.transformed_structures = [] for ts in trafo_new_structs: self.transformed_structures.extend(ts) @@ -223,19 +223,17 @@ def from_structures(cls, structures, transformations=None, extend_collection=0) class CifTransmuter(StandardTransmuter): - """Generate a Transmuter from a cif string, possibly containing multiple - structures. - """ + """Generate a Transmuter from a CIF string, possibly containing multiple structures.""" def __init__(self, cif_string, transformations=None, primitive=True, extend_collection=False): - """Generate a Transmuter from a cif string, possibly + """Generate a Transmuter from a CIF string, possibly containing multiple structures. Args: - cif_string: A string containing a cif or a series of CIFs + cif_string: A string containing a CIF or a series of CIFs transformations: New transformations to be applied to all structures - primitive: Whether to generate the primitive cell from the cif. + primitive: Whether to generate the primitive cell from the CIF. extend_collection: Whether to use more than one output structure from one-to-many transformations. extend_collection can be a number, which determines the maximum branching for each @@ -262,7 +260,7 @@ def from_filenames(cls, filenames, transformations=None, primitive=True, extend_ containing multiple structures. Args: - filenames: List of strings of the cif files + filenames: List of strings of the CIF files transformations: New transformations to be applied to all structures primitive: Same meaning as in __init__. diff --git a/pymatgen/analysis/chemenv/connectivity/connected_components.py b/pymatgen/analysis/chemenv/connectivity/connected_components.py index d05fd6cfc29..311f9973b8c 100644 --- a/pymatgen/analysis/chemenv/connectivity/connected_components.py +++ b/pymatgen/analysis/chemenv/connectivity/connected_components.py @@ -483,7 +483,7 @@ def compute_periodicity_cycle_basis(self) -> None: for current_delta in this_cycle_deltas: this_cycle_deltas_new.append(current_delta + delta) this_cycle_deltas = this_cycle_deltas_new - all_deltas.extend(this_cycle_deltas) # type: ignore + all_deltas.extend(this_cycle_deltas) all_deltas = get_linearly_independent_vectors(all_deltas) if len(all_deltas) == 3: return @@ -501,7 +501,7 @@ def compute_periodicity_cycle_basis(self) -> None: current_delta = get_delta(n1, n2, e1data) delta = get_delta(n2, n1, e2data) current_delta += delta - all_deltas.append(current_delta) # type: ignore + all_deltas.append(current_delta) else: raise ValueError("Should not be here ...") all_deltas = get_linearly_independent_vectors(all_deltas) @@ -770,7 +770,7 @@ def _edgedictkey_to_edgekey(key): except ValueError: return key else: - raise ValueError("Edge key in a dict of dicts representation of a graph should be either a str or an int.") + raise TypeError("Edge key in a dict of dicts representation of a graph should be either a str or an int.") @staticmethod def _retuplify_edgedata(edata): diff --git a/pymatgen/analysis/chemenv/coordination_environments/chemenv_strategies.py b/pymatgen/analysis/chemenv/coordination_environments/chemenv_strategies.py index 55438d3c56c..862070ca35f 100644 --- a/pymatgen/analysis/chemenv/coordination_environments/chemenv_strategies.py +++ b/pymatgen/analysis/chemenv/coordination_environments/chemenv_strategies.py @@ -236,7 +236,7 @@ def set_structure_environments(self, structure_environments): """ self.structure_environments = structure_environments if not isinstance(self.structure_environments.voronoi, DetailedVoronoiContainer): - raise ValueError('Voronoi Container not of type "DetailedVoronoiContainer"') + raise TypeError('Voronoi Container not of type "DetailedVoronoiContainer"') self.prepare_symmetries() def prepare_symmetries(self): @@ -512,28 +512,28 @@ class SimplestChemenvStrategy(AbstractChemenvStrategy): DEFAULT_ANGLE_CUTOFF = 0.3 DEFAULT_CONTINUOUS_SYMMETRY_MEASURE_CUTOFF = 10 DEFAULT_ADDITIONAL_CONDITION = AbstractChemenvStrategy.AC.ONLY_ACB - STRATEGY_OPTIONS: ClassVar[dict[str, dict]] = dict( # type: ignore - distance_cutoff=dict( - type=DistanceCutoffFloat, - internal="_distance_cutoff", - default=DEFAULT_DISTANCE_CUTOFF, - ), - angle_cutoff=dict( - type=AngleCutoffFloat, - internal="_angle_cutoff", - default=DEFAULT_ANGLE_CUTOFF, - ), - additional_condition=dict( - type=AdditionalConditionInt, - internal="_additional_condition", - default=DEFAULT_ADDITIONAL_CONDITION, - ), - continuous_symmetry_measure_cutoff=dict( - type=CSMFloat, - internal="_continuous_symmetry_measure_cutoff", - default=DEFAULT_CONTINUOUS_SYMMETRY_MEASURE_CUTOFF, - ), - ) + STRATEGY_OPTIONS: ClassVar[dict[str, dict]] = { + "distance_cutoff": { + "type": DistanceCutoffFloat, + "internal": "_distance_cutoff", + "default": DEFAULT_DISTANCE_CUTOFF, + }, + "angle_cutoff": { + "type": AngleCutoffFloat, + "internal": "_angle_cutoff", + "default": DEFAULT_ANGLE_CUTOFF, + }, + "additional_condition": { + "type": AdditionalConditionInt, + "internal": "_additional_condition", + "default": DEFAULT_ADDITIONAL_CONDITION, + }, + "continuous_symmetry_measure_cutoff": { + "type": CSMFloat, + "internal": "_continuous_symmetry_measure_cutoff", + "default": DEFAULT_CONTINUOUS_SYMMETRY_MEASURE_CUTOFF, + }, + } STRATEGY_DESCRIPTION = ( "Simplest ChemenvStrategy using fixed angle and distance parameters \n" @@ -598,7 +598,7 @@ def angle_cutoff(self, angle_cutoff): self._angle_cutoff = AngleCutoffFloat(angle_cutoff) @property - def additional_condition(self): + def additional_condition(self) -> AdditionalConditionInt: """Additional condition for this strategy.""" return self._additional_condition @@ -897,14 +897,14 @@ class SimpleAbundanceChemenvStrategy(AbstractChemenvStrategy): DEFAULT_MAX_DIST = 2.0 DEFAULT_ADDITIONAL_CONDITION = AbstractChemenvStrategy.AC.ONLY_ACB - STRATEGY_OPTIONS: ClassVar[dict[str, dict]] = dict( # type: ignore - surface_calculation_type={}, - additional_condition=dict( - type=AdditionalConditionInt, - internal="_additional_condition", - default=DEFAULT_ADDITIONAL_CONDITION, - ), - ) + STRATEGY_OPTIONS: ClassVar[dict[str, dict]] = { + "surface_calculation_type": {}, + "additional_condition": { + "type": AdditionalConditionInt, + "internal": "_additional_condition", + "default": DEFAULT_ADDITIONAL_CONDITION, + }, + } STRATEGY_DESCRIPTION = ( 'Simple Abundance ChemenvStrategy using the most "abundant" neighbors map \n' "for the definition of neighbors in the Voronoi approach. \n" @@ -1057,7 +1057,7 @@ def __eq__(self, other: object) -> bool: if not isinstance(other, type(self)): return NotImplemented - return self._additional_condition == other.additional_condition # type: ignore + return self._additional_condition == other.additional_condition # type: ignore[has-type] def as_dict(self): """ @@ -1347,7 +1347,7 @@ def angle_sumn(self, nb_set): def __eq__(self, other: object) -> bool: if not hasattr(other, "aa"): return NotImplemented - return self.aa == other.aa # type: ignore + return self.aa == other.aa def as_dict(self): """MSONable dict.""" @@ -1644,14 +1644,14 @@ class SelfCSMNbSetWeight(NbSetWeight): SHORT_NAME = "SelfCSMWeight" - DEFAULT_EFFECTIVE_CSM_ESTIMATOR: ClassVar = dict( - function="power2_inverse_decreasing", - options={"max_csm": 8.0}, - ) - DEFAULT_WEIGHT_ESTIMATOR: ClassVar = dict( - function="power2_decreasing_exp", - options={"max_csm": 8.0, "alpha": 1}, - ) + DEFAULT_EFFECTIVE_CSM_ESTIMATOR: ClassVar = { + "function": "power2_inverse_decreasing", + "options": {"max_csm": 8.0}, + } + DEFAULT_WEIGHT_ESTIMATOR: ClassVar = { + "function": "power2_decreasing_exp", + "options": {"max_csm": 8.0, "alpha": 1}, + } DEFAULT_SYMMETRY_MEASURE_TYPE = "csm_wcs_ctwcc" def __init__( @@ -1747,15 +1747,15 @@ class DeltaCSMNbSetWeight(NbSetWeight): SHORT_NAME = "DeltaCSMWeight" - DEFAULT_EFFECTIVE_CSM_ESTIMATOR: ClassVar = dict( - function="power2_inverse_decreasing", - options={"max_csm": 8.0}, - ) + DEFAULT_EFFECTIVE_CSM_ESTIMATOR: ClassVar = { + "function": "power2_inverse_decreasing", + "options": {"max_csm": 8.0}, + } DEFAULT_SYMMETRY_MEASURE_TYPE = "csm_wcs_ctwcc" - DEFAULT_WEIGHT_ESTIMATOR: ClassVar = dict( - function="smootherstep", - options={"delta_csm_min": 0.5, "delta_csm_max": 3.0}, - ) + DEFAULT_WEIGHT_ESTIMATOR: ClassVar = { + "function": "smootherstep", + "options": {"delta_csm_min": 0.5, "delta_csm_max": 3.0}, + } def __init__( self, @@ -2125,11 +2125,11 @@ class DistanceAngleAreaNbSetWeight(NbSetWeight): SHORT_NAME = "DistAngleAreaWeight" AC = AdditionalConditions() - DEFAULT_SURFACE_DEFINITION: ClassVar = dict( - type="standard_elliptic", - distance_bounds={"lower": 1.2, "upper": 1.8}, - angle_bounds={"lower": 0.1, "upper": 0.8}, - ) + DEFAULT_SURFACE_DEFINITION: ClassVar = { + "type": "standard_elliptic", + "distance_bounds": {"lower": 1.2, "upper": 1.8}, + "angle_bounds": {"lower": 0.1, "upper": 0.8}, + } def __init__( self, @@ -2648,10 +2648,10 @@ class WeightedNbSetChemenvStrategy(AbstractChemenvStrategy): """WeightedNbSetChemenvStrategy.""" STRATEGY_DESCRIPTION = " WeightedNbSetChemenvStrategy" - DEFAULT_CE_ESTIMATOR: ClassVar = dict( - function="power2_inverse_power2_decreasing", - options={"max_csm": 8.0}, - ) + DEFAULT_CE_ESTIMATOR: ClassVar = { + "function": "power2_inverse_power2_decreasing", + "options": {"max_csm": 8.0}, + } def __init__( self, @@ -2952,10 +2952,10 @@ class MultiWeightsChemenvStrategy(WeightedNbSetChemenvStrategy): # 'cn_map_delta_csm', 'cn_map_delta_csms_cn_map2', 'cn_map_delta_csm_weight', # 'cn_map_cn_weight', # 'cn_map_fraction', 'cn_map_ce_fraction', 'ce_fraction'] - DEFAULT_CE_ESTIMATOR: ClassVar = dict( - function="power2_inverse_power2_decreasing", - options={"max_csm": 8.0}, - ) + DEFAULT_CE_ESTIMATOR: ClassVar = { + "function": "power2_inverse_power2_decreasing", + "options": {"max_csm": 8.0}, + } def __init__( self, diff --git a/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py b/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py index 142fe838f7e..33dafd3548a 100644 --- a/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py +++ b/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py @@ -767,7 +767,7 @@ def faces(self, sites, permutation=None): coords = [site.coords for site in sites] if permutation is None else [sites[ii].coords for ii in permutation] return [[coords[ii] for ii in face] for face in self._faces] - def edges(self, sites, permutation=None, input="sites"): + def edges(self, sites, permutation=None, input="sites"): # noqa: A002 """Get the list of edges of this coordination geometry. Each edge is given as a list of its end vertices coordinates. """ @@ -1144,7 +1144,7 @@ def is_a_valid_coordination_geometry( # TODO give a more helpful error message that suggests possible reasons and solutions raise RuntimeError("Should not be here!") - def pretty_print(self, type="implemented_geometries", maxcn=8, additional_info=None): + def pretty_print(self, type="implemented_geometries", maxcn=8, additional_info=None): # noqa: A002 """Get a string with a list of the Coordination Geometries. Args: diff --git a/pymatgen/analysis/chemenv/coordination_environments/coordination_geometry_finder.py b/pymatgen/analysis/chemenv/coordination_environments/coordination_geometry_finder.py index f202bec079a..71e65012abf 100644 --- a/pymatgen/analysis/chemenv/coordination_environments/coordination_geometry_finder.py +++ b/pymatgen/analysis/chemenv/coordination_environments/coordination_geometry_finder.py @@ -364,12 +364,12 @@ class LocalGeometryFinder: """Main class used to find the local environments in a structure.""" DEFAULT_BVA_DISTANCE_SCALE_FACTOR = 1.0 - BVA_DISTANCE_SCALE_FACTORS: ClassVar = dict( - experimental=1.0, - GGA_relaxed=1.015, - LDA_relaxed=0.995, - ) - DEFAULT_SPG_ANALYZER_OPTIONS: ClassVar = dict(symprec=1e-3, angle_tolerance=5) + BVA_DISTANCE_SCALE_FACTORS: ClassVar = { + "experimental": 1.0, + "GGA_relaxed": 1.015, + "LDA_relaxed": 0.995, + } + DEFAULT_SPG_ANALYZER_OPTIONS: ClassVar = {"symprec": 1e-3, "angle_tolerance": 5} STRUCTURE_REFINEMENT_NONE = "none" STRUCTURE_REFINEMENT_REFINED = "refined" STRUCTURE_REFINEMENT_SYMMETRIZED = "symmetrized" diff --git a/pymatgen/analysis/chemenv/utils/chemenv_config.py b/pymatgen/analysis/chemenv/utils/chemenv_config.py index 4e9ee6e8e1a..ae75a351d3d 100644 --- a/pymatgen/analysis/chemenv/utils/chemenv_config.py +++ b/pymatgen/analysis/chemenv/utils/chemenv_config.py @@ -29,8 +29,8 @@ class ChemEnvConfig: - Default options (strategies, ...). """ - DEFAULT_PACKAGE_OPTIONS: ClassVar = dict( - default_strategy={ + DEFAULT_PACKAGE_OPTIONS: ClassVar = { + "default_strategy": { "strategy": "SimplestChemenvStrategy", "strategy_options": { "distance_cutoff": strategies_class_lookup["SimplestChemenvStrategy"].DEFAULT_DISTANCE_CUTOFF, @@ -41,8 +41,8 @@ class ChemEnvConfig: ].DEFAULT_CONTINUOUS_SYMMETRY_MEASURE_CUTOFF, }, }, - default_max_distance_factor=1.5, - ) + "default_max_distance_factor": 1.5, + } def __init__(self, package_options=None): """ diff --git a/pymatgen/analysis/chemenv/utils/func_utils.py b/pymatgen/analysis/chemenv/utils/func_utils.py index 3d227c62a6e..5bae04c94a9 100644 --- a/pymatgen/analysis/chemenv/utils/func_utils.py +++ b/pymatgen/analysis/chemenv/utils/func_utils.py @@ -116,15 +116,15 @@ def from_dict(cls, dct: dict) -> Self: class RatioFunction(AbstractRatioFunction): """Concrete implementation of a series of ratio functions.""" - ALLOWED_FUNCTIONS: ClassVar = dict( - power2_decreasing_exp=["max", "alpha"], - smoothstep=["lower", "upper"], - smootherstep=["lower", "upper"], - inverse_smoothstep=["lower", "upper"], - inverse_smootherstep=["lower", "upper"], - power2_inverse_decreasing=["max"], - power2_inverse_power2_decreasing=["max"], - ) + ALLOWED_FUNCTIONS: ClassVar = { + "power2_decreasing_exp": ["max", "alpha"], + "smoothstep": ["lower", "upper"], + "smootherstep": ["lower", "upper"], + "inverse_smoothstep": ["lower", "upper"], + "inverse_smootherstep": ["lower", "upper"], + "power2_inverse_decreasing": ["max"], + "power2_inverse_power2_decreasing": ["max"], + } def power2_decreasing_exp(self, vals): """Get the evaluation of the ratio function f(x)=exp(-a*x)*(x-1)^2. @@ -229,11 +229,11 @@ class CSMFiniteRatioFunction(AbstractRatioFunction): D. Waroquiers et al., Acta Cryst. B 76, 683 (2020). """ - ALLOWED_FUNCTIONS: ClassVar = dict( - power2_decreasing_exp=["max_csm", "alpha"], - smoothstep=["lower_csm", "upper_csm"], - smootherstep=["lower_csm", "upper_csm"], - ) + ALLOWED_FUNCTIONS: ClassVar = { + "power2_decreasing_exp": ["max_csm", "alpha"], + "smoothstep": ["lower_csm", "upper_csm"], + "smootherstep": ["lower_csm", "upper_csm"], + } def power2_decreasing_exp(self, vals): """Get the evaluation of the ratio function f(x)=exp(-a*x)*(x-1)^2. @@ -330,10 +330,10 @@ class CSMInfiniteRatioFunction(AbstractRatioFunction): D. Waroquiers et al., Acta Cryst. B 76, 683 (2020). """ - ALLOWED_FUNCTIONS: ClassVar = dict( - power2_inverse_decreasing=["max_csm"], - power2_inverse_power2_decreasing=["max_csm"], - ) + ALLOWED_FUNCTIONS: ClassVar = { + "power2_inverse_decreasing": ["max_csm"], + "power2_inverse_power2_decreasing": ["max_csm"], + } def power2_inverse_decreasing(self, vals): """Get the evaluation of the ratio function f(x)=(x-1)^2 / x. @@ -421,7 +421,7 @@ class DeltaCSMRatioFunction(AbstractRatioFunction): D. Waroquiers et al., Acta Cryst. B 76, 683 (2020). """ - ALLOWED_FUNCTIONS: ClassVar = dict(smootherstep=["delta_csm_min", "delta_csm_max"]) + ALLOWED_FUNCTIONS: ClassVar = {"smootherstep": ["delta_csm_min", "delta_csm_max"]} def smootherstep(self, vals): """Get the evaluation of the smootherstep ratio function: f(x)=6*x^5-15*x^4+10*x^3. diff --git a/pymatgen/analysis/chemenv/utils/scripts_utils.py b/pymatgen/analysis/chemenv/utils/scripts_utils.py index 087a42b2402..ca0fe90c08c 100644 --- a/pymatgen/analysis/chemenv/utils/scripts_utils.py +++ b/pymatgen/analysis/chemenv/utils/scripts_utils.py @@ -3,11 +3,11 @@ from __future__ import annotations import re +from typing import TYPE_CHECKING import numpy as np from pymatgen.analysis.chemenv.coordination_environments.chemenv_strategies import ( - AbstractChemenvStrategy, SimpleAbundanceChemenvStrategy, SimplestChemenvStrategy, TargetedPenaltiedAbundanceChemenvStrategy, @@ -32,6 +32,9 @@ except ImportError: StructureVis = None # type: ignore[misc] +if TYPE_CHECKING: + from typing import Any + __author__ = "David Waroquiers" __copyright__ = "Copyright 2012, The Materials Project" __credits__ = "Geoffroy Hautier" @@ -40,10 +43,10 @@ __email__ = "david.waroquiers@gmail.com" __date__ = "Feb 20, 2016" -strategies_class_lookup: dict[str, AbstractChemenvStrategy] = { - "SimplestChemenvStrategy": SimplestChemenvStrategy, # type: ignore - "SimpleAbundanceChemenvStrategy": SimpleAbundanceChemenvStrategy, # type: ignore - "TargetedPenaltiedAbundanceChemenvStrategy": TargetedPenaltiedAbundanceChemenvStrategy, # type: ignore +strategies_class_lookup: dict[str, Any] = { + "SimplestChemenvStrategy": SimplestChemenvStrategy, + "SimpleAbundanceChemenvStrategy": SimpleAbundanceChemenvStrategy, + "TargetedPenaltiedAbundanceChemenvStrategy": TargetedPenaltiedAbundanceChemenvStrategy, } diff --git a/pymatgen/analysis/chempot_diagram.py b/pymatgen/analysis/chempot_diagram.py index 2890ca9db28..a2c6cfc7031 100644 --- a/pymatgen/analysis/chempot_diagram.py +++ b/pymatgen/analysis/chempot_diagram.py @@ -187,7 +187,7 @@ def get_plot( default_min_limit=self.default_min_limit, formal_chempots=self.formal_chempots, ) - fig = cpd.get_plot(elements=elems, label_stable=label_stable) # type: ignore + fig = cpd.get_plot(elements=elems, label_stable=label_stable) # type: ignore[arg-type] else: fig = self._get_3d_plot( elements=elems, @@ -211,7 +211,7 @@ def _get_domains(self) -> dict[str, np.ndarray]: interior_point = np.min(self.lims, axis=1) + 1e-1 hs_int = HalfspaceIntersection(hs_hyperplanes, interior_point) - domains = {entry.reduced_formula: [] for entry in entries} # type: ignore + domains: dict[str, list] = {entry.reduced_formula: [] for entry in entries} for intersection, facet in zip(hs_int.intersections, hs_int.dual_facets): for v in facet: @@ -585,7 +585,7 @@ def get_chempot_axis_title(element) -> str: return axes_layout - @property # type: ignore + @property @lru_cache(maxsize=1) # noqa: B019 def domains(self) -> dict[str, np.ndarray]: """Mapping of formulas to array of domain boundary points.""" diff --git a/pymatgen/analysis/diffraction/neutron.py b/pymatgen/analysis/diffraction/neutron.py index 694182dc960..59d36759ba0 100644 --- a/pymatgen/analysis/diffraction/neutron.py +++ b/pymatgen/analysis/diffraction/neutron.py @@ -26,8 +26,8 @@ __email__ = "resnant@outlook.jp" __date__ = "4/19/18" -with open(os.path.join(os.path.dirname(__file__), "neutron_scattering_length.json")) as file: - # This table was cited from "Neutron Data Booklet" 2nd ed (Old City 2003). +# This table was cited from "Neutron Data Booklet" 2nd ed (Old City 2003). +with open(os.path.join(os.path.dirname(__file__), "neutron_scattering_length.json"), encoding="utf-8") as file: ATOMIC_SCATTERING_LEN = json.load(file) @@ -133,7 +133,7 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) two_thetas: list[float] = [] for hkl, g_hkl, ind, _ in sorted(recip_pts, key=lambda i: (i[1], -i[0][0], -i[0][1], -i[0][2])): - # Force miller indices to be integers. + # Force miller indices to be integers hkl = [int(round(i)) for i in hkl] if g_hkl != 0: d_hkl = 1 / g_hkl @@ -149,7 +149,7 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) dw_correction = np.exp(-dw_factors * (s**2)) # Vectorized computation of g.r for all fractional coords and - # hkl. + # hkl g_dot_r = np.dot(frac_coords, np.transpose([hkl])).T[0] # Structure factor = sum of atomic scattering factors (with @@ -160,24 +160,24 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) # Lorentz polarization correction for hkl lorentz_factor = 1 / (sin(theta) ** 2 * cos(theta)) - # Intensity for hkl is modulus square of structure factor. + # Intensity for hkl is modulus square of structure factor i_hkl = (f_hkl * f_hkl.conjugate()).real two_theta = degrees(2 * theta) if is_hex: - # Use Miller-Bravais indices for hexagonal lattices. + # Use Miller-Bravais indices for hexagonal lattices hkl = (hkl[0], hkl[1], -hkl[0] - hkl[1], hkl[2]) - # Deal with floating point precision issues. + # Deal with floating point precision issues ind = np.where(np.abs(np.subtract(two_thetas, two_theta)) < self.TWO_THETA_TOL) if len(ind[0]) > 0: peaks[two_thetas[ind[0][0]]][0] += i_hkl * lorentz_factor - peaks[two_thetas[ind[0][0]]][1].append(tuple(hkl)) # type: ignore + peaks[two_thetas[ind[0][0]]][1].append(tuple(hkl)) # type: ignore[union-attr] else: peaks[two_theta] = [i_hkl * lorentz_factor, [tuple(hkl)], d_hkl] two_thetas.append(two_theta) - # Scale intensities so that the max intensity is 100. + # Scale intensities so that the max intensity is 100 max_intensity = max(v[0] for v in peaks.values()) x = [] y = [] @@ -186,7 +186,7 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) for key in sorted(peaks): v = peaks[key] fam = get_unique_families(v[1]) - if v[0] / max_intensity * 100 > self.SCALED_INTENSITY_TOL: # type: ignore + if v[0] / max_intensity * 100 > self.SCALED_INTENSITY_TOL: # type: ignore[operator] x.append(key) y.append(v[0]) hkls.append([{"hkl": hkl, "multiplicity": mult} for hkl, mult in fam.items()]) diff --git a/pymatgen/analysis/diffraction/tem.py b/pymatgen/analysis/diffraction/tem.py index 7c7a7584102..45b8b9f9cf4 100644 --- a/pymatgen/analysis/diffraction/tem.py +++ b/pymatgen/analysis/diffraction/tem.py @@ -101,7 +101,7 @@ def generate_points(coord_left: int = -10, coord_right: int = 10) -> np.ndarray: """ points = [0, 0, 0] coord_values = np.arange(coord_left, coord_right + 1) - points[0], points[1], points[2] = np.meshgrid(coord_values, coord_values, coord_values) # type: ignore + points[0], points[1], points[2] = np.meshgrid(coord_values, coord_values, coord_values) points_matrix = (np.ravel(points[i]) for i in range(3)) return np.vstack(list(points_matrix)).transpose() @@ -120,7 +120,7 @@ def zone_axis_filter(self, points: list[Tuple3Ints] | np.ndarray, laue_zone: int if len(points) == 0: return [] filtered = np.where(np.dot(np.array(self.beam_direction), np.transpose(points)) == laue_zone) - result = points[filtered] # type: ignore + result = points[filtered] return cast(list[Tuple3Ints], [tuple(x) for x in result.tolist()]) def get_interplanar_spacings( @@ -194,7 +194,7 @@ def x_ray_factors( for plane in bragg_angles: scattering_factor_curr = atom.Z - 41.78214 * s2[plane] * np.sum( coeffs[:, 0] * np.exp(-coeffs[:, 1] * s2[plane]), - axis=None, # type: ignore + axis=None, ) scattering_factors_for_atom[plane] = scattering_factor_curr x_ray_factors[atom.symbol] = scattering_factors_for_atom diff --git a/pymatgen/analysis/diffraction/xrd.py b/pymatgen/analysis/diffraction/xrd.py index 8a15d24fc9c..49eb07e05a0 100644 --- a/pymatgen/analysis/diffraction/xrd.py +++ b/pymatgen/analysis/diffraction/xrd.py @@ -47,7 +47,7 @@ "AgKb1": 0.497082, } -with open(os.path.join(os.path.dirname(__file__), "atomic_scattering_params.json")) as file: +with open(os.path.join(os.path.dirname(__file__), "atomic_scattering_params.json"), encoding="utf-8") as file: ATOMIC_SCATTERING_PARAMS = json.load(file) @@ -196,7 +196,7 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) two_thetas: list[float] = [] for hkl, g_hkl, ind, _ in sorted(recip_pts, key=lambda i: (i[1], -i[0][0], -i[0][1], -i[0][2])): - # Force miller indices to be integers. + # Force miller indices to be integers hkl = [int(round(i)) for i in hkl] if g_hkl != 0: # Bragg condition @@ -206,11 +206,11 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) # 1/|ghkl|) s = g_hkl / 2 - # Store s^2 since we are using it a few times. + # Store s^2 since we are using it a few times s2 = s**2 # Vectorized computation of g.r for all fractional coords and - # hkl. + # hkl g_dot_r = np.dot(frac_coords, np.transpose([hkl])).T[0] # Highly vectorized computation of atomic scattering factors. @@ -223,7 +223,7 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) # [d[0] * exp(-d[1] * s2) for d in coeff]) fs = zs - 41.78214 * s2 * np.sum( coeffs[:, :, 0] * np.exp(-coeffs[:, :, 1] * s2), - axis=1, # type: ignore + axis=1, ) dw_correction = np.exp(-dw_factors * s2) @@ -236,27 +236,27 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) # Lorentz polarization correction for hkl lorentz_factor = (1 + cos(2 * theta) ** 2) / (sin(theta) ** 2 * cos(theta)) - # Intensity for hkl is modulus square of structure factor. + # Intensity for hkl is modulus square of structure factor i_hkl = (f_hkl * f_hkl.conjugate()).real two_theta = degrees(2 * theta) if is_hex: - # Use Miller-Bravais indices for hexagonal lattices. + # Use Miller-Bravais indices for hexagonal lattices hkl = (hkl[0], hkl[1], -hkl[0] - hkl[1], hkl[2]) - # Deal with floating point precision issues. + # Deal with floating point precision issues ind = np.where( np.abs(np.subtract(two_thetas, two_theta)) < AbstractDiffractionPatternCalculator.TWO_THETA_TOL ) if len(ind[0]) > 0: peaks[two_thetas[ind[0][0]]][0] += i_hkl * lorentz_factor - peaks[two_thetas[ind[0][0]]][1].append(tuple(hkl)) # type: ignore + peaks[two_thetas[ind[0][0]]][1].append(tuple(hkl)) # type: ignore[union-attr] else: d_hkl = 1 / g_hkl peaks[two_theta] = [i_hkl * lorentz_factor, [tuple(hkl)], d_hkl] two_thetas.append(two_theta) - # Scale intensities so that the max intensity is 100. + # Scale intensities so that the max intensity is 100 max_intensity = max(v[0] for v in peaks.values()) x = [] y = [] @@ -265,7 +265,7 @@ def get_pattern(self, structure: Structure, scaled=True, two_theta_range=(0, 90) for k in sorted(peaks): v = peaks[k] fam = get_unique_families(v[1]) - if v[0] / max_intensity * 100 > AbstractDiffractionPatternCalculator.SCALED_INTENSITY_TOL: # type: ignore + if v[0] / max_intensity * 100 > AbstractDiffractionPatternCalculator.SCALED_INTENSITY_TOL: # type: ignore[operator] x.append(k) y.append(v[0]) hkls.append([{"hkl": hkl, "multiplicity": mult} for hkl, mult in fam.items()]) diff --git a/pymatgen/analysis/disorder.py b/pymatgen/analysis/disorder.py index a47221add8c..538c9863228 100644 --- a/pymatgen/analysis/disorder.py +++ b/pymatgen/analysis/disorder.py @@ -24,17 +24,17 @@ def get_warren_cowley_parameters(structure: Structure, r: float, dr: float) -> d """ comp = structure.composition - n_ij = defaultdict(int) # type: ignore - n_neighbors = defaultdict(int) # type: ignore + n_ij: defaultdict = defaultdict(int) + n_neighbors: defaultdict = defaultdict(int) for site in structure: for nn in structure.get_neighbors_in_shell(site.coords, r, dr): n_ij[(site.specie, nn.specie)] += 1 n_neighbors[site.specie] += 1 - alpha_ij = {} # type: ignore + alpha_ij = {} for sp1, sp2 in itertools.product(comp, comp): pij = n_ij.get((sp1, sp2), 0) / n_neighbors[sp1] conc2 = comp.get_atomic_fraction(sp2) alpha_ij[(sp1, sp2)] = (pij - conc2) / ((1 if sp1 == sp2 else 0) - conc2) - return alpha_ij # type: ignore + return alpha_ij diff --git a/pymatgen/analysis/elasticity/elastic.py b/pymatgen/analysis/elasticity/elastic.py index fc9809de459..dfe9d67db4d 100644 --- a/pymatgen/analysis/elasticity/elastic.py +++ b/pymatgen/analysis/elasticity/elastic.py @@ -874,15 +874,15 @@ def diff_fit(strains, stresses, eq_stress=None, order=2, tol: float = 1e-10): dei_dsi = np.zeros((order - 1, 6, len(strain_state_dict))) for idx, (strain_state, data) in enumerate(strain_state_dict.items()): hvec = data["strains"][:, strain_state.index(1)] - for ord in range(1, order): - coef = get_diff_coeff(hvec, ord) - dei_dsi[ord - 1, :, idx] = np.dot(coef, data["stresses"]) + for _ord in range(1, order): + coef = get_diff_coeff(hvec, _ord) + dei_dsi[_ord - 1, :, idx] = np.dot(coef, data["stresses"]) m, _absent = generate_pseudo(list(strain_state_dict), order) - for ord in range(1, order): - cvec, carr = get_symbol_list(ord + 1) - svec = np.ravel(dei_dsi[ord - 1].T) - cmap = dict(zip(cvec, np.dot(m[ord - 1], svec))) + for _ord in range(1, order): + cvec, carr = get_symbol_list(_ord + 1) + svec = np.ravel(dei_dsi[_ord - 1].T) + cmap = dict(zip(cvec, np.dot(m[_ord - 1], svec))) c_list.append(v_subs(carr, cmap)) return [Tensor.from_voigt(c) for c in c_list] diff --git a/pymatgen/analysis/eos.py b/pymatgen/analysis/eos.py index 01e10854289..8feabcb6a92 100644 --- a/pymatgen/analysis/eos.py +++ b/pymatgen/analysis/eos.py @@ -534,15 +534,15 @@ class EOS: eos_fit.plot() """ - MODELS: ClassVar = dict( - murnaghan=Murnaghan, - birch=Birch, - birch_murnaghan=BirchMurnaghan, - pourier_tarantola=PourierTarantola, - vinet=Vinet, - deltafactor=DeltaFactor, - numerical_eos=NumericalEOS, - ) + MODELS: ClassVar = { + "murnaghan": Murnaghan, + "birch": Birch, + "birch_murnaghan": BirchMurnaghan, + "pourier_tarantola": PourierTarantola, + "vinet": Vinet, + "deltafactor": DeltaFactor, + "numerical_eos": NumericalEOS, + } def __init__(self, eos_name="murnaghan"): """ diff --git a/pymatgen/analysis/functional_groups.py b/pymatgen/analysis/functional_groups.py index f21f3ea894b..94f4cce6f17 100644 --- a/pymatgen/analysis/functional_groups.py +++ b/pymatgen/analysis/functional_groups.py @@ -83,7 +83,7 @@ def __init__(self, molecule, optimize=False): self.molgraph = molecule else: - raise ValueError("Input to FunctionalGroupExtractor must be str, Molecule, or MoleculeGraph.") + raise TypeError("Input to FunctionalGroupExtractor must be str, Molecule, or MoleculeGraph.") if self.molgraph is None: self.molgraph = MoleculeGraph.from_local_env_strategy(self.molecule, OpenBabelNN()) diff --git a/pymatgen/analysis/graphs.py b/pymatgen/analysis/graphs.py index 1722aea1720..d34dbf09b77 100644 --- a/pymatgen/analysis/graphs.py +++ b/pymatgen/analysis/graphs.py @@ -769,10 +769,10 @@ def get_connected_sites(self, n: int, jimage: Tuple3Ints = (0, 0, 0)) -> list[Co out_edges = [(u, v, d, "out") for u, v, d in self.graph.out_edges(n, data=True)] in_edges = [(u, v, d, "in") for u, v, d in self.graph.in_edges(n, data=True)] - for u, v, data, dir in out_edges + in_edges: + for u, v, data, dirc in out_edges + in_edges: to_jimage = data["to_jimage"] - if dir == "in": + if dirc == "in": u, v = v, u to_jimage = np.multiply(-1, to_jimage) diff --git a/pymatgen/analysis/interface_reactions.py b/pymatgen/analysis/interface_reactions.py index ffdf0a06c8b..39e7a1be81d 100644 --- a/pymatgen/analysis/interface_reactions.py +++ b/pymatgen/analysis/interface_reactions.py @@ -92,7 +92,7 @@ def __init__( bypass_grand_warning = kwargs.get("bypass_grand_warning", False) if isinstance(pd, GrandPotentialPhaseDiagram) and not bypass_grand_warning: - raise ValueError( + raise TypeError( "Please use the GrandPotentialInterfacialReactivity " "class for interfacial reactions with open elements!" ) @@ -338,17 +338,16 @@ def _get_plotly_figure(self) -> Figure: hoverinfo="none", ) - annotations = self._get_plotly_annotations(x, energy, reactions) # type: ignore + annotations = self._get_plotly_annotations(x, energy, reactions) - min_idx = energy.index(min(energy)) # type: ignore + min_idx = energy.index(min(energy)) x_min = x.pop(min_idx) e_min = energy.pop(min_idx) rxn_min = reactions.pop(min_idx) labels = [ - f"{htmlify(str(r))}
\u0394Erxn = {round(e, 3)} eV/atom" # type: ignore - for r, e in zip(reactions, energy) + f"{htmlify(str(r))}
\u0394Erxn = {round(e, 3)} eV/atom" for r, e in zip(reactions, energy) ] markers = Scatter( @@ -367,7 +366,7 @@ def _get_plotly_figure(self) -> Figure: hoverlabel={"bgcolor": "navy"}, ) - min_label = f"{htmlify(str(rxn_min))}
\u0394Erxn = {round(e_min, 3)} eV/atom" # type: ignore + min_label = f"{htmlify(str(rxn_min))}
\u0394Erxn = {round(e_min, 3)} eV/atom" minimum = Scatter( x=[x_min], @@ -625,9 +624,9 @@ def __init__( warning message. """ if not isinstance(grand_pd, GrandPotentialPhaseDiagram): - raise ValueError("Please use the InterfacialReactivity class if using a regular phase diagram!") + raise TypeError("Please use the InterfacialReactivity class if using a regular phase diagram!") if not isinstance(pd_non_grand, PhaseDiagram): - raise ValueError("Please provide non-grand phase diagram to compute no_mixing_energy!") + raise TypeError("Please provide non-grand phase diagram to compute no_mixing_energy!") super().__init__( c1=c1, c2=c2, pd=grand_pd, norm=norm, use_hull_energy=use_hull_energy, bypass_grand_warning=True diff --git a/pymatgen/analysis/local_env.py b/pymatgen/analysis/local_env.py index cad13415668..2fc0b90f224 100644 --- a/pymatgen/analysis/local_env.py +++ b/pymatgen/analysis/local_env.py @@ -220,7 +220,7 @@ def _handle_disorder(structure: Structure, on_disorder: on_disorder_options): # As a workaround, we create a new structure with majority species on each site. structure = structure.copy() # make a copy so we don't mutate the original structure for idx, site in enumerate(structure): - max_specie = max(site.species, key=site.species.get) # type: ignore + max_specie = max(site.species, key=site.species.get) max_val = site.species[max_specie] if max_val <= 0.5: if on_disorder == "take_majority_strict": @@ -621,7 +621,7 @@ def get_bonded_structure( structure, self, weights=weights, edge_properties=edge_properties ) - # sets the attributes + # Set the attributes struct_graph.set_node_attributes() return struct_graph @@ -655,7 +655,7 @@ def get_local_order_parameters(self, structure: Structure, n: int): params.append(tmp) lsops = LocalStructOrderParams(types, parameters=params) sites = [structure[n], *self.get_nn(structure, n)] - lostop_vals = lsops.get_order_parameters(sites, 0, indices_neighs=list(range(1, cn + 1))) # type: ignore + lostop_vals = lsops.get_order_parameters(sites, 0, indices_neighs=list(range(1, cn + 1))) # type: ignore[call-overload, arg-type] dct = {} for idx, lsop in enumerate(lostop_vals): dct[names[idx]] = lsop @@ -769,7 +769,7 @@ def get_voronoi_polyhedra(self, structure: Structure, n: int): if self.cutoff >= max_cutoff: if exc.args and "vertex" in exc.args[0]: # pass through the error raised by _extract_cell_info - raise exc + raise raise RuntimeError("Error in Voronoi neighbor finding; max cutoff exceeded") self.cutoff = min(self.cutoff * 2, max_cutoff + 0.001) return cell_info @@ -817,14 +817,14 @@ def get_all_voronoi_polyhedra(self, structure: Structure): indices.extend([(x[2],) + x[3] for x in neighs]) # Get the non-duplicates (using the site indices for numerical stability) - indices = np.array(indices, dtype=int) # type: ignore + indices = np.array(indices, dtype=int) indices, uniq_inds = np.unique(indices, return_index=True, axis=0) # type: ignore[assignment] sites = [sites[idx] for idx in uniq_inds] # Sort array such that atoms in the root image are first # Exploit the fact that the array is sorted by the unique operation such that # the images associated with atom 0 are first, followed by atom 1, etc. - (root_images,) = np.nonzero(np.abs(indices[:, 1:]).max(axis=1) == 0) # type: ignore + (root_images,) = np.nonzero(np.abs(indices[:, 1:]).max(axis=1) == 0) # type: ignore[call-overload] del indices # Save memory (tessellations can be costly) @@ -1486,7 +1486,7 @@ def get_nn_info(self, structure: Structure, n: int): return siw - def get_bonded_structure(self, structure: Structure, decorate: bool = False) -> StructureGraph: # type: ignore + def get_bonded_structure(self, structure: Structure, decorate: bool = False) -> StructureGraph: # type: ignore[override] """ Obtain a MoleculeGraph object using this NearNeighbor class. Requires the optional dependency networkx @@ -1633,7 +1633,7 @@ def get_nn_info(self, structure: Structure, n: int): return siw - def get_bonded_structure(self, structure: Structure, decorate: bool = False) -> MoleculeGraph: # type: ignore + def get_bonded_structure(self, structure: Structure, decorate: bool = False) -> MoleculeGraph: # type: ignore[override] """ Obtain a MoleculeGraph object using this NearNeighbor class. @@ -2874,7 +2874,7 @@ def get_order_parameters( for j, neigh in enumerate(neighsites): rij.append(neigh.coords - centvec) dist.append(float(np.linalg.norm(rij[j]))) - rij_norm.append(rij[j] / dist[j]) # type: ignore + rij_norm.append(rij[j] / dist[j]) if self._computerjks: for j, neigh in enumerate(neighsites): rjk.append([]) @@ -2890,7 +2890,7 @@ def get_order_parameters( rjknorm[j].append(rjk[j][kk] / distjk[j][kk]) kk += 1 # Initialize OP list and, then, calculate OPs. - ops = [0.0 for t in self._types] + ops: list[float | None] = [0.0 for t in self._types] # norms = [[[] for j in range(nneigh)] for t in self._types] # First, coordination number and distance-based OPs. @@ -2947,8 +2947,8 @@ def get_order_parameters( # Zimmermann et al., J. Am. Chem. Soc., under revision, 2015). if self._geomops: gaussthetak: list[float] = [0 for _t in self._types] # not used by all OPs - qsp_theta = [[[] for _j in range(n_neighbors)] for _t in self._types] # type: ignore - norms = [[[] for _j in range(n_neighbors)] for _t in self._types] # type: ignore + qsp_theta: list[list[list]] = [[[] for _j in range(n_neighbors)] for _t in self._types] + norms: list[list[list]] = [[[] for _j in range(n_neighbors)] for _t in self._types] ipi = 1 / math.pi piover2 = math.pi / 2.0 onethird = 1 / 3 @@ -3254,7 +3254,8 @@ def get_order_parameters( for j in range(n_neighbors): ops[idx] += sum(qsp_theta[idx][j]) tmp_norm += float(sum(norms[idx][j])) - ops[idx] = ops[idx] / tmp_norm if tmp_norm > 1.0e-12 else None # type: ignore + ops[idx] = ops[idx] / tmp_norm if tmp_norm > 1.0e-12 else None # type: ignore[operator] + elif typ in { "T", "tri_pyr", @@ -3283,16 +3284,18 @@ def get_order_parameters( qsp_theta[idx][j][k] / norms[idx][j][k] if norms[idx][j][k] > 1.0e-12 else 0.0 ) ops[idx] = max(qsp_theta[idx][j]) if j == 0 else max(ops[idx], *qsp_theta[idx][j]) + elif typ == "bcc": ops[idx] = 0.0 for j in range(n_neighbors): ops[idx] += sum(qsp_theta[idx][j]) if n_neighbors > 3: - ops[idx] = ops[idx] / float( + ops[idx] = ops[idx] / float( # type: ignore[operator] 0.5 * float(n_neighbors * (6 + (n_neighbors - 2) * (n_neighbors - 3))) ) else: ops[idx] = None # type: ignore[call-overload] + elif typ == "sq_pyr_legacy": if n_neighbors > 1: dmean = np.mean(dist) @@ -3302,7 +3305,7 @@ def get_order_parameters( acc = acc + math.exp(-0.5 * tmp * tmp) for j in range(n_neighbors): ops[idx] = max(qsp_theta[idx][j]) if j == 0 else max(ops[idx], *qsp_theta[idx][j]) - ops[idx] = acc * ops[idx] / float(n_neighbors) + ops[idx] = acc * ops[idx] / float(n_neighbors) # type: ignore[operator] # nneigh * (nneigh - 1)) else: ops[idx] = None # type: ignore[call-overload] @@ -3334,15 +3337,15 @@ def get_order_parameters( else: ops[idx] = 1.0 if typ == "reg_tri": - a = 2 * math.asin(b / (2 * math.sqrt(h * h + (b / (2 * math.cos(3 * math.pi / 18))) ** 2))) # type: ignore + a = 2 * math.asin(b / (2 * math.sqrt(h * h + (b / (2 * math.cos(3 * math.pi / 18))) ** 2))) nmax = 3 else: - a = 2 * math.asin(b / (2 * math.sqrt(h * h + dhalf * dhalf))) # type: ignore + a = 2 * math.asin(b / (2 * math.sqrt(h * h + dhalf * dhalf))) nmax = 4 for j in range(min([n_neighbors, nmax])): - ops[idx] = ops[idx] * math.exp(-0.5 * ((aijs[j] - a) * self._params[idx][0]) ** 2) + ops[idx] = ops[idx] * math.exp(-0.5 * ((aijs[j] - a) * self._params[idx][0]) ** 2) # type: ignore[operator] return ops @@ -3995,7 +3998,7 @@ def get_nn_data(self, structure: Structure, n: int, length=None): return self.transform_to_length(self.NNData(nn, cn_weights, cn_nninfo), length) - def get_cn(self, structure: Structure, n: int, **kwargs) -> float: # type: ignore + def get_cn(self, structure: Structure, n: int, **kwargs) -> float: # type: ignore[override] """Get coordination number, CN, of site with index n in structure. Args: @@ -4301,7 +4304,7 @@ def extend_structure_molecules(self) -> bool: """ return True - def get_bonded_structure(self, structure: Structure, decorate: bool = False) -> StructureGraph: # type: ignore + def get_bonded_structure(self, structure: Structure, decorate: bool = False) -> StructureGraph: # type: ignore[override] """ Args: structure (Structure): Input structure diff --git a/pymatgen/analysis/magnetism/analyzer.py b/pymatgen/analysis/magnetism/analyzer.py index a983da40ca0..6c10495630b 100644 --- a/pymatgen/analysis/magnetism/analyzer.py +++ b/pymatgen/analysis/magnetism/analyzer.py @@ -266,8 +266,8 @@ def __init__( elif overwrite_magmom_mode == OverwriteMagmomMode.normalize.value and magmoms[idx] != 0: magmoms[idx] = int(magmoms[idx] / abs(magmoms[idx])) - # round magmoms, used to smooth out computational data - magmoms = self._round_magmoms(magmoms, round_magmoms) if round_magmoms else magmoms # type: ignore + # Round magmoms, used to smooth out computational data + magmoms = self._round_magmoms(magmoms, round_magmoms) if round_magmoms else magmoms if set_net_positive: sign = np.sum(magmoms) diff --git a/pymatgen/analysis/magnetism/jahnteller.py b/pymatgen/analysis/magnetism/jahnteller.py index b102c3c352f..dda2d3b4907 100644 --- a/pymatgen/analysis/magnetism/jahnteller.py +++ b/pymatgen/analysis/magnetism/jahnteller.py @@ -348,7 +348,7 @@ def _get_number_of_d_electrons(species: Species) -> float: elec = species.element.full_electronic_structure if len(elec) < 4 or elec[-1][1] != "s" or elec[-2][1] != "d": raise AttributeError(f"Invalid element {species.symbol} for crystal field calculation.") - n_electrons = int(elec[-1][2] + elec[-2][2] - species.oxi_state) # type: ignore + n_electrons = int(elec[-1][2] + elec[-2][2] - species.oxi_state) # type: ignore[operator] if n_electrons < 0 or n_electrons > 10: raise AttributeError(f"Invalid oxidation state {species.oxi_state} for element {species.symbol}") diff --git a/pymatgen/analysis/molecule_structure_comparator.py b/pymatgen/analysis/molecule_structure_comparator.py index a3907fd08d7..32d603abd28 100644 --- a/pymatgen/analysis/molecule_structure_comparator.py +++ b/pymatgen/analysis/molecule_structure_comparator.py @@ -39,104 +39,104 @@ class CovalentRadius: Beatriz C. et al. Dalton Trans. 2008, 2832-2838. https://doi.org/10.1039/b801115j """ - radius: ClassVar = dict( - H=0.31, - He=0.28, - Li=1.28, - Be=0.96, - B=0.84, - C=0.73, - N=0.71, - O=0.66, - F=0.57, - Ne=0.58, - Na=1.66, - Mg=1.41, - Al=1.21, - Si=1.11, - P=1.07, - S=1.05, - Cl=1.02, - Ar=1.06, - K=2.03, - Ca=1.76, - Sc=1.70, - Ti=1.60, - V=1.53, - Cr=1.39, - Mn=1.50, - Fe=1.42, - Co=1.38, - Ni=1.24, - Cu=1.32, - Zn=1.22, - Ga=1.22, - Ge=1.20, - As=1.19, - Se=1.20, - Br=1.20, - Kr=1.16, - Rb=2.20, - Sr=1.95, - Y=1.90, - Zr=1.75, - Nb=1.64, - Mo=1.54, - Tc=1.47, - Ru=1.46, - Rh=1.42, - Pd=1.39, - Ag=1.45, - Cd=1.44, - In=1.42, - Sn=1.39, - Sb=1.39, - Te=1.38, - I=1.39, - Xe=1.40, - Cs=2.44, - Ba=2.15, - La=2.07, - Ce=2.04, - Pr=2.03, - Nd=2.01, - Pm=1.99, - Sm=1.98, - Eu=1.98, - Gd=1.96, - Tb=1.94, - Dy=1.92, - Ho=1.92, - Er=1.89, - Tm=1.90, - Yb=1.87, - Lu=1.87, - Hf=1.75, - Ta=1.70, - W=1.62, - Re=1.51, - Os=1.44, - Ir=1.41, - Pt=1.36, - Au=1.36, - Hg=1.32, - Tl=1.45, - Pb=1.46, - Bi=1.48, - Po=1.40, - At=1.50, - Rn=1.50, - Fr=2.60, - Ra=2.21, - Ac=2.15, - Th=2.06, - Pa=2, - U=1.96, - Np=1.90, - Pu=1.87, - Am=1.80, - Cm=1.69, - ) + radius: ClassVar = { + "H": 0.31, + "He": 0.28, + "Li": 1.28, + "Be": 0.96, + "B": 0.84, + "C": 0.73, + "N": 0.71, + "O": 0.66, + "F": 0.57, + "Ne": 0.58, + "Na": 1.66, + "Mg": 1.41, + "Al": 1.21, + "Si": 1.11, + "P": 1.07, + "S": 1.05, + "Cl": 1.02, + "Ar": 1.06, + "K": 2.03, + "Ca": 1.76, + "Sc": 1.70, + "Ti": 1.60, + "V": 1.53, + "Cr": 1.39, + "Mn": 1.50, + "Fe": 1.42, + "Co": 1.38, + "Ni": 1.24, + "Cu": 1.32, + "Zn": 1.22, + "Ga": 1.22, + "Ge": 1.20, + "As": 1.19, + "Se": 1.20, + "Br": 1.20, + "Kr": 1.16, + "Rb": 2.20, + "Sr": 1.95, + "Y": 1.90, + "Zr": 1.75, + "Nb": 1.64, + "Mo": 1.54, + "Tc": 1.47, + "Ru": 1.46, + "Rh": 1.42, + "Pd": 1.39, + "Ag": 1.45, + "Cd": 1.44, + "In": 1.42, + "Sn": 1.39, + "Sb": 1.39, + "Te": 1.38, + "I": 1.39, + "Xe": 1.40, + "Cs": 2.44, + "Ba": 2.15, + "La": 2.07, + "Ce": 2.04, + "Pr": 2.03, + "Nd": 2.01, + "Pm": 1.99, + "Sm": 1.98, + "Eu": 1.98, + "Gd": 1.96, + "Tb": 1.94, + "Dy": 1.92, + "Ho": 1.92, + "Er": 1.89, + "Tm": 1.90, + "Yb": 1.87, + "Lu": 1.87, + "Hf": 1.75, + "Ta": 1.70, + "W": 1.62, + "Re": 1.51, + "Os": 1.44, + "Ir": 1.41, + "Pt": 1.36, + "Au": 1.36, + "Hg": 1.32, + "Tl": 1.45, + "Pb": 1.46, + "Bi": 1.48, + "Po": 1.40, + "At": 1.50, + "Rn": 1.50, + "Fr": 2.60, + "Ra": 2.21, + "Ac": 2.15, + "Th": 2.06, + "Pa": 2, + "U": 1.96, + "Np": 1.90, + "Pu": 1.87, + "Am": 1.80, + "Cm": 1.69, + } class MoleculeStructureComparator(MSONable): diff --git a/pymatgen/analysis/nmr.py b/pymatgen/analysis/nmr.py index de10dd6370a..bf16031f028 100644 --- a/pymatgen/analysis/nmr.py +++ b/pymatgen/analysis/nmr.py @@ -238,6 +238,6 @@ def coupling_constant(self, specie): elif isinstance(specie, Species): quad_pol_mom = specie.get_nmr_quadrupole_moment() else: - raise ValueError("Invalid species provided for quadrupolar coupling constant calculations") + raise TypeError("Invalid species provided for quadrupolar coupling constant calculations") return (e * quad_pol_mom * Vzz / planks_constant).to("MHz") diff --git a/pymatgen/analysis/phase_diagram.py b/pymatgen/analysis/phase_diagram.py index 5557b85d6c5..8411ac64da2 100644 --- a/pymatgen/analysis/phase_diagram.py +++ b/pymatgen/analysis/phase_diagram.py @@ -2492,7 +2492,7 @@ def get_contour_pd_plot(self): return ax - @property # type: ignore + @property @lru_cache(1) # noqa: B019 def pd_plot_data(self): """ diff --git a/pymatgen/analysis/piezo_sensitivity.py b/pymatgen/analysis/piezo_sensitivity.py index 64e2c01bc7c..0a93140dc15 100644 --- a/pymatgen/analysis/piezo_sensitivity.py +++ b/pymatgen/analysis/piezo_sensitivity.py @@ -534,7 +534,7 @@ def get_asum_FCM(self, fcm: np.ndarray, numiter: int = 15): pastrow = 0 total = np.zeros([3, 3]) for col in range(n_sites): - total = total + X[0:3, col * 3 : col * 3 + 3] + total = total + X[:3, col * 3 : col * 3 + 3] total = total / (n_sites) for op in operations: diff --git a/pymatgen/analysis/reaction_calculator.py b/pymatgen/analysis/reaction_calculator.py index a98876d6615..456e6ea97d9 100644 --- a/pymatgen/analysis/reaction_calculator.py +++ b/pymatgen/analysis/reaction_calculator.py @@ -283,8 +283,8 @@ def from_str(cls, rxn_str: str) -> Self: def get_comp_amt(comp_str): return { - Composition(m.group(2)): float(m.group(1) or 1) - for m in re.finditer(r"([\d\.]*(?:[eE]-?[\d\.]+)?)\s*([A-Z][\w\.\(\)]*)", comp_str) + Composition(match[2]): float(match[1] or 1) + for match in re.finditer(r"([\d\.]*(?:[eE]-?[\d\.]+)?)\s*([A-Z][\w\.\(\)]*)", comp_str) } return BalancedReaction(get_comp_amt(rct_str), get_comp_amt(prod_str)) diff --git a/pymatgen/analysis/structure_matcher.py b/pymatgen/analysis/structure_matcher.py index a2640c127ee..36bdf43e01f 100644 --- a/pymatgen/analysis/structure_matcher.py +++ b/pymatgen/analysis/structure_matcher.py @@ -899,7 +899,7 @@ def _anonymous_match( List of (mapping, match) """ if not isinstance(self._comparator, SpeciesComparator): - raise ValueError("Anonymous fitting currently requires SpeciesComparator") + raise TypeError("Anonymous fitting currently requires SpeciesComparator") # check that species lists are comparable sp1 = struct1.elements diff --git a/pymatgen/analysis/surface_analysis.py b/pymatgen/analysis/surface_analysis.py index c251e44c479..752e9da35fb 100644 --- a/pymatgen/analysis/surface_analysis.py +++ b/pymatgen/analysis/surface_analysis.py @@ -872,10 +872,10 @@ def chempot_vs_gamma_plot_one( mark = "--" if ucell_comp != clean_comp else "-" delu_dict = self.set_all_variables(delu_dict, delu_default) - delu_dict[ref_delu] = chempot_range[0] # type: ignore + delu_dict[ref_delu] = chempot_range[0] # type: ignore[index] gamma_min = self.as_coeffs_dict[entry] gamma_min = gamma_min if type(gamma_min).__name__ == "float" else sub_chempots(gamma_min, delu_dict) - delu_dict[ref_delu] = chempot_range[1] # type: ignore + delu_dict[ref_delu] = chempot_range[1] # type: ignore[index] gamma_max = self.as_coeffs_dict[entry] gamma_max = gamma_max if type(gamma_max).__name__ == "float" else sub_chempots(gamma_max, delu_dict) gamma_range = [gamma_min, gamma_max] diff --git a/pymatgen/cli/pmg_analyze.py b/pymatgen/cli/pmg_analyze.py index 132e447b8c3..c12ef4186ef 100644 --- a/pymatgen/cli/pmg_analyze.py +++ b/pymatgen/cli/pmg_analyze.py @@ -91,11 +91,11 @@ def get_energies(rootdir, reanalyze, verbose, quick, sort, fmt): return 0 -def get_magnetizations(dir: str, ion_list: list[int]): +def get_magnetizations(dirc: str, ion_list: list[int]): """Get magnetization info from OUTCARs. Args: - dir (str): Directory name + dirc (str): Directory name ion_list (list[int]): List of ions to obtain magnetization information for. Returns: @@ -103,7 +103,7 @@ def get_magnetizations(dir: str, ion_list: list[int]): """ data = [] max_row = 0 - for parent, _subdirs, files in os.walk(dir): + for parent, _subdirs, files in os.walk(dirc): for file in files: if re.match(r"OUTCAR*", file): try: diff --git a/pymatgen/cli/pmg_config.py b/pymatgen/cli/pmg_config.py index d3c135b7c71..d8253983e19 100755 --- a/pymatgen/cli/pmg_config.py +++ b/pymatgen/cli/pmg_config.py @@ -26,7 +26,7 @@ def setup_cp2k_data(cp2k_data_dirs: list[str]) -> None: """Setup CP2K basis and potential data directory.""" - data_dir, target_dir = (os.path.abspath(dir) for dir in cp2k_data_dirs) + data_dir, target_dir = (os.path.abspath(dirc) for dirc in cp2k_data_dirs) try: os.mkdir(target_dir) except OSError: @@ -74,9 +74,7 @@ def setup_cp2k_data(cp2k_data_dirs: list[str]) -> None: try: basis = GaussianTypeOrbitalBasisSet.from_str(chk) basis.filename = os.path.basename(basis_file) - settings[basis.element.symbol]["basis_sets"][basis.get_hash()] = jsanitize( # type: ignore - basis, strict=True - ) + settings[basis.element.symbol]["basis_sets"][basis.get_hash()] = jsanitize(basis, strict=True) # type: ignore[union-attr] except ValueError: # Chunk was readable, but the element is not pmg recognized continue @@ -146,17 +144,17 @@ def setup_potcars(potcar_dirs: list[str]): shutil.copy(fname, dest) ext = fname.split(".")[-1] if ext.upper() in ["Z", "GZ"]: - with subprocess.Popen(["gunzip", dest]) as p: - p.communicate() + with subprocess.Popen(["gunzip", dest]) as process: + process.communicate() elif ext.upper() == "BZ2": - with subprocess.Popen(["bunzip2", dest]) as p: - p.communicate() + with subprocess.Popen(["bunzip2", dest]) as process: + process.communicate() if subdir == "Osmium": subdir = "Os" dest = os.path.join(base_dir, f"POTCAR.{subdir}") shutil.move(f"{base_dir}/POTCAR", dest) - with subprocess.Popen(["gzip", "-f", dest]) as p: - p.communicate() + with subprocess.Popen(["gzip", "-f", dest]) as process: + process.communicate() except Exception as exc: print(f"An error has occurred. Message is {exc}. Trying to continue... ") @@ -273,7 +271,7 @@ def add_config_var(tokens: list[str], backup_suffix: str) -> None: print(f"Existing {rc_path} backed up to {rc_path}{backup_suffix}") dct = loadfn(rc_path) special_vals = {"true": True, "false": False, "none": None, "null": None} - for key, val in zip(tokens[0::2], tokens[1::2]): + for key, val in zip(tokens[::2], tokens[1::2]): dct[key] = special_vals.get(val.lower(), val) dumpfn(dct, rc_path) print(f"New {rc_path} written!") diff --git a/pymatgen/command_line/bader_caller.py b/pymatgen/command_line/bader_caller.py index 27bca78353b..dbbb743acc9 100644 --- a/pymatgen/command_line/bader_caller.py +++ b/pymatgen/command_line/bader_caller.py @@ -17,7 +17,6 @@ import shutil import subprocess import warnings -from datetime import datetime from glob import glob from pathlib import Path from shutil import which @@ -244,13 +243,6 @@ def _parse_atomic_densities(self) -> list[dict]: "shift" is the shift used to center the atomic charge density, and "dim" is the dimension of the original charge density. """ - # Deprecation tracker - if ( - datetime(2025, 2, 26) < datetime.now() - and os.getenv("CI") - and os.getenv("GITHUB_REPOSITORY") == "materialsproject/pymatgen" - ): - raise RuntimeError("This method should have been removed, see #3656.") def slice_from_center(data: np.ndarray, x_width: int, y_width: int, z_width: int) -> np.ndarray: """Slices a central window from the data array.""" diff --git a/pymatgen/command_line/critic2_caller.py b/pymatgen/command_line/critic2_caller.py index 6d43959576d..4f6261afe3e 100644 --- a/pymatgen/command_line/critic2_caller.py +++ b/pymatgen/command_line/critic2_caller.py @@ -351,7 +351,7 @@ class CriticalPoint(MSONable): def __init__( self, index, - type, + type, # noqa: A002 frac_coords, point_group, multiplicity, diff --git a/pymatgen/command_line/enumlib_caller.py b/pymatgen/command_line/enumlib_caller.py index e8db875440d..bdae0256e0e 100644 --- a/pymatgen/command_line/enumlib_caller.py +++ b/pymatgen/command_line/enumlib_caller.py @@ -273,14 +273,14 @@ def get_sg_info(ss): file.write("\n".join(output)) def _run_multienum(self): - with subprocess.Popen([enum_cmd], stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) as p: + with subprocess.Popen([enum_cmd], stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) as process: if self.timeout: timed_out = False - timer = Timer(self.timeout * 60, lambda p: p.kill(), [p]) + timer = Timer(self.timeout * 60, lambda p: p.kill(), [process]) try: timer.start() - output = p.communicate()[0].decode("utf-8") + output = process.communicate()[0].decode("utf-8") finally: if not timer.is_alive(): timed_out = True @@ -290,7 +290,7 @@ def _run_multienum(self): raise TimeoutError("Enumeration took too long") else: - output = p.communicate()[0].decode("utf-8") + output = process.communicate()[0].decode("utf-8") count = 0 start_count = False diff --git a/pymatgen/command_line/mcsqs_caller.py b/pymatgen/command_line/mcsqs_caller.py index 657060d6dec..dd1cca70b1c 100644 --- a/pymatgen/command_line/mcsqs_caller.py +++ b/pymatgen/command_line/mcsqs_caller.py @@ -178,8 +178,8 @@ def _parse_sqs_path(path) -> Sqs: detected_instances = len(list(path.glob("bestsqs*[0-9]*.out"))) # Convert best SQS structure to CIF file and pymatgen Structure - with Popen("str2cif < bestsqs.out > bestsqs.cif", shell=True, cwd=path) as p: - p.communicate() + with Popen("str2cif < bestsqs.out > bestsqs.cif", shell=True, cwd=path) as process: + process.communicate() with warnings.catch_warnings(): warnings.simplefilter("ignore") @@ -200,8 +200,8 @@ def _parse_sqs_path(path) -> Sqs: sqs_out = f"bestsqs{idx + 1}.out" sqs_cif = f"bestsqs{idx + 1}.cif" corr_out = f"bestcorr{idx + 1}.out" - with Popen(f"str2cif < {sqs_out} > {sqs_cif}", shell=True, cwd=path) as p: - p.communicate() + with Popen(f"str2cif < {sqs_out} > {sqs_cif}", shell=True, cwd=path) as process: + process.communicate() sqs = Structure.from_file(path / sqs_out) with open(path / corr_out) as file: lines = file.readlines() diff --git a/pymatgen/core/bonds.py b/pymatgen/core/bonds.py index ac3c4b7bbf6..7faed475c54 100644 --- a/pymatgen/core/bonds.py +++ b/pymatgen/core/bonds.py @@ -228,4 +228,4 @@ def get_bond_length( f"No order {bond_order} bond lengths between {sp1} and {sp2} found in " "database. Returning sum of atomic radius." ) - return sp1.atomic_radius + sp2.atomic_radius # type: ignore + return sp1.atomic_radius + sp2.atomic_radius # type: ignore[operator] diff --git a/pymatgen/core/composition.py b/pymatgen/core/composition.py index d3d498806ce..533a8ab58a6 100644 --- a/pymatgen/core/composition.py +++ b/pymatgen/core/composition.py @@ -81,19 +81,19 @@ class Composition(collections.abc.Hashable, collections.abc.Mapping, MSONable, S # Special formula handling for peroxides and certain elements. This is so # that formula output does not write LiO instead of Li2O2 for example. - special_formulas: ClassVar[dict[str, str]] = dict( - LiO="Li2O2", - NaO="Na2O2", - KO="K2O2", - HO="H2O2", - CsO="Cs2O2", - RbO="Rb2O2", - O="O2", - N="N2", - F="F2", - Cl="Cl2", - H="H2", - ) + special_formulas: ClassVar[dict[str, str]] = { + "LiO": "Li2O2", + "NaO": "Na2O2", + "KO": "K2O2", + "HO": "H2O2", + "CsO": "Cs2O2", + "RbO": "Rb2O2", + "O": "O2", + "N": "N2", + "F": "F2", + "Cl": "Cl2", + "H": "H2", + } oxi_prob = None # prior probability of oxidation used by oxi_state_guesses @@ -1137,7 +1137,7 @@ def _parse_chomp_and_rank(match, formula: str, m_dict: dict[str, float], m_point el = match[1] if len(el) > 2 or len(el) < 1: raise ValueError("Invalid element symbol entered!") - amt = float(match.group(2)) if match.group(2).strip() != "" else 1 + amt = float(match[2]) if match[2].strip() != "" else 1 # convert the element string to proper [uppercase,lowercase] format # and award points if it is already in that format diff --git a/pymatgen/core/interface.py b/pymatgen/core/interface.py index d7d5c8eccf3..badc0d6bfc6 100644 --- a/pymatgen/core/interface.py +++ b/pymatgen/core/interface.py @@ -698,7 +698,7 @@ def gb_from_parameters( list(top_grain.frac_coords) + list(bottom_grain.frac_coords), ) t_and_b_dis = t_and_b.lattice.get_all_distances( - t_and_b.frac_coords[0:n_sites], t_and_b.frac_coords[n_sites : n_sites * 2] + t_and_b.frac_coords[:n_sites], t_and_b.frac_coords[n_sites : n_sites * 2] ) index_incident = np.nonzero(t_and_b_dis < np.min(t_and_b_dis) + tol_coi) diff --git a/pymatgen/core/lattice.py b/pymatgen/core/lattice.py index 50fcb50b22c..5448c09813a 100644 --- a/pymatgen/core/lattice.py +++ b/pymatgen/core/lattice.py @@ -1504,7 +1504,7 @@ def get_points_in_sphere_old( center = np.array(center) # Prepare the list of output atoms - n = len(frac_points) # type: ignore + n = len(frac_points) frac_coords = np.array(frac_points) % 1 indices = np.arange(n) @@ -1623,13 +1623,13 @@ def get_distance_and_image( """ if jimage is None: v, d2 = pbc_shortest_vectors(self, frac_coords1, frac_coords2, return_d2=True) - fc = self.get_fractional_coords(v[0][0]) + frac_coords1 - frac_coords2 # type: ignore + fc = self.get_fractional_coords(v[0][0]) + frac_coords1 - frac_coords2 fc = np.array(np.round(fc), dtype=int) return np.sqrt(d2[0, 0]), fc jimage = np.array(jimage) - mapped_vec = self.get_cartesian_coords(jimage + frac_coords2 - frac_coords1) # type: ignore - return np.linalg.norm(mapped_vec), jimage # type: ignore + mapped_vec = self.get_cartesian_coords(jimage + frac_coords2 - frac_coords1) + return np.linalg.norm(mapped_vec), jimage def get_miller_index_from_coords( self, @@ -1660,7 +1660,7 @@ def get_miller_index_from_coords( tuple: The Miller index. """ if coords_are_cartesian: - coords = [self.get_fractional_coords(c) for c in coords] # type: ignore + coords = [self.get_fractional_coords(c) for c in coords] coords = np.asarray(coords) g = coords.sum(axis=0) / coords.shape[0] @@ -1837,12 +1837,12 @@ def get_points_in_spheres( valid_images = np.concatenate(valid_images, axis=0) else: - valid_coords = all_coords # type: ignore + valid_coords = all_coords valid_images = [[0, 0, 0]] * len(valid_coords) - valid_indices = np.arange(len(valid_coords)) # type: ignore + valid_indices = np.arange(len(valid_coords)) # Divide the valid 3D space into cubes and compute the cube ids - all_cube_index = _compute_cube_index(valid_coords, global_min, r) # type: ignore + all_cube_index = _compute_cube_index(valid_coords, global_min, r) nx, ny, nz = _compute_cube_index(global_max, global_min, r) + 1 all_cube_index = _three_to_one(all_cube_index, ny, nz) site_cube_index = _three_to_one(_compute_cube_index(center_coords, global_min, r), ny, nz) diff --git a/pymatgen/core/operations.py b/pymatgen/core/operations.py index a96be8d2c09..54f24f8515b 100644 --- a/pymatgen/core/operations.py +++ b/pymatgen/core/operations.py @@ -367,7 +367,7 @@ def reflection(normal: ArrayLike, origin: ArrayLike = (0, 0, 0)) -> SymmOp: u, v, w = normal translation = np.eye(4) - translation[0:3, 3] = -np.array(origin) + translation[:3, 3] = -np.array(origin) xx = 1 - 2 * u**2 yy = 1 - 2 * v**2 @@ -394,7 +394,7 @@ def inversion(origin: ArrayLike = (0, 0, 0)) -> SymmOp: """ mat = -np.eye(4) mat[3, 3] = 1 - mat[0:3, 3] = 2 * np.array(origin) + mat[:3, 3] = 2 * np.array(origin) return SymmOp(mat) @staticmethod diff --git a/pymatgen/core/periodic_table.py b/pymatgen/core/periodic_table.py index d21a33e4129..f26cff49a01 100644 --- a/pymatgen/core/periodic_table.py +++ b/pymatgen/core/periodic_table.py @@ -1208,7 +1208,8 @@ def get_shannon_radius( Shannon radius for specie in the specified environment. """ radii = self._el.data["Shannon radii"] - radii = radii[str(int(self._oxi_state))][cn] # type: ignore + assert self._oxi_state is not None + radii = radii[str(int(self._oxi_state))][cn] if len(radii) == 1: key, data = next(iter(radii.items())) if key != spin: @@ -1247,7 +1248,8 @@ def get_crystal_field_spin( if len(elec) < 4 or elec[-1][1] != "s" or elec[-2][1] != "d": raise AttributeError(f"Invalid element {self.symbol} for crystal field calculation") - n_electrons = elec[-1][2] + elec[-2][2] - self.oxi_state # type: ignore + assert self.oxi_state is not None + n_electrons = elec[-1][2] + elec[-2][2] - self.oxi_state if n_electrons < 0 or n_electrons > 10: raise AttributeError(f"Invalid oxidation state {self.oxi_state} for element {self.symbol}") @@ -1504,13 +1506,13 @@ def get_el_sp(obj: int | SpeciesLike) -> Element | Species | DummySpecies: Species | Element: with a bias for the maximum number of properties that can be determined. """ - # if obj is already an Element or Species, return as is + # If obj is already an Element or Species, return as is if isinstance(obj, (Element, Species, DummySpecies)): if getattr(obj, "_is_named_isotope", None): return Element(obj.name) if isinstance(obj, Element) else Species(str(obj)) return obj - # if obj is an integer, return the Element with atomic number obj + # If obj is an integer, return the Element with atomic number obj try: flt = float(obj) assert flt == int(flt) @@ -1518,22 +1520,22 @@ def get_el_sp(obj: int | SpeciesLike) -> Element | Species | DummySpecies: except (AssertionError, ValueError, TypeError, KeyError): pass - # if obj is a string, attempt to parse it as a Species + # If obj is a string, attempt to parse it as a Species try: - return Species.from_str(obj) # type: ignore + return Species.from_str(obj) # type: ignore[arg-type] except (ValueError, TypeError, KeyError): pass - # if Species parsing failed, try Element + # If Species parsing failed, try Element try: - return Element(obj) # type: ignore + return Element(obj) # type: ignore[arg-type] except (ValueError, TypeError, KeyError): pass - # if Element parsing failed, try DummySpecies + # If Element parsing failed, try DummySpecies try: - return DummySpecies.from_str(obj) # type: ignore - except Exception: - raise ValueError(f"Can't parse Element or Species from {obj!r}") + return DummySpecies.from_str(obj) # type: ignore[arg-type] + except Exception as exc: + raise ValueError(f"Can't parse Element or Species from {obj!r}") from exc @unique diff --git a/pymatgen/core/structure.py b/pymatgen/core/structure.py index 0d040a88fe4..f387dc0fd6b 100644 --- a/pymatgen/core/structure.py +++ b/pymatgen/core/structure.py @@ -2952,7 +2952,7 @@ def from_id(cls, id_: str, source: StructureSources = "Materials Project", **kwa from pymatgen.ext.matproj import MPRester mpr = MPRester(**kwargs) - return mpr.get_structure_by_material_id(id_) # type: ignore + return mpr.get_structure_by_material_id(id_) # type: ignore[attr-defined] if source == "COD": from pymatgen.ext.cod import COD @@ -3961,7 +3961,7 @@ def __setitem__( # type: ignore[override] structure[(0, 2, 3)] = "Fe" Replaces sites 0, 2 and 3 with Fe. - structure[0::2] = "Fe" + structure[::2] = "Fe" Replaces all even index sites with Fe. structure["Mn"] = "Fe" diff --git a/pymatgen/core/tensors.py b/pymatgen/core/tensors.py index 35152d195bf..cb7234cc6ed 100644 --- a/pymatgen/core/tensors.py +++ b/pymatgen/core/tensors.py @@ -139,7 +139,7 @@ def einsum_sequence( ) -> NDArray: """Calculate the result of an einstein summation expression.""" if not isinstance(other_arrays, list): - raise ValueError("other tensors must be list of tensors or tensor input") + raise TypeError("other tensors must be list of tensors or tensor input") other_arrays = [np.array(a) for a in other_arrays] if not einsum_string: @@ -356,7 +356,7 @@ def is_voigt_symmetric(self, tol: float = 1e-6) -> bool: transpose_pieces[n] += [transpose_pieces[n][0][::-1]] for trans_seq in itertools.product(*transpose_pieces): transpose_seq = list(itertools.chain(*trans_seq)) - if (self - self.transpose(transpose_seq) > tol).any(): # type: ignore + if (self - self.transpose(transpose_seq) > tol).any(): return False return True diff --git a/pymatgen/electronic_structure/boltztrap.py b/pymatgen/electronic_structure/boltztrap.py index a0de391a7d5..fe4d8ce2649 100644 --- a/pymatgen/electronic_structure/boltztrap.py +++ b/pymatgen/electronic_structure/boltztrap.py @@ -611,14 +611,11 @@ def run( bt_exe.append("-so") with subprocess.Popen( - bt_exe, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - stderr=subprocess.PIPE, - ) as p: - p.wait() - - for c in p.communicate(): + bt_exe, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE + ) as process: + process.wait() + + for c in process.communicate(): logging.info(c.decode()) if "error in factorization" in c.decode(): raise BoltztrapError("error in factorization") @@ -870,7 +867,7 @@ def get_symm_bands(self, structure: Structure, efermi, kpt_line=None, labels_dic w: list[bool] = [] prec = 1e-5 while len(w) == 0: - w = np.where(np.all(np.abs(kp - self._bz_kpoints) < [prec] * 3, axis=1))[0] # type: ignore + w = np.where(np.all(np.abs(kp - self._bz_kpoints) < [prec] * 3, axis=1))[0] prec *= 10 _idx_list.append((idx, w[0])) @@ -878,7 +875,7 @@ def get_symm_bands(self, structure: Structure, efermi, kpt_line=None, labels_dic idx_list = np.array(_idx_list) bz_bands_in_eV = (self._bz_bands * Energy(1, "Ry").to("eV") + efermi).T - bands_dict = {Spin.up: bz_bands_in_eV[:, idx_list[:, 1]].tolist()} # type: ignore + bands_dict = {Spin.up: bz_bands_in_eV[:, idx_list[:, 1]].tolist()} return BandStructureSymmLine( kpt_line, bands_dict, structure.lattice.reciprocal_lattice, efermi, labels_dict=labels_dict diff --git a/pymatgen/electronic_structure/cohp.py b/pymatgen/electronic_structure/cohp.py index bd1fa4b794f..b641d2a3992 100644 --- a/pymatgen/electronic_structure/cohp.py +++ b/pymatgen/electronic_structure/cohp.py @@ -172,7 +172,7 @@ def has_antibnd_states_below_efermi(self, spin=None, limit=0.01): if spin is None: dict_to_return = {} for sp, cohp_vals in populations.items(): - if (max(cohp_vals[0:n_energies_below_efermi])) > limit: + if (max(cohp_vals[:n_energies_below_efermi])) > limit: dict_to_return[sp] = True else: dict_to_return[sp] = False @@ -182,7 +182,7 @@ def has_antibnd_states_below_efermi(self, spin=None, limit=0.01): spin = Spin(spin) elif isinstance(spin, str): spin = Spin({"up": 1, "down": -1}[spin.lower()]) - if (max(populations[spin][0:n_energies_below_efermi])) > limit: + if (max(populations[spin][:n_energies_below_efermi])) > limit: dict_to_return[spin] = True else: dict_to_return[spin] = False diff --git a/pymatgen/electronic_structure/dos.py b/pymatgen/electronic_structure/dos.py index be074213ca6..43605e08ade 100644 --- a/pymatgen/electronic_structure/dos.py +++ b/pymatgen/electronic_structure/dos.py @@ -558,7 +558,7 @@ def get_fermi( for _ in range(precision): fermi_range = np.arange(-nstep, nstep + 1) * step + fermi calc_doping = np.array([self.get_doping(fermi_lvl, temperature) for fermi_lvl in fermi_range]) - relative_error = np.abs(calc_doping / concentration - 1.0) # type: ignore + relative_error = np.abs(calc_doping / concentration - 1.0) fermi = fermi_range[np.argmin(relative_error)] step /= 10.0 @@ -809,16 +809,12 @@ def get_band_filling( if elements: for idx, el in enumerate(elements): spd_dos = self.get_element_spd_dos(el)[band] - densities = ( - spd_dos.densities if idx == 0 else add_densities(densities, spd_dos.densities) # type: ignore - ) + densities = spd_dos.densities if idx == 0 else add_densities(densities, spd_dos.densities) dos = Dos(self.efermi, self.energies, densities) elif sites: for idx, site in enumerate(sites): spd_dos = self.get_site_spd_dos(site)[band] - densities = ( - spd_dos.densities if idx == 0 else add_densities(densities, spd_dos.densities) # type: ignore - ) + densities = spd_dos.densities if idx == 0 else add_densities(densities, spd_dos.densities) dos = Dos(self.efermi, self.energies, densities) else: dos = self.get_spd_dos()[band] @@ -1092,7 +1088,7 @@ def get_upper_band_edge( def get_dos_fp( self, - type: str = "summed_pdos", + type: str = "summed_pdos", # noqa: A002 binning: bool = True, min_e: float | None = None, max_e: float | None = None, @@ -1169,7 +1165,7 @@ class fingerprint(NamedTuple): dos_rebin = np.zeros(ener.shape) - for ii, e1, e2 in zip(range(len(ener)), ener_bounds[0:-1], ener_bounds[1:]): + for ii, e1, e2 in zip(range(len(ener)), ener_bounds[:-1], ener_bounds[1:]): inds = np.where((energies >= e1) & (energies < e2)) dos_rebin[ii] = np.sum(densities[inds]) if normalize: # scale DOS bins to make area under histogram equal 1 @@ -1283,9 +1279,7 @@ def as_dict(self) -> dict: for at in self.structure: dd = {} for orb, pdos in self.pdos[at].items(): - dd[str(orb)] = { - "densities": {str(int(spin)): list(dens) for spin, dens in pdos.items()} # type: ignore - } + dd[str(orb)] = {"densities": {str(int(spin)): list(dens) for spin, dens in pdos.items()}} dct["pdos"].append(dd) dct["atom_dos"] = {str(at): dos.as_dict() for at, dos in self.get_element_dos().items()} dct["spd_dos"] = {str(orb): dos.as_dict() for orb, dos in self.get_spd_dos().items()} @@ -1298,7 +1292,7 @@ def __str__(self) -> str: class LobsterCompleteDos(CompleteDos): """Extended CompleteDOS for Lobster.""" - def get_site_orbital_dos(self, site: PeriodicSite, orbital: str) -> Dos: # type: ignore + def get_site_orbital_dos(self, site: PeriodicSite, orbital: str) -> Dos: # type: ignore[override] """Get the Dos for a particular orbital of a particular site. Args: @@ -1312,7 +1306,7 @@ def get_site_orbital_dos(self, site: PeriodicSite, orbital: str) -> Dos: # type Returns: Dos containing densities of an orbital of a specific site. """ - if orbital[1:] not in [ + if orbital[1:] not in { "s", "p_y", "p_z", @@ -1329,9 +1323,9 @@ def get_site_orbital_dos(self, site: PeriodicSite, orbital: str) -> Dos: # type "f_xz^2", "f_z(x^2-y^2)", "f_x(x^2-3y^2)", - ]: + }: raise ValueError("orbital is not correct") - return Dos(self.efermi, self.energies, self.pdos[site][orbital]) # type: ignore + return Dos(self.efermi, self.energies, self.pdos[site][orbital]) # type: ignore[index] def get_site_t2g_eg_resolved_dos(self, site: PeriodicSite) -> dict[str, Dos]: """Get the t2g, eg projected DOS for a particular site. @@ -1358,7 +1352,7 @@ def get_site_t2g_eg_resolved_dos(self, site: PeriodicSite) -> dict[str, Dos]: "e_g": Dos(self.efermi, self.energies, functools.reduce(add_densities, eg_dos)), } - def get_spd_dos(self) -> dict[str, Dos]: # type: ignore + def get_spd_dos(self) -> dict[OrbitalType, Dos]: """Get orbital projected Dos. For example, if 3s and 4s are included in the basis of some element, they will be both summed in the orbital projected DOS. @@ -1367,6 +1361,7 @@ def get_spd_dos(self) -> dict[str, Dos]: # type: ignore dict of {orbital: Dos}, e.g. {"s": Dos object, ...} """ spd_dos = {} + orb = None for atom_dos in self.pdos.values(): for orb, pdos in atom_dos.items(): orbital_type = _get_orb_type_lobster(orb) @@ -1375,9 +1370,9 @@ def get_spd_dos(self) -> dict[str, Dos]: # type: ignore else: spd_dos[orbital_type] = add_densities(spd_dos[orbital_type], pdos) - return {orb: Dos(self.efermi, self.energies, densities) for orb, densities in spd_dos.items()} # type: ignore + return {orb: Dos(self.efermi, self.energies, densities) for orb, densities in spd_dos.items()} # type: ignore[misc] - def get_element_spd_dos(self, el: SpeciesLike) -> dict[str, Dos]: # type: ignore + def get_element_spd_dos(self, el: SpeciesLike) -> dict[OrbitalType, Dos]: """Get element and spd projected Dos. Args: @@ -1397,7 +1392,7 @@ def get_element_spd_dos(self, el: SpeciesLike) -> dict[str, Dos]: # type: ignor else: el_dos[orbital_type] = add_densities(el_dos[orbital_type], pdos) - return {orb: Dos(self.efermi, self.energies, densities) for orb, densities in el_dos.items()} # type: ignore + return {orb: Dos(self.efermi, self.energies, densities) for orb, densities in el_dos.items()} # type: ignore[misc] @classmethod def from_dict(cls, dct: dict) -> Self: diff --git a/pymatgen/electronic_structure/plotter.py b/pymatgen/electronic_structure/plotter.py index 29dae3e718d..f4cfa52be78 100644 --- a/pymatgen/electronic_structure/plotter.py +++ b/pymatgen/electronic_structure/plotter.py @@ -289,7 +289,7 @@ def _check_bs_kpath(self, band_structs: list[BandStructureSymmLine]) -> Literal[ # check obj type for bs in band_structs: if not isinstance(bs, BandStructureSymmLine): - raise ValueError( + raise TypeError( "BSPlotter only works with BandStructureSymmLine objects. " "A BandStructure object (on a uniform grid for instance and " "not along symmetry lines won't work)" @@ -1290,7 +1290,7 @@ def _get_projections_by_branches_patom_pmorb(self, dictio, dictpa, sum_atoms, su raise ValueError("The 'selected_branches' is empty. We cannot do anything.") for index in selected_branches: if not isinstance(index, int): - raise ValueError( + raise TypeError( "You do not give a correct type of index of symmetry lines. It should be 'int' type" ) if index > n_branches or index < 1: @@ -1777,7 +1777,7 @@ def _Orbitals_SumOrbitals(cls, dictio, sum_morbs): raise ValueError(f"The dictio[{elt}] is empty. We cannot do anything") for orb in dictio[elt]: if not isinstance(orb, str): - raise ValueError( + raise TypeError( f"The invalid format of orbitals is in 'dictio[{elt}]': {orb}. They should be string." ) if orb not in all_orbitals: @@ -1902,8 +1902,8 @@ def _number_of_subfigures(self, dictio, dictpa, sum_atoms, sum_morbs): raise ValueError(f"The dictpa[{elt}] is empty. We cannot do anything") _sites = self._bs.structure.sites indices = [] - for site_idx in range(len(_sites)): - if next(iter(_sites[site_idx]._species)) == Element(elt): + for site_idx, site in enumerate(_sites): + if next(iter(site._species)) == Element(elt): indices.append(site_idx + 1) for number in dictpa[elt]: if isinstance(number, str): @@ -1917,7 +1917,7 @@ def _number_of_subfigures(self, dictio, dictpa, sum_atoms, sum_morbs): if number not in indices: raise ValueError(f"You put wrong site numbers in 'dictpa[{elt}]': {number}.") else: - raise ValueError(f"You put wrong site numbers in 'dictpa[{elt}]': {number}.") + raise TypeError(f"You put wrong site numbers in 'dictpa[{elt}]': {number}.") nelems = Counter(dictpa[elt]).values() if sum(nelems) > len(nelems): raise ValueError(f"You put at least two similar site numbers into 'dictpa[{elt}]'.") @@ -1949,8 +1949,8 @@ def _number_of_subfigures(self, dictio, dictpa, sum_atoms, sum_morbs): raise ValueError(f"The sum_atoms[{elt}] is empty. We cannot do anything") _sites = self._bs.structure.sites indices = [] - for site_idx in range(len(_sites)): - if next(iter(_sites[site_idx]._species)) == Element(elt): + for site_idx, site in enumerate(_sites): + if next(iter(site._species)) == Element(elt): indices.append(site_idx + 1) for number in sum_atoms[elt]: if isinstance(number, str): @@ -1968,7 +1968,8 @@ def _number_of_subfigures(self, dictio, dictpa, sum_atoms, sum_morbs): f"mentioned in dicpta[{elt}]" ) else: - raise ValueError(f"You put wrong site numbers in 'sum_atoms[{elt}]'.") + raise TypeError(f"You put wrong site numbers in 'sum_atoms[{elt}]'.") + nelems = Counter(sum_atoms[elt]).values() if sum(nelems) > len(nelems): raise ValueError(f"You put at least two similar site numbers into 'sum_atoms[{elt}]'.") @@ -2363,7 +2364,7 @@ def get_plot( left_kpoint = bs.kpoints[branch["start_index"]].cart_coords right_kpoint = bs.kpoints[branch["end_index"]].cart_coords distance = np.linalg.norm(right_kpoint - left_kpoint) - xlabel_distances.append(xlabel_distances[-1] + distance) # type: ignore + xlabel_distances.append(xlabel_distances[-1] + distance) # add x-coordinates for kpoint data npts = branch["end_index"] - branch["start_index"] @@ -2411,7 +2412,7 @@ def get_plot( band_energies[spin] = [] for band in bs.bands[spin]: band = cast(list[float], band) - band_energies[spin].append([e - bs.efermi for e in band]) # type: ignore + band_energies[spin].append([e - bs.efermi for e in band]) # type: ignore[arg-type] # renormalize the DOS energies to Fermi level dos_energies = [e - dos.efermi for e in dos.energies] if dos else [] @@ -2446,7 +2447,7 @@ def get_plot( if spin in dos.densities: # plot the total DOS dos_densities = dos.densities[spin] * int(spin) - label = "total" if spin == Spin.up else None + label: str | None = "total" if spin == Spin.up else None dos_ax.plot(dos_densities, dos_energies, color=(0.6, 0.6, 0.6), label=label) dos_ax.fill_betweenx( dos_energies, @@ -2480,7 +2481,7 @@ def get_plot( for idx, orb in enumerate([OrbitalType.s, OrbitalType.p, OrbitalType.d, OrbitalType.f]): if orb in spd_dos: dos_densities = spd_dos[orb].densities[spin] * int(spin) - label = orb if spin == Spin.up else None # type: ignore + label = orb if spin == Spin.up else None # type: ignore[assignment] dos_ax.plot( dos_densities, dos_energies, @@ -2671,7 +2672,7 @@ def _cmyk_triangle(ax, c_label, m_label, y_label, k_label, loc) -> None: inset_ax.set_ylim([-0.35, 1.00]) # add the labels - common = dict(fontsize=13, family="Times New Roman") + common = {"fontsize": 13, "family": "Times New Roman"} inset_ax.text(0.70, -0.2, m_label, **common, color=(0, 0, 0), horizontalalignment="left") inset_ax.text(0.325, 0.70, c_label, **common, color=(0, 0, 0), horizontalalignment="center") inset_ax.text(-0.05, -0.2, y_label, **common, color=(0, 0, 0), horizontalalignment="right") diff --git a/pymatgen/entries/compatibility.py b/pymatgen/entries/compatibility.py index fcfc8982d51..8108b788b7b 100644 --- a/pymatgen/entries/compatibility.py +++ b/pymatgen/entries/compatibility.py @@ -9,7 +9,7 @@ import os import warnings from collections import defaultdict -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union, cast import numpy as np from monty.design_patterns import cached_class @@ -306,7 +306,7 @@ def get_correction(self, entry) -> ufloat: correction += ox_corr * comp["O"] elif hasattr(entry, "structure"): - ox_type, n_bonds = oxide_type(entry.structure, 1.05, return_nbonds=True) # type: ignore + ox_type, n_bonds = cast(tuple[str, int], oxide_type(entry.structure, 1.05, return_nbonds=True)) if ox_type in self.oxide_correction: correction += self.oxide_correction[ox_type] * n_bonds elif ox_type == "hydroxide": @@ -603,7 +603,7 @@ def process_entries( adjustments = self.get_adjustments(entry) except CompatibilityError as exc: if on_error == "raise": - raise exc + raise if on_error == "warn": warnings.warn(str(exc)) continue diff --git a/pymatgen/entries/correction_calculator.py b/pymatgen/entries/correction_calculator.py index 153c71a4b59..e832a0576c0 100644 --- a/pymatgen/entries/correction_calculator.py +++ b/pymatgen/entries/correction_calculator.py @@ -359,7 +359,7 @@ def graph_residual_error_per_species(self, specie: str) -> go.Figure: return fig - def make_yaml(self, name: str = "MP2020", dir: str | None = None) -> None: + def make_yaml(self, name: str = "MP2020", dir: str | None = None) -> None: # noqa: A002 """Create the _name_Compatibility.yaml that stores corrections as well as _name_CompatibilityUncertainties.yaml for correction uncertainties. diff --git a/pymatgen/entries/entry_tools.py b/pymatgen/entries/entry_tools.py index da2903f0d20..6fe98612ca5 100644 --- a/pymatgen/entries/entry_tools.py +++ b/pymatgen/entries/entry_tools.py @@ -112,7 +112,7 @@ def group_entries_by_structure( """ if comparator is None: comparator = SpeciesComparator() - start = datetime.datetime.now() + start = datetime.datetime.now(tz=datetime.timezone.utc) logger.info(f"Started at {start}") entries_host = [(entry, _get_host(entry.structure, species_to_remove)) for entry in entries] if ncpus: @@ -123,9 +123,9 @@ def group_entries_by_structure( logging.info(f"Using {ncpus} cpus") manager = mp.Manager() groups = manager.list() - with mp.Pool(ncpus) as p: + with mp.Pool(ncpus) as pool: # Parallel processing only supports Python primitives and not objects. - p.map( + pool.map( _perform_grouping, [ ( @@ -161,8 +161,8 @@ def group_entries_by_structure( entry_groups = [] for g in groups: entry_groups.append(json.loads(g, cls=MontyDecoder)) - logging.info(f"Finished at {datetime.datetime.now()}") - logging.info(f"Took {datetime.datetime.now() - start}") + logging.info(f"Finished at {datetime.datetime.now(tz=datetime.timezone.utc)}") + logging.info(f"Took {datetime.datetime.now(tz=datetime.timezone.utc) - start}") return entry_groups diff --git a/pymatgen/ext/cod.py b/pymatgen/ext/cod.py index e695a56a4d7..21983b6891f 100644 --- a/pymatgen/ext/cod.py +++ b/pymatgen/ext/cod.py @@ -76,7 +76,7 @@ def get_cod_ids(self, formula) -> list[int]: cod_ids = [] for line in text: if match := re.search(r"(\d+)", line): - cod_ids.append(int(match.group(1))) + cod_ids.append(int(match[1])) return cod_ids def get_structure_by_id(self, cod_id: int, timeout: int = 600, **kwargs) -> Structure: diff --git a/pymatgen/ext/matproj.py b/pymatgen/ext/matproj.py index a7ccd0801b3..a7c4318a440 100644 --- a/pymatgen/ext/matproj.py +++ b/pymatgen/ext/matproj.py @@ -253,7 +253,7 @@ def get_initial_structures_by_material_id( response = self.request(f"materials/summary/{material_id}/?_fields={prop}") structures = response[0][prop] if conventional_unit_cell: - return [SpacegroupAnalyzer(s).get_conventional_standard_structure() for s in structures] # type: ignore + return [SpacegroupAnalyzer(s).get_conventional_standard_structure() for s in structures] return structures def get_entries( diff --git a/pymatgen/ext/matproj_legacy.py b/pymatgen/ext/matproj_legacy.py index 62fc26dd9b0..26b28e3ed42 100644 --- a/pymatgen/ext/matproj_legacy.py +++ b/pymatgen/ext/matproj_legacy.py @@ -1014,8 +1014,8 @@ def query( break except MPRestError as exc: if match := re.search(r"error status code (\d+)", str(exc)): - if not match.group(1).startswith("5"): - raise exc + if not match[1].startswith("5"): + raise n_tries += 1 print( "Unknown server error. Trying again in five " @@ -1606,7 +1606,7 @@ def parse_sym(sym): return [el.symbol for el in Element] if match := re.match(r"\{(.*)\}", sym): - return [s.strip() for s in match.group(1).split(",")] + return [s.strip() for s in match[1].split(",")] return [sym] def parse_tok(t): diff --git a/pymatgen/ext/optimade.py b/pymatgen/ext/optimade.py index 6fbd1d18a05..2f5c1345429 100644 --- a/pymatgen/ext/optimade.py +++ b/pymatgen/ext/optimade.py @@ -356,10 +356,10 @@ def get_snls_with_filter( if structures: all_snls[identifier] = structures - except Exception as exc: + except Exception: # TODO: manually inspect failures to either (a) correct a bug or (b) raise more appropriate error - _logger.error(f"Could not retrieve required information from provider {identifier} and {url=}: {exc}") + _logger.exception(f"Could not retrieve required information from provider {identifier} and {url=}") return all_snls @@ -520,8 +520,8 @@ def _parse_provider(self, provider: str, provider_url: str) -> dict[str, Provide try: url = urljoin(provider_url, "v1/links") provider_link_json = self._get_json(url) - except Exception as exc: - _logger.error(f"Failed to parse {url} when following links: {exc}") + except Exception: + _logger.exception(f"Failed to parse {url} when following links") return {} def _parse_provider_link(provider, provider_link_json): diff --git a/pymatgen/io/abinit/abiobjects.py b/pymatgen/io/abinit/abiobjects.py index 8be6d95af2d..e8f80107083 100644 --- a/pymatgen/io/abinit/abiobjects.py +++ b/pymatgen/io/abinit/abiobjects.py @@ -404,14 +404,14 @@ class Smearing(AbivarAble, MSONable): """ # Map string_mode to occopt - _mode2occopt: ClassVar[dict[str, int]] = dict( - nosmearing=1, - fermi_dirac=3, - marzari4=4, - marzari5=5, - methfessel=6, - gaussian=7, - ) + _mode2occopt: ClassVar[dict[str, int]] = { + "nosmearing": 1, + "fermi_dirac": 3, + "marzari4": 4, + "marzari5": 5, + "methfessel": 6, + "gaussian": 7, + } def __init__(self, occopt, tsmear): """ @@ -510,18 +510,18 @@ class ElectronsAlgorithm(dict, AbivarAble, MSONable): """Variables controlling the SCF/NSCF algorithm.""" # None indicates that we use abinit defaults - _DEFAULT: ClassVar[dict[str, int | None]] = dict( - iprcell=None, - iscf=None, - diemac=None, - diemix=None, - diemixmag=None, - dielam=None, - diegap=None, - dielng=None, - diecut=None, - nstep=50, - ) + _DEFAULT: ClassVar[dict[str, int | None]] = { + "iprcell": None, + "iscf": None, + "diemac": None, + "diemix": None, + "diemixmag": None, + "dielam": None, + "diegap": None, + "dielng": None, + "diecut": None, + "nstep": 50, + } def __init__(self, *args, **kwargs): """ @@ -1035,17 +1035,17 @@ class RelaxationMethod(AbivarAble, MSONable): The set of variables are constructed in to_abivars depending on ionmov and optcell. """ - _default_vars: ClassVar[dict[str, Any]] = dict( - ionmov=MANDATORY, - optcell=MANDATORY, - ntime=80, - dilatmx=1.05, - ecutsm=0.5, - strfact=None, - tolmxf=None, - strtarget=None, - atoms_constraints={}, # Constraints are stored in a dictionary. {} means if no constraint is enforced. - ) + _default_vars: ClassVar[dict[str, Any]] = { + "ionmov": MANDATORY, + "optcell": MANDATORY, + "ntime": 80, + "dilatmx": 1.05, + "ecutsm": 0.5, + "strfact": None, + "tolmxf": None, + "strtarget": None, + "atoms_constraints": {}, # Constraints are stored in a dictionary. {} means if no constraint is enforced. + } IONMOV_DEFAULT = 3 OPTCELL_DEFAULT = 2 @@ -1337,14 +1337,14 @@ class Screening(AbivarAble): """ # Approximations used for W - _WTYPES: ClassVar[dict[str, int]] = dict(RPA=0) + _WTYPES: ClassVar[dict[str, int]] = {"RPA": 0} # Self-consistency modes - _SC_MODES: ClassVar[dict[str, int]] = dict( - one_shot=0, - energy_only=1, - wavefunctions=2, - ) + _SC_MODES: ClassVar[dict[str, int]] = { + "one_shot": 0, + "energy_only": 1, + "wavefunctions": 2, + } def __init__( self, @@ -1428,20 +1428,20 @@ def to_abivars(self): class SelfEnergy(AbivarAble): """Define the parameters used for the computation of the self-energy.""" - _SIGMA_TYPES: ClassVar[dict[str, int]] = dict( - gw=0, - hartree_fock=5, - sex=6, - cohsex=7, - model_gw_ppm=8, - model_gw_cd=9, - ) + _SIGMA_TYPES: ClassVar[dict[str, int]] = { + "gw": 0, + "hartree_fock": 5, + "sex": 6, + "cohsex": 7, + "model_gw_ppm": 8, + "model_gw_cd": 9, + } - _SC_MODES: ClassVar[dict[str, int]] = dict( - one_shot=0, - energy_only=1, - wavefunctions=2, - ) + _SC_MODES: ClassVar[dict[str, int]] = { + "one_shot": 0, + "energy_only": 1, + "wavefunctions": 2, + } def __init__( self, @@ -1553,7 +1553,7 @@ def to_abivars(self): # ppmodel variables if self.use_ppmodel: - abivars.update(self.ppmodel.to_abivars()) + abivars |= self.ppmodel.to_abivars() return abivars @@ -1562,18 +1562,18 @@ class ExcHamiltonian(AbivarAble): """Contain parameters for the solution of the Bethe-Salpeter equation.""" # Types of excitonic Hamiltonian. - _EXC_TYPES: ClassVar[dict[str, int]] = dict( - TDA=0, # Tamm-Dancoff approximation. - coupling=1, # Calculation with coupling. - ) + _EXC_TYPES: ClassVar[dict[str, int]] = { + "TDA": 0, # Tamm-Dancoff approximation. + "coupling": 1, # Calculation with coupling. + } # Algorithms used to compute the macroscopic dielectric function # and/or the exciton wavefunctions. - _ALGO2VAR: ClassVar[dict[str, int]] = dict( - direct_diago=1, - haydock=2, - cg=3, - ) + _ALGO2VAR: ClassVar[dict[str, int]] = { + "direct_diago": 1, + "haydock": 2, + "cg": 3, + } # Options specifying the treatment of the Coulomb term. _COULOMB_MODES = ("diago", "full", "model_df") diff --git a/pymatgen/io/abinit/abitimer.py b/pymatgen/io/abinit/abitimer.py index 3f034c307fb..0505b03bdac 100644 --- a/pymatgen/io/abinit/abitimer.py +++ b/pymatgen/io/abinit/abitimer.py @@ -653,10 +653,7 @@ def ncpus(self): def get_section(self, section_name): """Return section associated to `section_name`.""" - try: - idx = self.section_names.index(section_name) - except Exception: - raise + idx = self.section_names.index(section_name) sect = self.sections[idx] assert sect.name == section_name return sect @@ -721,7 +718,7 @@ def get_values(self, keys): values.append([sec.__dict__[key] for sec in self.sections]) return values - def names_and_values(self, key, minval=None, minfract=None, sorted=True): + def names_and_values(self, key, minval=None, minfract=None, sorted=True): # noqa: A002 """Select the entries whose value[key] is >= minval or whose fraction[key] is >= minfract Return the names of the sections and the corresponding values. """ diff --git a/pymatgen/io/abinit/inputs.py b/pymatgen/io/abinit/inputs.py index cce399da66e..9b7c06940fa 100644 --- a/pymatgen/io/abinit/inputs.py +++ b/pymatgen/io/abinit/inputs.py @@ -1097,7 +1097,7 @@ def from_inputs(cls, inputs: list[BasicAbinitInput]) -> Self: return multi @classmethod - def replicate_input(cls, input, ndtset): + def replicate_input(cls, input, ndtset): # noqa: A002 """Construct a multidataset with ndtset from the BasicAbinitInput input.""" multi = cls(input.structure, input.pseudos, ndtset=ndtset) diff --git a/pymatgen/io/abinit/netcdf.py b/pymatgen/io/abinit/netcdf.py index 92e06620ea3..ab7aea8074a 100644 --- a/pymatgen/io/abinit/netcdf.py +++ b/pymatgen/io/abinit/netcdf.py @@ -101,7 +101,7 @@ def __enter__(self) -> Self: """Activated when used in the with statement.""" return self - def __exit__(self, type, value, traceback): + def __exit__(self, type, value, traceback): # noqa: A002 """Activated at the end of the with statement. It automatically closes the file.""" self.rootgrp.close() @@ -315,7 +315,7 @@ def structure_from_ncdata(ncdata, site_properties=None, cls=Structure): znucl_type = ncdata.read_value("atomic_numbers") - # type_atom[0:natom] --> index Between 1 and number of atom species + # type_atom[:natom] --> index Between 1 and number of atom species type_atom = ncdata.read_value("atom_species") # Fortran to C index and float --> int conversion. @@ -446,7 +446,7 @@ def __init__(self, name, doc, etsf_name=None): ), # _H(type(pawrhoij_type), allocatable :: pawrhoij(:) ! EVOLVING variable, only for paw ) -_HDR_VARIABLES = {h.name: h for h in _HDR_VARIABLES} # type: ignore +_HDR_VARIABLES = {h.name: h for h in _HDR_VARIABLES} # type: ignore[assignment] class AbinitHeader(AttrDict): diff --git a/pymatgen/io/abinit/pseudos.py b/pymatgen/io/abinit/pseudos.py index a0b3f2b71dd..3934d727294 100644 --- a/pymatgen/io/abinit/pseudos.py +++ b/pymatgen/io/abinit/pseudos.py @@ -666,20 +666,20 @@ def _int_from_str(string): class NcAbinitHeader(AbinitHeader): """The abinit header found in the NC pseudopotential files.""" - _VARS: ClassVar[dict[str, tuple]] = dict( - zatom=(None, _int_from_str), - zion=(None, float), - pspdat=(None, float), - pspcod=(None, int), - pspxc=(None, int), - lmax=(None, int), - lloc=(None, int), - r2well=(None, float), - mmax=(None, float), - rchrg=(0.0, float), - fchrg=(0.0, float), - qchrg=(0.0, float), - ) + _VARS: ClassVar[dict[str, tuple]] = { + "zatom": (None, _int_from_str), + "zion": (None, float), + "pspdat": (None, float), + "pspcod": (None, int), + "pspxc": (None, int), + "lmax": (None, int), + "lloc": (None, int), + "r2well": (None, float), + "mmax": (None, float), + "rchrg": (0.0, float), + "fchrg": (0.0, float), + "qchrg": (0.0, float), + } def __init__(self, summary, **kwargs): super().__init__() @@ -857,26 +857,26 @@ def tm_header(filename, ppdesc): class PawAbinitHeader(AbinitHeader): """The abinit header found in the PAW pseudopotential files.""" - _VARS: ClassVar[dict[str, tuple]] = dict( - zatom=(None, _int_from_str), - zion=(None, float), - pspdat=(None, float), - pspcod=(None, int), - pspxc=(None, int), - lmax=(None, int), - lloc=(None, int), - mmax=(None, int), - r2well=(None, float), - pspfmt=(None, str), - creatorID=(None, int), - basis_size=(None, int), - lmn_size=(None, int), - orbitals=(None, list), - number_of_meshes=(None, int), - r_cut=(None, float), # r_cut(PAW) in the header - shape_type=(None, int), - rshape=(None, float), - ) + _VARS: ClassVar[dict[str, tuple]] = { + "zatom": (None, _int_from_str), + "zion": (None, float), + "pspdat": (None, float), + "pspcod": (None, int), + "pspxc": (None, int), + "lmax": (None, int), + "lloc": (None, int), + "mmax": (None, int), + "r2well": (None, float), + "pspfmt": (None, str), + "creatorID": (None, int), + "basis_size": (None, int), + "lmn_size": (None, int), + "orbitals": (None, list), + "number_of_meshes": (None, int), + "r_cut": (None, float), # r_cut(PAW) in the header + "shape_type": (None, int), + "rshape": (None, float), + } def __init__(self, summary, **kwargs): super().__init__() diff --git a/pymatgen/io/adf.py b/pymatgen/io/adf.py index e302530505c..557fb94507e 100644 --- a/pymatgen/io/adf.py +++ b/pymatgen/io/adf.py @@ -93,7 +93,7 @@ def __init__(self, name, options=None, subkeys=None): if len(self.subkeys) > 0: for k in subkeys: if not isinstance(k, AdfKey): - raise ValueError("Not all subkeys are ``AdfKey`` objects!") + raise TypeError("Not all subkeys are ``AdfKey`` objects!") self._sized_op = None if len(self.options) > 0: self._sized_op = isinstance(self.options[0], (list, tuple)) @@ -168,7 +168,7 @@ def has_subkey(self, subkey: str | AdfKey) -> bool: elif isinstance(subkey, AdfKey): key = subkey.key else: - raise ValueError("The subkey should be an AdfKey or a string!") + raise TypeError("The subkey should be an AdfKey or a string!") return len(self.subkeys) > 0 and key in (k.key for k in self.subkeys) def add_subkey(self, subkey): @@ -370,13 +370,13 @@ class AdfTask(MSONable): ADF does not support calculating force/gradient. """ - operations: ClassVar[dict[str, str]] = dict( - energy="Evaluate the single point energy.", - optimize="Minimize the energy by varying the molecular structure.", - frequencies="Compute second derivatives and print out an analysis of molecular vibrations.", - freq="Same as frequencies.", - numerical_frequencies="Compute molecular frequencies using numerical method.", - ) + operations: ClassVar[dict[str, str]] = { + "energy": "Evaluate the single point energy.", + "optimize": "Minimize the energy by varying the molecular structure.", + "frequencies": "Compute second derivatives and print out an analysis of molecular vibrations.", + "freq": "Same as frequencies.", + "numerical_frequencies": "Compute molecular frequencies using numerical method.", + } def __init__( self, @@ -474,7 +474,7 @@ def __str__(self): out += "\n" for block_key in self.other_directives: if not isinstance(block_key, AdfKey): - raise ValueError(f"{block_key} is not an AdfKey!") + raise TypeError(f"{block_key} is not an AdfKey!") out += str(block_key) + "\n" return out @@ -663,19 +663,19 @@ def _parse_logfile(self, logfile): for line in file: if match := error_patt.search(line): self.is_failed = True - self.error = match.group(1) + self.error = match[1] break if self.run_type is None: if match := run_type_patt.search(line): - if match.group(1) == "FREQUENCIES": + if match[1] == "FREQUENCIES": self.freq_type = "Numerical" self.run_type = "NumericalFreq" - elif match.group(1) == "GEOMETRY OPTIMIZATION": + elif match[1] == "GEOMETRY OPTIMIZATION": self.run_type = "GeometryOptimization" - elif match.group(1) == "CREATE": + elif match[1] == "CREATE": self.run_type = None - elif match.group(1) == "SINGLE POINT": + elif match[1] == "SINGLE POINT": self.run_type = "SinglePoint" else: raise AdfOutputError("Undefined Runtype!") @@ -684,12 +684,12 @@ def _parse_logfile(self, logfile): if match := coord_patt.search(line): sites.append([match.groups()[0], list(map(float, match.groups()[2:]))]) elif match := final_energy_patt.search(line): - self.final_energy = float(match.group(1)) + self.final_energy = float(match[1]) self.final_structure = self._sites_to_mol(sites) elif self.run_type == "GeometryOptimization": if match := cycle_patt.search(line): - cycle = int(match.group(1)) + cycle = int(match[1]) if cycle <= 0: raise AdfOutputError(f"Wrong {cycle=}") if cycle > last_cycle: @@ -701,14 +701,14 @@ def _parse_logfile(self, logfile): if match := coord_patt.search(line): sites.append([match.groups()[1], list(map(float, match.groups()[2:]))]) elif match := energy_patt.search(line): - self.energies.append(float(match.group(1))) + self.energies.append(float(match[1])) mol = self._sites_to_mol(sites) self.structures.append(mol) parse_cycle = False sites = [] elif parse_final: if match := final_energy_patt.search(line): - self.final_energy = float(match.group(1)) + self.final_energy = float(match[1]) elif self.run_type == "NumericalFreq": break @@ -759,7 +759,7 @@ def _parse_adf_output(self): if match := coord_on_patt.search(line): parse_coord = True elif match := coord_patt.search(line): - sites.append([match.group(2), list(map(float, match.groups()[2:5]))]) + sites.append([match[2], list(map(float, match.groups()[2:5]))]) n_strike += 1 elif n_strike > 0: find_structure = False @@ -789,12 +789,12 @@ def _parse_adf_output(self): self.normal_modes.append([]) elif parse_mode and (match := mode_patt.search(line)): - v = list(chunks(map(float, match.group(3).split()), 3)) + v = list(chunks(map(float, match[3].split()), 3)) if len(v) != n_next: raise AdfOutputError("Odd Error!") for i, k in enumerate(range(-n_next, 0)): self.normal_modes[k].extend(v[i]) - if int(match.group(1)) == n_atoms: + if int(match[1]) == n_atoms: parse_freq = True parse_mode = False if isinstance(self.final_structure, list): diff --git a/pymatgen/io/aims/parsers.py b/pymatgen/io/aims/parsers.py index f06f1307893..b1ea80e7a46 100644 --- a/pymatgen/io/aims/parsers.py +++ b/pymatgen/io/aims/parsers.py @@ -105,7 +105,7 @@ def search_for_all(self, key: str, line_start: int = 0, line_end: int = -1) -> l line_index.append(ll + line_start) return line_index - def parse_scalar(self, property: str) -> float | None: + def parse_scalar(self, property: str) -> float | None: # noqa: A002 """Parse a scalar property from the chunk. Args: diff --git a/pymatgen/io/aims/sets/base.py b/pymatgen/io/aims/sets/base.py index b868a8621d8..633f65b0f41 100644 --- a/pymatgen/io/aims/sets/base.py +++ b/pymatgen/io/aims/sets/base.py @@ -20,7 +20,8 @@ if TYPE_CHECKING: from collections.abc import Sequence - from pathlib import Path + + from pymatgen.util.typing import PathLike TMPDIR_NAME: str = "tmpdir" OUTPUT_FILE_NAME: str = "aims.out" @@ -133,7 +134,11 @@ def set_parameters(self, *args, **kwargs) -> dict[str, Any]: return self._parameters - def remove_parameters(self, keys: Iterable[str] | str, strict: bool = True) -> dict[str, Any]: + def remove_parameters( + self, + keys: Iterable[str] | str, + strict: bool = True, + ) -> dict[str, Any]: """Remove the aims parameters listed in keys. This removes the aims variables from the parameters object. @@ -190,10 +195,10 @@ class AimsInputGenerator(InputGenerator): user_params: dict[str, Any] = field(default_factory=dict) user_kpoints_settings: dict[str, Any] = field(default_factory=dict) - def get_input_set( # type: ignore + def get_input_set( self, structure: Structure | Molecule | None = None, - prev_dir: str | Path | None = None, + prev_dir: PathLike | None = None, properties: list[str] | None = None, ) -> AimsInputSet: """Generate an AimsInputSet object. @@ -221,7 +226,7 @@ def get_input_set( # type: ignore @staticmethod def _read_previous( - prev_dir: str | Path | None = None, + prev_dir: PathLike | None = None, ) -> tuple[Structure | Molecule | None, dict[str, Any], dict[str, Any]]: """Read in previous results. @@ -288,7 +293,9 @@ def _get_properties( return properties def _get_input_parameters( - self, structure: Structure | Molecule, prev_parameters: dict[str, Any] | None = None + self, + structure: Structure | Molecule, + prev_parameters: dict[str, Any] | None = None, ) -> dict[str, Any]: """Create the input parameters. @@ -340,7 +347,11 @@ def _get_input_parameters( return parameters - def get_parameter_updates(self, structure: Structure | Molecule, prev_parameters: dict[str, Any]) -> dict[str, Any]: + def get_parameter_updates( + self, + structure: Structure | Molecule, + prev_parameters: dict[str, Any], + ) -> dict[str, Any]: """Update the parameters for a given calculation type. Args: diff --git a/pymatgen/io/aims/sets/bs.py b/pymatgen/io/aims/sets/bs.py index 7c1cafaa7ef..d59c4abc71a 100644 --- a/pymatgen/io/aims/sets/bs.py +++ b/pymatgen/io/aims/sets/bs.py @@ -83,7 +83,7 @@ def get_parameter_updates( dict: The updated for the parameters for the output section of FHI-aims """ if isinstance(structure, Molecule): - raise ValueError("BandStructures can not be made for non-periodic systems") + raise ValueError("BandStructures can not be made for non-periodic systems") # noqa: TRY004 updated_outputs = prev_parameters.get("output", []) updated_outputs += prepare_band_input(structure, self.k_point_density) diff --git a/pymatgen/io/babel.py b/pymatgen/io/babel.py index b8326bd01e6..0d0e19871c4 100644 --- a/pymatgen/io/babel.py +++ b/pymatgen/io/babel.py @@ -84,7 +84,7 @@ def __init__(self, mol: Molecule | openbabel.OBMol | pybel.Molecule) -> None: elif isinstance(mol, pybel.Molecule): self._ob_mol = mol.OBMol else: - raise ValueError(f"Unsupported input type {type(mol)}, must be Molecule, openbabel.OBMol or pybel.Molecule") + raise TypeError(f"Unsupported input type {type(mol)}, must be Molecule, openbabel.OBMol or pybel.Molecule") @property def pymatgen_mol(self) -> Molecule: diff --git a/pymatgen/io/cif.py b/pymatgen/io/cif.py index 728abf7967d..dfe81b4856e 100644 --- a/pymatgen/io/cif.py +++ b/pymatgen/io/cif.py @@ -42,7 +42,7 @@ class CifBlock: """ - Object for storing cif data. All data is stored in a single dictionary. + Object for storing CIF data. All data is stored in a single dictionary. Data inside loops are stored in lists in the data dictionary, and information on which keys are grouped together are stored in the loops attribute. @@ -58,7 +58,7 @@ def __init__( ) -> None: """ Args: - data: dict of data to go into the cif. Values should be convertible to string, + data: dict of data to go into the CIF. Values should be convertible to string, or lists of these if the key is in a loop loops: list of lists of keys, grouped by which loop they should appear in header: name of the block (appears after the data_ on the first line). @@ -77,7 +77,7 @@ def __getitem__(self, key: str) -> Any: return self.data[key] def __str__(self) -> str: - """Get the cif string for the data block.""" + """Get the CIF string for the data block.""" out = [f"data_{self.header}"] keys = list(self.data) written = [] @@ -199,7 +199,7 @@ def from_str(cls, string: str) -> Self: while deq: _str = deq.popleft() - # cif keys aren't in quotes, so show up as _str[0] + # CIF keys aren't in quotes, so show up as _str[0] if _str[0] == "_eof": break @@ -249,7 +249,7 @@ def __init__( """ Args: data (dict): Of CifBlock objects. - orig_string (str): The original cif. + orig_string (str): The original CIF. comment (str): Comment. """ self.data = data @@ -372,13 +372,13 @@ def is_magcif_incommensurate() -> bool: self._site_tolerance = site_tolerance self._frac_tolerance = frac_tolerance - # Read cif file + # Read CIF file if isinstance(filename, (str, Path)): self._cif = CifFile.from_file(filename) elif isinstance(filename, StringIO): self._cif = CifFile.from_str(filename.read()) else: - raise RuntimeError("Unsupported file format.") + raise TypeError("Unsupported file format.") # Options related to checking CIFs for missing elements # or incorrect stoichiometries @@ -915,7 +915,7 @@ def _parse_symbol(self, sym: str) -> str | None: Returns: A string for the parsed symbol. None if no parsing was possible. """ - # Common representations for elements/water in cif files + # Common representations for elements/water in CIF files # TODO: fix inconsistent handling of water special_syms = { "Hw": "H", @@ -955,7 +955,7 @@ def _get_structure( symmetrized: bool, check_occu: bool = False, ) -> Structure | None: - """Generate structure from part of the cif.""" + """Generate structure from part of the CIF.""" def get_num_implicit_hydrogens(symbol: str) -> int: """Get number of implicit hydrogens.""" @@ -1142,7 +1142,7 @@ def get_matching_coord( all_coords.extend(coords) all_species.extend(len(coords) * [species]) all_magmoms.extend(_magmoms) - all_labels.extend(new_labels) # type: ignore + all_labels.extend(new_labels) # Scale occupancies if necessary all_species_noedit = all_species.copy() # save copy before scaling in case of check_occu=False, used below @@ -1346,7 +1346,7 @@ def get_bibtex_string(self) -> str: # TODO: CIF specification supports multiple citations. for idx, data in enumerate(self._cif.data.values()): - # Convert to lower-case keys, some cif files inconsistent + # Convert to lower-case keys, some CIF files inconsistent _data = {k.lower(): v for k, v in data.data.items()} bibtex_entry = {} @@ -1484,10 +1484,10 @@ def str2float(text: str) -> float: if isinstance(text, list) and len(text) == 1: return float(re.sub(r"\(.+\)*", "", text[0])) - except ValueError as exc: + except ValueError: if text.strip() == ".": return 0 - raise exc + raise raise ValueError(f"{text!s} cannot be converted to float") @@ -1508,7 +1508,7 @@ def __init__( Args: struct (Structure): structure to write. symprec (float): If not none, finds the symmetry of the structure - and writes the cif with symmetry information. Passes symprec + and writes the CIF with symmetry information. Passes symprec to the SpacegroupAnalyzer. See also refine_struct. write_magmoms (bool): If True, will write magCIF file. Incompatible with symprec diff --git a/pymatgen/io/core.py b/pymatgen/io/core.py index 4d723c138ed..1392e8a564e 100644 --- a/pymatgen/io/core.py +++ b/pymatgen/io/core.py @@ -37,7 +37,9 @@ from monty.json import MSONable if TYPE_CHECKING: - from os import PathLike + from typing_extensions import Self + + from pymatgen.util.typing import PathLike __author__ = "Ryan Kingsbury" @@ -59,18 +61,20 @@ class InputFile(MSONable): to __init__ as attributes. """ + def __str__(self) -> str: + return self.get_str() + @abc.abstractmethod def get_str(self) -> str: """Return a string representation of an entire input file.""" - def write_file(self, filename: str | PathLike) -> None: + def write_file(self, filename: PathLike) -> None: """Write the input file. Args: filename: The filename to output to, including path. """ - filename = filename if isinstance(filename, Path) else Path(filename) - with zopen(filename, mode="wt") as file: + with zopen(Path(filename), mode="wt") as file: file.write(self.get_str()) @classmethod @@ -88,7 +92,7 @@ def from_str(cls, contents: str) -> None: raise NotImplementedError(f"from_str has not been implemented in {cls.__name__}") @classmethod - def from_file(cls, path: str | Path) -> None: + def from_file(cls, path: PathLike) -> None: """ Creates an InputFile object from a file. @@ -98,13 +102,9 @@ def from_file(cls, path: str | Path) -> None: Returns: InputFile """ - filename = path if isinstance(path, Path) else Path(path) - with zopen(filename, mode="rt") as file: + with zopen(Path(path), mode="rt") as file: return cls.from_str(file.read()) # from_str not implemented - def __str__(self) -> str: - return self.get_str() - class InputSet(MSONable, MutableMapping): """ @@ -120,9 +120,8 @@ class InputSet(MSONable, MutableMapping): is optional. """ - def __init__(self, inputs: dict[str | Path, str | InputFile] | None = None, **kwargs): - """ - Instantiate an InputSet. + def __init__(self, inputs: dict[PathLike, str | InputFile] | None = None, **kwargs) -> None: + """Instantiate an InputSet. Args: inputs: The core mapping of filename: file contents that defines the InputSet data. @@ -139,12 +138,12 @@ def __init__(self, inputs: dict[str | Path, str | InputFile] | None = None, **kw self.__dict__.update(**kwargs) def __getattr__(self, key): - # allow accessing keys as attributes + """Allow accessing keys as attributes.""" if key in self._kwargs: return self.get(key) raise AttributeError(f"'{type(self).__name__}' object has no attribute {key!r}") - def __copy__(self) -> InputSet: + def __copy__(self) -> Self: cls = type(self) new_instance = cls.__new__(cls) @@ -153,7 +152,7 @@ def __copy__(self) -> InputSet: return new_instance - def __deepcopy__(self, memo: dict[int, InputSet]) -> InputSet: + def __deepcopy__(self, memo: dict[int, InputSet]) -> Self: cls = type(self) new_instance = cls.__new__(cls) memo[id(self)] = new_instance @@ -166,26 +165,26 @@ def __deepcopy__(self, memo: dict[int, InputSet]) -> InputSet: def __len__(self) -> int: return len(self.inputs) - def __iter__(self) -> Iterator[str | Path]: + def __iter__(self) -> Iterator[PathLike]: return iter(self.inputs) - def __getitem__(self, key: str | Path) -> str | InputFile | slice: + def __getitem__(self, key: PathLike) -> str | InputFile | slice: return self.inputs[key] - def __setitem__(self, key: str | Path, value: str | InputFile) -> None: + def __setitem__(self, key: PathLike, value: str | InputFile) -> None: self.inputs[key] = value - def __delitem__(self, key: str | Path) -> None: + def __delitem__(self, key: PathLike) -> None: del self.inputs[key] def write_input( self, - directory: str | Path, + directory: PathLike, make_dir: bool = True, overwrite: bool = True, zip_inputs: bool = False, - ): - """Write Inputs to one or more files. + ) -> None: + """Write inputs to one or more files. Args: directory: Directory to write input files to @@ -226,7 +225,7 @@ def write_input( pass @classmethod - def from_directory(cls, directory: str | Path) -> None: + def from_directory(cls, directory: PathLike) -> None: """ Construct an InputSet from a directory of one or more files. @@ -261,4 +260,4 @@ def get_input_set(self, *args, **kwargs): class ParseError(SyntaxError): - """This exception indicates a problem was encountered during parsing due to unexpected formatting.""" + """Indicate a problem was encountered during parsing due to unexpected formatting.""" diff --git a/pymatgen/io/cp2k/utils.py b/pymatgen/io/cp2k/utils.py index 6fd1f7f33e2..d82beca9c64 100644 --- a/pymatgen/io/cp2k/utils.py +++ b/pymatgen/io/cp2k/utils.py @@ -50,7 +50,7 @@ def postprocessor(data: str) -> str | float | bool | None: return data -def preprocessor(data: str, dir: str = ".") -> str: +def preprocessor(data: str, dir: str = ".") -> str: # noqa: A002 """ Cp2k contains internal preprocessor flags that are evaluated before execution. This helper function recognizes those preprocessor flags and replaces them with an equivalent cp2k input diff --git a/pymatgen/io/cssr.py b/pymatgen/io/cssr.py index 2db58b08a3d..97631f3bf28 100644 --- a/pymatgen/io/cssr.py +++ b/pymatgen/io/cssr.py @@ -80,8 +80,8 @@ def from_str(cls, string: str) -> Self: sp, coords = [], [] for line in lines[4:]: if match := re.match(r"\d+\s+(\w+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)", line.strip()): - sp.append(match.group(1)) - coords.append([float(match.group(i)) for i in range(2, 5)]) + sp.append(match[1]) + coords.append([float(match[i]) for i in range(2, 5)]) return cls(Structure(lattice, sp, coords)) @classmethod diff --git a/pymatgen/io/feff/inputs.py b/pymatgen/io/feff/inputs.py index 5ec7be0b45b..1d02ea6b650 100644 --- a/pymatgen/io/feff/inputs.py +++ b/pymatgen/io/feff/inputs.py @@ -193,7 +193,7 @@ def __init__( self.periodic = False self.space_number = self.space_group = None else: - raise ValueError("'struct' argument must be a Structure or Molecule!") + raise TypeError("'struct' argument must be a Structure or Molecule!") self.comment = comment or "None given" @classmethod diff --git a/pymatgen/io/gaussian.py b/pymatgen/io/gaussian.py index f423d218334..5372aa106bb 100644 --- a/pymatgen/io/gaussian.py +++ b/pymatgen/io/gaussian.py @@ -62,17 +62,17 @@ def read_route_line(route): for tok in route.split(): if match := scrf_patt.match(tok): - route_params[match.group(1)] = match.group(2) + route_params[match[1]] = match[2] elif tok.upper() in ["#", "#N", "#P", "#T"]: # does not store # in route to avoid error in input dieze_tag = "#N" if tok == "#" else tok continue elif match := re.match(multi_params_patt, tok.strip("#")): pars = {} - for par in match.group(2).split(","): + for par in match[2].split(","): p = par.split("=") pars[p[0]] = None if len(p) == 1 else p[1] - route_params[match.group(1)] = pars + route_params[match[1]] = pars else: d = tok.strip("#").split("=") route_params[d[0]] = None if len(d) == 1 else d[1] @@ -178,7 +178,7 @@ def _parse_coords(coord_lines): var_pattern = re.compile(r"^([A-Za-z]+\S*)[\s=,]+([\d\-\.]+)$") for line in coord_lines: if match := var_pattern.match(line.strip()): - paras[match.group(1).strip("=")] = float(match.group(2)) + paras[match[1].strip("=")] = float(match[2]) species = [] coords = [] @@ -191,7 +191,7 @@ def _parse_coords(coord_lines): break if (not zmode) and GaussianInput._xyz_patt.match(line): match = GaussianInput._xyz_patt.match(line) - species.append(match.group(1)) + species.append(match[1]) tokens = re.split(r"[,\s]+", line.strip()) if len(tokens) > 4: coords.append([float(i) for i in tokens[2:5]]) @@ -295,7 +295,7 @@ def from_str(cls, contents: str) -> Self: if link0_patt.match(line): match = link0_patt.match(line) assert match is not None - link0_dict[match.group(1).strip("=")] = match.group(2) + link0_dict[match[1].strip("=")] = match[2] route_patt = re.compile(r"^#[sSpPnN]*.*") route = "" @@ -672,7 +672,7 @@ def _parse(self, filename): parse_stage = 1 elif link0_patt.match(line): match = link0_patt.match(line) - self.link0[match.group(1)] = match.group(2) + self.link0[match[1]] = match[2] elif route_patt.search(line) or route_line != "": if set(line.strip()) == {"-"}: params = read_route_line(route_line) @@ -692,8 +692,8 @@ def _parse(self, filename): self.title = line.strip() elif charge_mul_patt.search(line): match = charge_mul_patt.search(line) - self.charge = int(match.group(1)) - self.spin_multiplicity = int(match.group(2)) + self.charge = int(match[1]) + self.spin_multiplicity = int(match[2]) parse_stage = 2 elif parse_stage == 2: if self.is_pcm: @@ -701,11 +701,11 @@ def _parse(self, filename): if "freq" in route_lower and thermo_patt.search(line): match = thermo_patt.search(line) - if match.group(1) == "Zero-point": - self.corrections["Zero-point"] = float(match.group(3)) + if match[1] == "Zero-point": + self.corrections["Zero-point"] = float(match[3]) else: - key = match.group(2).replace(" to ", "") - self.corrections[key] = float(match.group(3)) + key = match[2].replace(" to ", "") + self.corrections[key] = float(match[3]) if read_coord: [file.readline() for i in range(3)] @@ -751,7 +751,7 @@ def _parse(self, filename): # read molecular orbital coefficients if (not num_basis_found) and num_basis_func_patt.search(line): match = num_basis_func_patt.search(line) - self.num_basis_func = int(match.group(1)) + self.num_basis_func = int(match[1]) num_basis_found = True elif read_mo: # build a matrix with all coefficients @@ -775,12 +775,12 @@ def _parse(self, filename): # identify atom and OA labels match = mo_coeff_name_patt.search(line) - if match.group(1).strip() != "": - atom_idx = int(match.group(2)) - 1 - # atname = m.group(3) - self.atom_basis_labels.append([match.group(4)]) + if match[1].strip() != "": + atom_idx = int(match[2]) - 1 + # atname = match[3] + self.atom_basis_labels.append([match[4]]) else: - self.atom_basis_labels[atom_idx].append(match.group(4)) + self.atom_basis_labels[atom_idx].append(match[4]) # MO coefficients coeffs = [float(c) for c in float_patt.findall(line)] @@ -892,7 +892,7 @@ def _parse(self, filename): elif termination_patt.search(line): match = termination_patt.search(line) - if match.group(1) == "Normal": + if match[1] == "Normal": self.properly_terminated = True terminated = True elif error_patt.search(line): @@ -901,10 +901,10 @@ def _parse(self, filename): "Convergence failure": "SCF convergence error", } match = error_patt.search(line) - self.errors.append(error_defs[match.group(1)]) + self.errors.append(error_defs[match[1]]) elif num_elec_patt.search(line): match = num_elec_patt.search(line) - self.electrons = (int(match.group(1)), int(match.group(2))) + self.electrons = (int(match[1]), int(match[2])) elif (not self.is_pcm) and pcm_patt.search(line): self.is_pcm = True self.pcm = {} @@ -912,13 +912,13 @@ def _parse(self, filename): self.stationary_type = "Saddle" elif mp2_patt.search(line): match = mp2_patt.search(line) - self.energies.append(float(match.group(1).replace("D", "E"))) + self.energies.append(float(match[1].replace("D", "E"))) elif oniom_patt.search(line): match = oniom_patt.matcher(line) - self.energies.append(float(match.group(1))) + self.energies.append(float(match[1])) elif scf_patt.search(line): match = scf_patt.search(line) - self.energies.append(float(match.group(1))) + self.energies.append(float(match[1])) elif std_orientation_patt.search(line): standard_orientation = True geom_orientation = "standard" @@ -945,7 +945,7 @@ def _parse(self, filename): parse_forces = True elif freq_on_patt.search(line): parse_freq = True - _ = [file.readline() for _i in range(3)] + _ = [file.readline() for _ in range(3)] elif mo_coeff_patt.search(line): if "Alpha" in line: self.is_spin = True @@ -976,7 +976,7 @@ def _parse(self, filename): for line in mulliken_txt: if mulliken_charge_patt.search(line): match = mulliken_charge_patt.search(line) - dic = {int(match.group(1)): [match.group(2), float(match.group(3))]} + dic = {int(match[1]): [match[2], float(match[3])]} mulliken_charges.update(dic) read_mulliken = False self.Mulliken_charges = mulliken_charges @@ -1031,13 +1031,13 @@ def _check_pcm(self, line): if energy_patt.search(line): match = energy_patt.search(line) - self.pcm[f"{match.group(1)} energy"] = float(match.group(2)) + self.pcm[f"{match[1]} energy"] = float(match[2]) elif total_patt.search(line): match = total_patt.search(line) - self.pcm["Total energy"] = float(match.group(1)) + self.pcm["Total energy"] = float(match[1]) elif parameter_patt.search(line): match = parameter_patt.search(line) - self.pcm[match.group(1)] = float(match.group(2)) + self.pcm[match[1]] = float(match[2]) def as_dict(self): """JSON-serializable dict representation.""" diff --git a/pymatgen/io/lammps/data.py b/pymatgen/io/lammps/data.py index 72e248232f0..69d9d834853 100644 --- a/pymatgen/io/lammps/data.py +++ b/pymatgen/io/lammps/data.py @@ -399,15 +399,15 @@ def map_charges(q) -> str: coeffs: dict[str, dict] = {} for style, types in coeffs_data_type.items(): coeffs[style] = {} - for type, formatter in types.items(): - coeffs[style][type] = {} - for coeff, datatype in formatter.items(): # type: ignore + for typ, formatter in types.items(): + coeffs[style][typ] = {} + for coeff, datatype in formatter.items(): # type: ignore[attr-defined] if datatype == "int_format": - coeffs[style][type][coeff] = int_format + coeffs[style][typ][coeff] = int_format elif datatype == "float_format_2": - coeffs[style][type][coeff] = float_format_2 + coeffs[style][typ][coeff] = float_format_2 else: - coeffs[style][type][coeff] = float_format + coeffs[style][typ][coeff] = float_format section_template = "{kw}\n\n{df}\n" parts = [] @@ -830,7 +830,7 @@ def from_structure( velos = np.array(struct.site_properties["velocities"]) rot = SymmOp.from_rotation_and_translation(symm_op.rotation_matrix) rot_velos = rot.operate_multi(velos) - site_properties["velocities"] = rot_velos # type: ignore + site_properties["velocities"] = rot_velos boxed_s = Structure( box.to_lattice(), struct.species, diff --git a/pymatgen/io/lammps/inputs.py b/pymatgen/io/lammps/inputs.py index 9153321d152..565feea80bf 100644 --- a/pymatgen/io/lammps/inputs.py +++ b/pymatgen/io/lammps/inputs.py @@ -934,9 +934,9 @@ class LammpsTemplateGen(TemplateInputGen): See pymatgen.io.template.py for additional documentation of this method. """ - def get_input_set( # type: ignore + def get_input_set( # type: ignore[override] self, - script_template: str | Path, + script_template: PathLike, settings: dict | None = None, script_filename: str = "in.lammps", data: LammpsData | CombinedData | None = None, @@ -974,7 +974,7 @@ def write_lammps_inputs( **kwargs, ) -> None: """ - Writes input files for a LAMMPS run. Input script is constructed + Write input files for a LAMMPS run. Input script is constructed from a str template with placeholders to be filled by custom settings. Data file is either written from a LammpsData instance or copied from an existing file if read_data cmd is @@ -1051,7 +1051,7 @@ def write_lammps_inputs( input_script = template.safe_substitute(**variables) if make_dir_if_not_present: os.makedirs(output_dir, exist_ok=True) - with open(os.path.join(output_dir, script_filename), mode="w") as file: + with open(os.path.join(output_dir, script_filename), mode="w", encoding="utf-8") as file: file.write(input_script) if read_data := re.search(r"read_data\s+(.*)\n", input_script): diff --git a/pymatgen/io/lammps/sets.py b/pymatgen/io/lammps/sets.py index cb1cdb08e89..d61510f3d67 100644 --- a/pymatgen/io/lammps/sets.py +++ b/pymatgen/io/lammps/sets.py @@ -18,10 +18,10 @@ from pymatgen.io.lammps.inputs import LammpsInputFile if TYPE_CHECKING: - from pathlib import Path - from typing_extensions import Self + from pymatgen.util.typing import PathLike + __author__ = "Ryan Kingsbury, Guillaume Brunin (Matgenix)" __copyright__ = "Copyright 2021, The Materials Project" __version__ = "0.2" @@ -50,7 +50,7 @@ def __init__( inputfile: LammpsInputFile | str, data: LammpsData | CombinedData, calc_type: str = "", - template_file: str = "", + template_file: PathLike = "", keep_stages: bool = False, ) -> None: """ @@ -75,9 +75,9 @@ def __init__( super().__init__(inputs={"in.lammps": self.inputfile, "system.data": self.data}) @classmethod - def from_directory(cls, directory: str | Path, keep_stages: bool = False) -> Self: # type: ignore[override] - """ - Construct a LammpsInputSet from a directory of two or more files. + def from_directory(cls, directory: PathLike, keep_stages: bool = False) -> Self: # type: ignore[override] + """Construct a LammpsInputSet from a directory of two or more files. + TODO: accept directories with only the input file, that should include the structure as well. Args: @@ -88,7 +88,7 @@ def from_directory(cls, directory: str | Path, keep_stages: bool = False) -> Sel input_file = LammpsInputFile.from_file(f"{directory}/in.lammps", keep_stages=keep_stages) atom_style = input_file.get_args("atom_style") if isinstance(atom_style, list): - raise ValueError("Variable atom_style is specified multiple times in the input file.") + raise ValueError("Variable atom_style is specified multiple times in the input file.") # noqa: TRY004 data_file = LammpsData.from_file(f"{directory}/system.data", atom_style=atom_style) return cls(inputfile=input_file, data=data_file, calc_type="read_from_dir") diff --git a/pymatgen/io/lammps/utils.py b/pymatgen/io/lammps/utils.py index c7ae00f2f10..f28c696d331 100644 --- a/pymatgen/io/lammps/utils.py +++ b/pymatgen/io/lammps/utils.py @@ -190,7 +190,7 @@ def __init__( control_params: dict | None = None, auto_box: bool = True, output_file: str = "packed.xyz", - bin: str = "packmol", + bin: str = "packmol", # noqa: A002 ) -> None: """ Args: @@ -430,7 +430,7 @@ def restore_site_properties(self, site_property: str = "ff_map", filename: str | class LammpsRunner: """LAMMPS wrapper.""" - def __init__(self, input_filename: str = "lammps.in", bin: str = "lammps") -> None: + def __init__(self, input_filename: str = "lammps.in", bin: str = "lammps") -> None: # noqa: A002 """ Args: input_filename (str): input file name @@ -450,8 +450,8 @@ def run(self) -> tuple[bytes, bytes]: """Write the input/data files and run LAMMPS.""" lammps_cmd = [*self.lammps_bin, "-in", self.input_filename] print(f"Running: {' '.join(lammps_cmd)}") - with Popen(lammps_cmd, stdout=PIPE, stderr=PIPE) as p: - stdout, stderr = p.communicate() + with Popen(lammps_cmd, stdout=PIPE, stderr=PIPE) as process: + stdout, stderr = process.communicate() return stdout, stderr diff --git a/pymatgen/io/lmto.py b/pymatgen/io/lmto.py index 328821fea81..c784c146412 100644 --- a/pymatgen/io/lmto.py +++ b/pymatgen/io/lmto.py @@ -362,6 +362,6 @@ def _get_bond_data(line): # Replacing "/" with "-" makes splitting easier sites = line[0].replace("/", "-").split("-") site_indices = tuple(int(ind) - 1 for ind in sites[1:4:2]) - species = tuple(re.split(r"\d+", spec)[0] for spec in sites[0:3:2]) + species = tuple(re.split(r"\d+", spec)[0] for spec in sites[:3:2]) label = f"{species[0]}{site_indices[0] + 1}-{species[1]}{site_indices[1] + 1}" return label, length, site_indices diff --git a/pymatgen/io/lobster/outputs.py b/pymatgen/io/lobster/outputs.py index e30308233db..e1f8a39d92b 100644 --- a/pymatgen/io/lobster/outputs.py +++ b/pymatgen/io/lobster/outputs.py @@ -35,6 +35,7 @@ from typing import Any from pymatgen.core.structure import IStructure + from pymatgen.util.typing import PathLike __author__ = "Janine George, Marco Esters" __copyright__ = "Copyright 2017, The Materials Project" @@ -80,7 +81,7 @@ def __init__( are_coops: bool = False, are_cobis: bool = False, are_multi_center_cobis: bool = False, - filename: str | None = None, + filename: PathLike | None = None, ) -> None: """ Args: @@ -343,7 +344,7 @@ def __init__( self, are_coops: bool = False, are_cobis: bool = False, - filename: str | None = None, + filename: PathLike | None = None, is_spin_polarized: bool = False, orbitalwise: bool = False, icohpcollection=None, @@ -360,9 +361,6 @@ def __init__( icohpcollection: IcohpCollection Object """ - # to avoid circular dependencies - from pymatgen.electronic_structure.cohp import IcohpCollection - self._filename = filename self.is_spin_polarized = is_spin_polarized self.orbitalwise = orbitalwise @@ -492,6 +490,9 @@ def __init__( else: list_orb_icohp[int(label) - 1][orb_label] = {"icohp": icohp, "orbitals": orbitals} + # Avoid circular import + from pymatgen.electronic_structure.cohp import IcohpCollection + self._icohpcollection = IcohpCollection( are_coops=are_coops, are_cobis=are_cobis, @@ -537,15 +538,20 @@ class NciCobiList: "interaction_type": type of the multi-center interaction """ - def __init__(self, filename: str | None = "NcICOBILIST.lobster"): # LOBSTER < 4.1.0: no COBI/ICOBI/NcICOBI + def __init__( + self, + filename: PathLike | None = "NcICOBILIST.lobster", + ) -> None: """ + LOBSTER < 4.1.0: no COBI/ICOBI/NcICOBI + Args: filename: Name of the NcICOBILIST file. """ # LOBSTER list files have an extra trailing blank line # and we don't need the header. - with zopen(filename, mode="rt") as file: # type:ignore + with zopen(filename, mode="rt") as file: data = file.read().split("\n")[1:-1] if len(data) == 0: raise RuntimeError("NcICOBILIST file contains no data.") @@ -649,13 +655,13 @@ class Doscar: def __init__( self, - doscar: str = "DOSCAR.lobster", - structure_file: str | None = "POSCAR", + doscar: PathLike = "DOSCAR.lobster", + structure_file: PathLike | None = "POSCAR", structure: IStructure | Structure | None = None, ): """ Args: - doscar: DOSCAR filename, typically "DOSCAR.lobster" + doscar: DOSCAR file, typically "DOSCAR.lobster" structure_file: for vasp, this is typically "POSCAR" structure: instead of a structure file, the structure can be given directly. structure_file will be preferred. @@ -789,7 +795,7 @@ class Charge(MSONable): def __init__( self, - filename: str = "CHARGE.lobster", + filename: PathLike = "CHARGE.lobster", num_atoms: int | None = None, atomlist: list[str] | None = None, types: list[str] | None = None, @@ -798,7 +804,7 @@ def __init__( ): """ Args: - filename: filename for the CHARGE file, typically "CHARGE.lobster". + filename: The CHARGE file, typically "CHARGE.lobster". num_atoms: number of atoms in the structure atomlist: list of atoms in the structure types: list of unique species in the structure @@ -816,7 +822,7 @@ def __init__( with zopen(filename, mode="rt") as file: data = file.read().split("\n")[3:-3] if len(data) == 0: - raise RuntimeError("CHARGES file contains no data.") + raise RuntimeError("CHARGE file contains no data.") self.num_atoms = len(data) for atom in range(self.num_atoms): @@ -826,7 +832,7 @@ def __init__( self.mulliken += [float(line[2])] self.loewdin += [float(line[3])] - def get_structure_with_charges(self, structure_filename): + def get_structure_with_charges(self, structure_filename: PathLike) -> Structure: """Get a Structure with Mulliken and Loewdin charges as site properties Args: @@ -920,10 +926,10 @@ class Lobsterout(MSONable): # TODO: add tests for skipping COBI and madelung # TODO: add tests for including COBI and madelung - def __init__(self, filename: str | None, **kwargs) -> None: + def __init__(self, filename: PathLike | None, **kwargs) -> None: """ Args: - filename: filename of lobsterout. + filename: The lobsterout file. **kwargs: dict to initialize Lobsterout instance """ self.filename = filename @@ -1007,46 +1013,38 @@ def __init__(self, filename: str | None, **kwargs) -> None: def get_doc(self) -> dict[str, Any]: """Get the LobsterDict with all the information stored in lobsterout.""" - lobster_dict: dict[str, Any] = {} - # check if Lobster starts from a projection - lobster_dict["restart_from_projection"] = self.is_restart_from_projection - lobster_dict["lobster_version"] = self.lobster_version - lobster_dict["threads"] = self.number_of_threads - lobster_dict["dft_program"] = self.dft_program - - lobster_dict["charge_spilling"] = self.charge_spilling - lobster_dict["total_spilling"] = self.total_spilling - - lobster_dict["elements"] = self.elements - lobster_dict["basis_type"] = self.basis_type - lobster_dict["basis_functions"] = self.basis_functions - - lobster_dict["timing"] = self.timing - - lobster_dict["warning_lines"] = self.warning_lines - - lobster_dict["info_orthonormalization"] = self.info_orthonormalization - - lobster_dict["info_lines"] = self.info_lines - - lobster_dict["has_doscar"] = self.has_doscar - lobster_dict["has_doscar_lso"] = self.has_doscar_lso - lobster_dict["has_cohpcar"] = self.has_cohpcar - lobster_dict["has_coopcar"] = self.has_coopcar - lobster_dict["has_cobicar"] = self.has_cobicar - lobster_dict["has_charge"] = self.has_charge - lobster_dict["has_madelung"] = self.has_madelung - lobster_dict["has_projection"] = self.has_projection - lobster_dict["has_bandoverlaps"] = self.has_bandoverlaps - lobster_dict["has_fatbands"] = self.has_fatbands - lobster_dict["has_grosspopulation"] = self.has_grosspopulation - lobster_dict["has_density_of_energies"] = self.has_density_of_energies - - return lobster_dict + return { + # Check if LOBSTER starts from a projection + "restart_from_projection": self.is_restart_from_projection, + "lobster_version": self.lobster_version, + "threads": self.number_of_threads, + "dft_program": self.dft_program, + "charge_spilling": self.charge_spilling, + "total_spilling": self.total_spilling, + "elements": self.elements, + "basis_type": self.basis_type, + "basis_functions": self.basis_functions, + "timing": self.timing, + "warning_lines": self.warning_lines, + "info_orthonormalization": self.info_orthonormalization, + "info_lines": self.info_lines, + "has_doscar": self.has_doscar, + "has_doscar_lso": self.has_doscar_lso, + "has_cohpcar": self.has_cohpcar, + "has_coopcar": self.has_coopcar, + "has_cobicar": self.has_cobicar, + "has_charge": self.has_charge, + "has_madelung": self.has_madelung, + "has_projection": self.has_projection, + "has_bandoverlaps": self.has_bandoverlaps, + "has_fatbands": self.has_fatbands, + "has_grosspopulation": self.has_grosspopulation, + "has_density_of_energies": self.has_density_of_energies, + } - def as_dict(self): + def as_dict(self) -> dict: """MSONable dict""" - dct = vars(self) + dct = dict(vars(self)) dct["@module"] = type(self).__module__ dct["@class"] = type(self).__name__ @@ -1137,7 +1135,7 @@ def _get_elements_basistype_basisfunctions(data): @staticmethod def _get_timing(data): - # will give back wall, user and sys time + # Will give back wall, user and sys time begin = False user_time, wall_time, sys_time = [], [], [] @@ -1212,9 +1210,9 @@ class Fatband: def __init__( self, - filenames: str | list = ".", - kpoints_file: str = "KPOINTS", - vasprun_file: str | None = "vasprun.xml", + filenames: PathLike | list = ".", + kpoints_file: PathLike = "KPOINTS", + vasprun_file: PathLike | None = "vasprun.xml", structure: Structure | IStructure | None = None, efermi: float | None = None, ): @@ -1222,8 +1220,8 @@ def __init__( Args: filenames (list or string): can be a list of file names or a path to a folder from which all "FATBAND_*" files will be read - kpoints_file (str): KPOINTS file for bandstructure calculation, typically "KPOINTS". - vasprun_file (str): Corresponding vasprun file. + kpoints_file (PathLike): KPOINTS file for bandstructure calculation, typically "KPOINTS". + vasprun_file (PathLike): Corresponding vasprun file. Instead, the Fermi energy from the DFT run can be provided. Then, this value should be set to None. structure (Structure): Structure object. @@ -1406,13 +1404,13 @@ def __init__( self.label_dict = label_dict - def get_bandstructure(self): + def get_bandstructure(self) -> LobsterBandStructureSymmLine: """Get a LobsterBandStructureSymmLine object which can be plotted with a normal BSPlotter.""" return LobsterBandStructureSymmLine( kpoints=self.kpoints_array, eigenvals=self.eigenvals, lattice=self.lattice, - efermi=self.efermi, # type: ignore + efermi=self.efermi, labels_dict=self.label_dict, structure=self.structure, projections=self.p_eigenvals, @@ -2011,9 +2009,9 @@ def get_orb_from_str(orbs): orb_label = "" for iorb, orbital in enumerate(orbitals): if iorb == 0: - orb_label += f"{orbital[0]}{orbital[1].name}" # type: ignore + orb_label += f"{orbital[0]}{orbital[1].name}" else: - orb_label += f"-{orbital[0]}{orbital[1].name}" # type: ignore + orb_label += f"-{orbital[0]}{orbital[1].name}" return orb_label, orbitals diff --git a/pymatgen/io/nwchem.py b/pymatgen/io/nwchem.py index e070934bcc5..04686e878f7 100644 --- a/pymatgen/io/nwchem.py +++ b/pymatgen/io/nwchem.py @@ -732,7 +732,7 @@ def isfloatstring(in_str): if line.find(e) != -1: errors.append(v) if parse_time and (match := time_patt.search(line)): - time = match.group(1) + time = match[1] parse_time = False if parse_geom: if line.strip() == "Atomic Mass": @@ -746,11 +746,11 @@ def isfloatstring(in_str): parse_geom = False else: if match := coord_patt.search(line): - species.append(match.group(1).capitalize()) - coords.append([float(match.group(2)), float(match.group(3)), float(match.group(4))]) + species.append(match[1].capitalize()) + coords.append([float(match[2]), float(match[3]), float(match[4])]) if match := lat_vector_patt.search(line): - lattice.append([float(match.group(1)), float(match.group(2)), float(match.group(3))]) + lattice.append([float(match[1]), float(match[2]), float(match[3])]) if parse_force: if match := force_patt.search(line): @@ -836,7 +836,7 @@ def isfloatstring(in_str): else: if match := energy_patt.search(line): - energies.append(Energy(match.group(1), "Ha").to("eV")) + energies.append(Energy(match[1], "Ha").to("eV")) parse_time = True continue @@ -844,17 +844,17 @@ def isfloatstring(in_str): cosmo_scf_energy = energies[-1] energies[-1] = {} energies[-1]["cosmo scf"] = cosmo_scf_energy - energies[-1].update({"gas phase": Energy(match.group(1), "Ha").to("eV")}) + energies[-1].update({"gas phase": Energy(match[1], "Ha").to("eV")}) if match := energy_sol_patt.search(line): - energies[-1].update({"sol phase": Energy(match.group(1), "Ha").to("eV")}) + energies[-1].update({"sol phase": Energy(match[1], "Ha").to("eV")}) if match := preamble_patt.search(line): try: - val = int(match.group(2)) + val = int(match[2]) except ValueError: - val = match.group(2) - k = match.group(1).replace("No. of ", "n").replace(" ", "_") + val = match[2] + k = match[1].replace("No. of ", "n").replace(" ", "_") data[k.lower()] = val elif line.find('Geometry "geometry"') != -1: parse_geom = True @@ -892,7 +892,7 @@ def isfloatstring(in_str): if job_type == "NWChem DFT Module" and "COSMO solvation results" in output: job_type += " COSMO" elif match := corrections_patt.search(line): - corrections[match.group(1)] = FloatWithUnit(match.group(2), "kJ mol^-1").to("eV atom^-1") + corrections[match[1]] = FloatWithUnit(match[2], "kJ mol^-1").to("eV atom^-1") if frequencies: for _freq, mode in frequencies: diff --git a/pymatgen/io/openff.py b/pymatgen/io/openff.py index 2eb016d7ab4..a3f06767909 100644 --- a/pymatgen/io/openff.py +++ b/pymatgen/io/openff.py @@ -139,10 +139,10 @@ def get_atom_map(inferred_mol: tk.Molecule, openff_mol: tk.Molecule) -> tuple[bo isomorphism was found and a dictionary representing the atom mapping. """ # do not apply formal charge restrictions - kwargs = dict( - return_atom_map=True, - formal_charge_matching=False, - ) + kwargs = { + "return_atom_map": True, + "formal_charge_matching": False, + } isomorphic, atom_map = tk.topology.Molecule.are_isomorphic(openff_mol, inferred_mol, **kwargs) if isomorphic: return True, atom_map diff --git a/pymatgen/io/packmol.py b/pymatgen/io/packmol.py index 70cce25c10e..b234d7f11ec 100644 --- a/pymatgen/io/packmol.py +++ b/pymatgen/io/packmol.py @@ -23,12 +23,16 @@ class that provides a run() method for running packmol locally. import subprocess from pathlib import Path from shutil import which +from typing import TYPE_CHECKING import numpy as np from pymatgen.core import Molecule from pymatgen.io.core import InputGenerator, InputSet +if TYPE_CHECKING: + from pymatgen.util.typing import PathLike + __author__ = "Tingzheng Hou, Ryan Kingsbury, Orion Cohen" __version__ = "1.0" __maintainer__ = "Ryan Kingsbury" @@ -41,7 +45,7 @@ class PackmolSet(InputSet): InputSet for the Packmol software. This class defines several attributes related to. """ - def run(self, path: str | Path, timeout=30): + def run(self, path: PathLike, timeout=30): """Run packmol and write out the packed structure. Args: @@ -88,12 +92,12 @@ def run(self, path: str | Path, timeout=30): os.chdir(wd) @classmethod - def from_directory(cls, directory: str | Path) -> None: + def from_directory(cls, directory: PathLike) -> None: """ Construct an InputSet from a directory of one or more files. Args: - directory (str | Path): Directory to read input files from. + directory (PathLike): Directory to read input files from. """ raise NotImplementedError(f"from_directory has not been implemented in {cls.__name__}") @@ -109,9 +113,9 @@ def __init__( tolerance: float = 2.0, seed: int = 1, control_params: dict | None = None, - inputfile: str | Path = "packmol.inp", - outputfile: str | Path = "packmol_out.xyz", - stdoutfile: str | Path = "packmol.stdout", + inputfile: PathLike = "packmol.inp", + outputfile: PathLike = "packmol_out.xyz", + stdoutfile: PathLike = "packmol.stdout", ) -> None: """ Instantiate a PackmolBoxGen class. The init method defines simulations parameters @@ -132,7 +136,7 @@ def __init__( self.tolerance = tolerance self.seed = seed - def get_input_set( # type: ignore + def get_input_set( self, molecules: list[dict], box: list[float] | None = None, @@ -182,7 +186,7 @@ def get_input_set( # type: ignore # estimate the total volume of all molecules in cubic Å net_volume = 0.0 for d in molecules: - mol = Molecule.from_file(d["coords"]) if not isinstance(d["coords"], Molecule) else d["coords"] + mol = d["coords"] if isinstance(d["coords"], Molecule) else Molecule.from_file(d["coords"]) if mol is None: raise ValueError("Molecule cannot be None.") @@ -222,10 +226,10 @@ def get_input_set( # type: ignore file_contents += f" inside box {box_list}\n" file_contents += "end structure\n\n" - mapping.update({str(self.inputfile): file_contents}) + mapping |= {str(self.inputfile): file_contents} return PackmolSet( - inputs=mapping, # type: ignore + inputs=mapping, # type: ignore[arg-type] seed=self.seed, inputfile=self.inputfile, outputfile=self.outputfile, diff --git a/pymatgen/io/pwscf.py b/pymatgen/io/pwscf.py index 49f281569d2..73aa43f4a55 100644 --- a/pymatgen/io/pwscf.py +++ b/pymatgen/io/pwscf.py @@ -501,18 +501,18 @@ class PWInputError(BaseException): class PWOutput: """Parser for PWSCF output file.""" - patterns: ClassVar[dict[str, str]] = dict( - energies=r"total energy\s+=\s+([\d\.\-]+)\sRy", - ecut=r"kinetic\-energy cutoff\s+=\s+([\d\.\-]+)\s+Ry", - lattice_type=r"bravais\-lattice index\s+=\s+(\d+)", - celldm1=r"celldm\(1\)=\s+([\d\.]+)\s", - celldm2=r"celldm\(2\)=\s+([\d\.]+)\s", - celldm3=r"celldm\(3\)=\s+([\d\.]+)\s", - celldm4=r"celldm\(4\)=\s+([\d\.]+)\s", - celldm5=r"celldm\(5\)=\s+([\d\.]+)\s", - celldm6=r"celldm\(6\)=\s+([\d\.]+)\s", - nkpts=r"number of k points=\s+([\d]+)", - ) + patterns: ClassVar[dict[str, str]] = { + "energies": r"total energy\s+=\s+([\d\.\-]+)\sRy", + "ecut": r"kinetic\-energy cutoff\s+=\s+([\d\.\-]+)\s+Ry", + "lattice_type": r"bravais\-lattice index\s+=\s+(\d+)", + "celldm1": r"celldm\(1\)=\s+([\d\.]+)\s", + "celldm2": r"celldm\(2\)=\s+([\d\.]+)\s", + "celldm3": r"celldm\(3\)=\s+([\d\.]+)\s", + "celldm4": r"celldm\(4\)=\s+([\d\.]+)\s", + "celldm5": r"celldm\(5\)=\s+([\d\.]+)\s", + "celldm6": r"celldm\(6\)=\s+([\d\.]+)\s", + "nkpts": r"number of k points=\s+([\d]+)", + } def __init__(self, filename): """ diff --git a/pymatgen/io/qchem/inputs.py b/pymatgen/io/qchem/inputs.py index a960f2f24c1..27f2816103e 100644 --- a/pymatgen/io/qchem/inputs.py +++ b/pymatgen/io/qchem/inputs.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: from pathlib import Path - from typing import Literal + from typing import Any, Literal from typing_extensions import Self @@ -240,10 +240,6 @@ def __init__( # - Validity checks specific to job type? # - Check OPT and PCM sections? - def get_str(self) -> str: - """Return a string representation of an entire input file.""" - return str(self) - def __str__(self) -> str: combined_list: list = [] # molecule section @@ -288,6 +284,10 @@ def __str__(self) -> str: combined_list.append(self.pcm_nonels_template(self.pcm_nonels)) return "\n".join(combined_list) + def get_str(self) -> str: + """Return a string representation of an entire input file.""" + return str(self) + @staticmethod def multi_job_string(job_list: list[QCInput]) -> str: """ @@ -1154,23 +1154,23 @@ def read_cdft(string: str) -> list[list[dict]]: if len(const_out) == 0: continue for const in const_out: - const_dict = { + const_dict: dict[str, Any] = { "value": float(const[0]), "coefficients": [], "first_atoms": [], "last_atoms": [], "types": [], - } # type: ignore + } sub_consts = const[1].strip().split("\n") for subconst in sub_consts: tokens = subconst.split() - const_dict["coefficients"].append(float(tokens[0])) # type: ignore - const_dict["first_atoms"].append(int(tokens[1])) # type: ignore - const_dict["last_atoms"].append(int(tokens[2])) # type: ignore + const_dict["coefficients"].append(float(tokens[0])) + const_dict["first_atoms"].append(int(tokens[1])) + const_dict["last_atoms"].append(int(tokens[2])) if len(tokens) > 3: - const_dict["types"].append(tokens[3]) # type: ignore + const_dict["types"].append(tokens[3]) else: - const_dict["types"].append(None) # type: ignore + const_dict["types"].append(None) state_list.append(const_dict) @@ -1202,7 +1202,7 @@ def read_almo(string: str) -> list[list[tuple[int, int]]]: section = section[0] - almo_coupling = [[], []] # type: ignore + almo_coupling: list[list] = [[], []] state_1 = section[0] for line in state_1.strip().split("\n"): diff --git a/pymatgen/io/qchem/outputs.py b/pymatgen/io/qchem/outputs.py index 1bafe43d2fb..088206d2c25 100644 --- a/pymatgen/io/qchem/outputs.py +++ b/pymatgen/io/qchem/outputs.py @@ -2333,7 +2333,7 @@ def parse_natural_populations(lines: list[str]) -> list[pd.DataFrame]: # Extract the values values = line.split() if len(values[0]) > 2: - values.insert(0, values[0][0:-3]) + values.insert(0, values[0][:-3]) values[1] = values[1][-3:] data.append( [ diff --git a/pymatgen/io/qchem/sets.py b/pymatgen/io/qchem/sets.py index 6b5f7661d99..1b40d49fb4c 100644 --- a/pymatgen/io/qchem/sets.py +++ b/pymatgen/io/qchem/sets.py @@ -13,9 +13,10 @@ from pymatgen.io.qchem.utils import lower_and_check_unique if TYPE_CHECKING: - from typing import Literal + from typing import Any, Literal from pymatgen.core.structure import Molecule + from pymatgen.util.typing import PathLike __author__ = "Samuel Blau, Brandon Wood, Shyam Dwaraknath, Evan Spotte-Smith, Ryan Kingsbury" __copyright__ = "Copyright 2018-2022, The Materials Project" @@ -25,12 +26,12 @@ logger = logging.getLogger(__name__) -# note that in addition to the solvent-specific parameters, this dict contains +# Note that in addition to the solvent-specific parameters, this dict contains # dielectric constants for use with each solvent. The dielectric constants # are used by the isodensity SS(V)PE electrostatic calculation part of CMIRS # they are not part of the parameters tabulated by Q-Chem # see https://manual.q-chem.com/latest/example_CMIRS-water.html -CMIRS_SETTINGS = { +CMIRS_SETTINGS: dict[str, Any] = { "water": { "0.001": { "a": "-0.006736", @@ -384,7 +385,7 @@ def __init__( "vdwscale": "1.1", } - svp_defaults = {"rhoiso": "0.001", "nptleb": "1202", "itrngr": "2", "irotgr": "2"} + svp_defaults: dict[str, Any] = {"rhoiso": "0.001", "nptleb": "1202", "itrngr": "2", "irotgr": "2"} plots_defaults = {"grid_spacing": "0.05", "total_density": "0"} @@ -397,20 +398,21 @@ def __init__( smx: dict = {} vdw: dict = {} plots: dict = {} - rem: dict = {} - svp: dict = {} - pcm_nonels: dict = {} - rem["job_type"] = job_type - rem["basis"] = self.basis_set - rem["max_scf_cycles"] = str(self.max_scf_cycles) - rem["gen_scfman"] = "true" - rem["xc_grid"] = "3" - rem["thresh"] = "14" - rem["s2thresh"] = "16" - rem["scf_algorithm"] = self.scf_algorithm - rem["resp_charges"] = "true" - rem["symmetry"] = "false" - rem["sym_ignore"] = "true" + svp: dict[str, Any] = {} + pcm_nonels: dict[str, Any] = {} + rem: dict[str, Any] = { + "job_type": job_type, + "basis": self.basis_set, + "max_scf_cycles": str(self.max_scf_cycles), + "gen_scfman": "true", + "xc_grid": "3", + "thresh": "14", + "s2thresh": "16", + "scf_algorithm": self.scf_algorithm, + "resp_charges": "true", + "symmetry": "false", + "sym_ignore": "true", + } if self.dft_rung == 1: rem["method"] = "spw92" @@ -476,10 +478,10 @@ def __init__( svp = svp_defaults rem["solvent_method"] = "isosvp" rem["gen_scfman"] = "false" - svp["dielst"] = CMIRS_SETTINGS[self.cmirs_solvent]["dielst"] # type: ignore + svp["dielst"] = CMIRS_SETTINGS[self.cmirs_solvent]["dielst"] svp["idefesr"] = "1" # this flag enables the CMIRS part svp["ipnrf"] = "1" # this flag is also required for some undocumented reason - pcm_nonels = CMIRS_SETTINGS[self.cmirs_solvent][svp["rhoiso"]] # type: ignore + pcm_nonels = CMIRS_SETTINGS[self.cmirs_solvent][svp["rhoiso"]] pcm_nonels["delta"] = "7" # as recommended by Q-Chem. See manual. pcm_nonels["gaulag_n"] = "40" # as recommended by Q-Chem. See manual. @@ -563,8 +565,8 @@ def __init__( "CMIRS is only parameterized for RHOISO values of 0.001 or 0.0005! Exiting..." ) for k2 in pcm_nonels: - if CMIRS_SETTINGS[self.cmirs_solvent][v].get(k2): # type: ignore - pcm_nonels[k2] = CMIRS_SETTINGS[self.cmirs_solvent][v].get(k2) # type: ignore + if CMIRS_SETTINGS[self.cmirs_solvent][v].get(k2): + pcm_nonels[k2] = CMIRS_SETTINGS[self.cmirs_solvent][v].get(k2) if k == "idefesr": if self.cmirs_solvent is not None and v == "0": warnings.warn( @@ -615,13 +617,13 @@ def __init__( pcm_nonels=pcm_nonels, ) - def write(self, input_file: str): + def write(self, input_file: PathLike) -> None: """ Args: - input_file (str): Filename. + input_file (PathLike): Filename. """ self.write_file(input_file) - if self.smd_solvent in ("custom", "other") and self.qchem_version == 5: + if self.smd_solvent in {"custom", "other"} and self.qchem_version == 5: with zopen(os.path.join(os.path.dirname(input_file), "solvent_data"), mode="wt") as file: file.write(self.custom_smd) diff --git a/pymatgen/io/res.py b/pymatgen/io/res.py index 0c0c2e38842..d43efbaaf00 100644 --- a/pymatgen/io/res.py +++ b/pymatgen/io/res.py @@ -421,7 +421,7 @@ def _parse_date(cls, string: str) -> date: raise ResParseError(f"Could not parse the date from {string=}.") day, month, year, *_ = match.groups() - month_num = datetime.datetime.strptime(month, "%b").month + month_num = datetime.datetime.strptime(month, "%b").replace(tzinfo=datetime.timezone.utc).month return datetime.date(int(year), month_num, int(day)) diff --git a/pymatgen/io/shengbte.py b/pymatgen/io/shengbte.py index d648c67a81f..deef4d74a9f 100644 --- a/pymatgen/io/shengbte.py +++ b/pymatgen/io/shengbte.py @@ -119,7 +119,7 @@ def __init__(self, ngrid: list[int] | None = None, temperature: float | dict[str self["t_max"] = temperature["max"] self["t_step"] = temperature["step"] else: - raise ValueError("Unsupported temperature type, must be float or dict") + raise TypeError("Unsupported temperature type, must be float or dict") self.update(kwargs) diff --git a/pymatgen/io/template.py b/pymatgen/io/template.py index de8aa33cbd4..2ee08031ede 100644 --- a/pymatgen/io/template.py +++ b/pymatgen/io/template.py @@ -13,7 +13,7 @@ from pymatgen.io.core import InputGenerator, InputSet if TYPE_CHECKING: - from pathlib import Path + from pymatgen.util.typing import PathLike __author__ = "Ryan Kingsbury" __email__ = "RKingsbury@lbl.gov" @@ -31,9 +31,12 @@ class TemplateInputGen(InputGenerator): classes. """ - def get_input_set( # type: ignore - self, template: str | Path, variables: dict | None = None, filename: str = "input.txt" - ): + def get_input_set( + self, + template: PathLike, + variables: dict | None = None, + filename: PathLike = "input.txt", + ) -> InputSet: """ Args: template: the input file template containing variable strings to be @@ -42,16 +45,16 @@ def get_input_set( # type: ignore text to replaced with the values, e.g. {"TEMPERATURE": 298} will replace the text $TEMPERATURE in the template. See Python's Template.safe_substitute() method documentation for more details. - filename: name of the file to be written. + filename: the file to be written. """ self.template = template self.variables = variables or {} - self.filename = filename + self.filename = str(filename) - # load the template + # Load the template with zopen(self.template, mode="r") as file: template_str = file.read() - # replace all variables + # Replace all variables self.data = Template(template_str).safe_substitute(**self.variables) return InputSet({self.filename: self.data}) diff --git a/pymatgen/io/vasp/inputs.py b/pymatgen/io/vasp/inputs.py index c8989160086..9c568157330 100644 --- a/pymatgen/io/vasp/inputs.py +++ b/pymatgen/io/vasp/inputs.py @@ -1489,12 +1489,12 @@ def copy(self) -> Self: return self.from_dict(self.as_dict()) @classmethod - def from_file(cls, filename: str | Path) -> Self: + def from_file(cls, filename: PathLike) -> Self: """ Reads a Kpoints object from a KPOINTS file. Args: - filename (str): filename to read from. + filename (PathLike): filename to read from. Returns: Kpoints object diff --git a/pymatgen/io/vasp/optics.py b/pymatgen/io/vasp/optics.py index 206b55816ef..9e1e1b66cf7 100644 --- a/pymatgen/io/vasp/optics.py +++ b/pymatgen/io/vasp/optics.py @@ -130,7 +130,7 @@ def _try_reading(dtypes): except ValueError as exc: if "reshape" in str(exc): continue - raise exc + raise return None vrun = Vasprun(f"{directory}/vasprun.xml") @@ -414,7 +414,7 @@ def epsilon_imag( except ValueError as exc: if "zero-size array" in str(exc): return egrid, np.zeros_like(egrid, dtype=np.complex128) - raise exc + raise _, _, nk, nspin = cderm.shape[:4] iter_idx = [ range(min_band0, max_band0 + 1), diff --git a/pymatgen/io/vasp/outputs.py b/pymatgen/io/vasp/outputs.py index 7eccca20661..ab9721aba0d 100644 --- a/pymatgen/io/vasp/outputs.py +++ b/pymatgen/io/vasp/outputs.py @@ -2,6 +2,7 @@ from __future__ import annotations +import datetime import itertools import logging import math @@ -12,7 +13,6 @@ from collections import defaultdict from collections.abc import Iterable from dataclasses import dataclass -from datetime import datetime from glob import glob from io import StringIO from pathlib import Path @@ -155,13 +155,13 @@ def _vasprun_float(flt: float | str) -> float: try: return float(flt) - except ValueError as exc: + except ValueError: flt = cast(str, flt) _flt: str = flt.strip() if _flt == "*" * len(_flt): warnings.warn("Float overflow (*******) encountered in vasprun") return np.nan - raise exc + raise @dataclass @@ -526,9 +526,9 @@ def _parse( if "kinetic" in d: md_data[-1]["energy"] = {i.attrib["name"]: float(i.text) for i in elem.findall("i")} - except ET.ParseError as exc: + except ET.ParseError: if self.exception_on_bad_xml: - raise exc + raise warnings.warn( "XML is malformed. Parsing has stopped but partial data is available.", UserWarning, @@ -846,7 +846,7 @@ def get_computed_entry( ComputedStructureEntry/ComputedEntry """ if entry_id is None: - entry_id = f"vasprun-{datetime.now()}" + entry_id = f"vasprun-{datetime.datetime.now(tz=datetime.timezone.utc)}" param_names = { "is_hubbard", "hubbards", @@ -1379,12 +1379,12 @@ def _parse_params(self, elem: XML_Element) -> dict: else: params[name] = _parse_v_parameters(ptype, val, self.filename, name) - except Exception as exc: + except Exception: if name == "RANDOM_SEED": # Handle the case where RANDOM_SEED > 99999, which results in ***** params[name] = None else: - raise exc + raise elem.clear() return Incar(params) @@ -1398,12 +1398,12 @@ def parse_atomic_symbol(symbol: str) -> str: return str(Element(symbol)) # vasprun.xml uses "X" instead of "Xe" for Xenon - except ValueError as exc: + except ValueError: if symbol == "X": return "Xe" if symbol == "r": return "Zr" - raise exc + raise atomic_symbols = [] potcar_symbols = [] diff --git a/pymatgen/io/vasp/sets.py b/pymatgen/io/vasp/sets.py index eaa8a93cb01..bd89a447cfb 100644 --- a/pymatgen/io/vasp/sets.py +++ b/pymatgen/io/vasp/sets.py @@ -1404,14 +1404,20 @@ def kpoints_updates(self) -> dict | Kpoints: factor = self.small_gap_multiply[1] # prefer to use k-point scheme from previous run unless lepsilon = True is specified - if self.prev_kpoints and self.prev_kpoints.style == Kpoints.supported_modes.Monkhorst and not self.lepsilon: # type: ignore + if ( + self.prev_kpoints + and isinstance(self.prev_kpoints, Kpoints) + and self.prev_kpoints.style == Kpoints.supported_modes.Monkhorst + and not self.lepsilon + and self.structure is not None + ): kpoints = Kpoints.automatic_density_by_vol( - self.structure, # type: ignore + self.structure, int(self.reciprocal_density * factor), self.force_gamma, ) - k_div = [kp + 1 if kp % 2 == 1 else kp for kp in kpoints.kpts[0]] # type: ignore - return Kpoints.monkhorst_automatic(k_div) # type: ignore + k_div = cast(Kpoint, tuple(kp + 1 if kp % 2 == 1 else kp for kp in kpoints.kpts[0])) + return Kpoints.monkhorst_automatic(k_div) return {"reciprocal_density": self.reciprocal_density * factor} @@ -1919,11 +1925,11 @@ def incar_updates(self) -> dict[str, Any]: PREC="ACCURATE", SIGMA=0.01, ) - elif self.mode.lower() == "efg": + elif self.mode.lower() == "efg" and self.structure is not None: isotopes = {ist.split("-")[0]: ist for ist in self.isotopes} quad_efg = [ - float(Species(s.name).get_nmr_quadrupole_moment(isotopes.get(s.name))) - for s in self.structure.species # type: ignore + float(Species(sp.name).get_nmr_quadrupole_moment(isotopes.get(sp.name))) + for sp in self.structure.species ] updates.update( ALGO="FAST", @@ -2129,9 +2135,9 @@ def incar_updates(self) -> dict[str, Any]: updates |= {"ISIF": 2, "LVTOT": True, "NELMIN": 8} if self.set_mix: updates |= {"AMIN": 0.01, "AMIX": 0.2, "BMIX": 0.001} - if self.auto_dipole: - weights = [s.species.weight for s in self.structure] # type: ignore - center_of_mass = np.average(self.structure.frac_coords, weights=weights, axis=0) # type: ignore + if self.auto_dipole and self.structure is not None: + weights = [struct.species.weight for struct in self.structure] + center_of_mass = np.average(self.structure.frac_coords, weights=weights, axis=0) updates |= {"IDIPOL": 3, "LDIPOL": True, "DIPOL": center_of_mass} return updates @@ -2343,8 +2349,8 @@ def write_input( make_dir_if_not_present (bool): Set to True if you want the directory (and the whole path) to be created if it is not present. - write_cif (bool): If true, writes a cif along with each POSCAR. - write_path_cif (bool): If true, writes a cif for each image. + write_cif (bool): If true, writes a CIF along with each POSCAR. + write_path_cif (bool): If true, writes a CIF for each image. write_endpoint_inputs (bool): If true, writes input files for running endpoint calculations. """ diff --git a/pymatgen/io/xr.py b/pymatgen/io/xr.py index 60a9ac01975..645c8a6910c 100644 --- a/pymatgen/io/xr.py +++ b/pymatgen/io/xr.py @@ -126,16 +126,16 @@ def from_str(cls, string: str, use_cores: bool = True, thresh: float = 1.0e-4) - r"\d+\s+(\w+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)", lines[4 + j].strip(), ): - tmp_sp = match.group(1) + tmp_sp = match[1] if use_cores and tmp_sp[len(tmp_sp) - 2 :] == "_s": continue if not use_cores and tmp_sp[len(tmp_sp) - 2 :] == "_c": continue if tmp_sp[len(tmp_sp) - 2] == "_": - sp.append(tmp_sp[0 : len(tmp_sp) - 2]) + sp.append(tmp_sp[: len(tmp_sp) - 2]) else: sp.append(tmp_sp) - coords.append([float(match.group(i)) for i in range(2, 5)]) + coords.append([float(match[i]) for i in range(2, 5)]) return cls(Structure(lattice, sp, coords, coords_are_cartesian=True)) @classmethod diff --git a/pymatgen/io/xyz.py b/pymatgen/io/xyz.py index d09c7a26edb..81430321a28 100644 --- a/pymatgen/io/xyz.py +++ b/pymatgen/io/xyz.py @@ -62,7 +62,7 @@ def _from_frame_str(contents) -> Molecule: coord_pattern = re.compile(r"(\w+)\s+([0-9\-\+\.*^eEdD]+)\s+([0-9\-\+\.*^eEdD]+)\s+([0-9\-\+\.*^eEdD]+)") for idx in range(2, 2 + n_sites): if match := coord_pattern.search(lines[idx]): - sp.append(match.group(1)) # this is 1-indexed + sp.append(match[1]) # this is 1-indexed # this is 0-indexed # in case of 0.0D+00 or 0.00d+01 old double precision writing # replace d or D by e for ten power exponent, @@ -92,7 +92,7 @@ def from_str(cls, contents: str) -> Self: pat = re.compile(frame_pattern_text, re.MULTILINE) mols = [] for xyz_match in pat.finditer(contents): - xyz_text = xyz_match.group(0) + xyz_text = xyz_match[0] mols.append(XYZ._from_frame_str(xyz_text)) return cls(mols) diff --git a/pymatgen/io/zeopp.py b/pymatgen/io/zeopp.py index 70f8d13e141..fa8299a2925 100644 --- a/pymatgen/io/zeopp.py +++ b/pymatgen/io/zeopp.py @@ -128,11 +128,11 @@ def from_str(cls, string: str) -> Self: r"\d+\s+(\w+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+(?:0\s+){8}([0-9\-\.]+)", line.strip(), ): - sp.append(match.group(1)) - # coords.append([float(m.group(i)) for i in xrange(2, 5)]) + sp.append(match[1]) + # coords.append([float(m[i]) for i in xrange(2, 5)]) # Zeo++ takes x-axis along a and pymatgen takes z-axis along c - coords.append([float(match.group(i)) for i in [3, 4, 2]]) - charge.append(match.group(5)) + coords.append([float(match[i]) for i in [3, 4, 2]]) + charge.append(match[5]) return cls(Structure(lattice, sp, coords, site_properties={"charge": charge})) @classmethod @@ -183,10 +183,10 @@ def from_str(cls, contents: str) -> Self: coord_patt = re.compile(r"(\w+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)") for idx in range(2, 2 + n_sites): if match := coord_patt.search(lines[idx]): - sp.append(match.group(1)) # this is 1-indexed + sp.append(match[1]) # this is 1-indexed # coords.append(map(float, m.groups()[1:4])) # this is 0-indexed - coords.append([float(j) for j in [match.group(i) for i in [3, 4, 2]]]) - prop.append(float(match.group(5))) + coords.append([float(j) for j in [match[i] for i in [3, 4, 2]]]) + prop.append(float(match[5])) return cls(Molecule(sp, coords, site_properties={"voronoi_radius": prop})) @classmethod diff --git a/pymatgen/phonon/gruneisen.py b/pymatgen/phonon/gruneisen.py index 1d309a81c75..a4aee2cc443 100644 --- a/pymatgen/phonon/gruneisen.py +++ b/pymatgen/phonon/gruneisen.py @@ -169,7 +169,7 @@ def thermal_conductivity_slack( return thermal_cond - @property # type: ignore + @property @requires(phonopy, "This method requires phonopy to be installed") def tdos(self): """The total DOS (re)constructed from the gruneisen.yaml file.""" diff --git a/pymatgen/phonon/plotter.py b/pymatgen/phonon/plotter.py index ad4fb598cef..4fe7295fe15 100644 --- a/pymatgen/phonon/plotter.py +++ b/pymatgen/phonon/plotter.py @@ -93,7 +93,7 @@ def __init__(self, stack: bool = False, sigma: float | None = None) -> None: # a likely user mistake is to try to pass a DOS as the first argument (similar to PhononBSPlotter) but # without the isinstance check, this would not raise an error and just silently cause a blank plot if not isinstance(stack, bool): - raise ValueError( + raise TypeError( "The first argument stack expects a boolean. If you are trying to add a DOS, use the add_dos() method." ) self.stack = stack @@ -293,7 +293,7 @@ def __init__(self, bs: PhononBandStructureSymmLine, label: str | None = None) -> the plot_compare method to distinguish the band structures. """ if not isinstance(bs, PhononBandStructureSymmLine): - raise ValueError( + raise TypeError( "PhononBSPlotter only works with PhononBandStructureSymmLine objects. " "A PhononBandStructure object (on a uniform grid for instance and " "not along symmetry lines won't work)" @@ -476,7 +476,7 @@ def get_proj_plot( assert 0 <= idx < len(all_sites), "one or more indices in site_comb does not exist" all_indices.remove(idx) if len(all_indices) != 0: - raise Exception(f"not all {len(all_sites)} indices are included in site_comb") + raise ValueError(f"not all {len(all_sites)} indices are included in site_comb") indices = site_comb # type: ignore[assignment] assert rgb_labels is None or len(rgb_labels) == len(indices), "wrong number of rgb_labels" @@ -1007,7 +1007,7 @@ def __init__(self, bs: GruneisenPhononBandStructureSymmLine) -> None: bs: A GruneisenPhononBandStructureSymmLine object. """ if not isinstance(bs, GruneisenPhononBandStructureSymmLine): - raise ValueError( + raise TypeError( "GruneisenPhononBSPlotter only works with GruneisenPhononBandStructureSymmLine objects. " "A GruneisenPhononBandStructure object (on a uniform grid for instance and " "not along symmetry lines won't work)" diff --git a/pymatgen/phonon/thermal_displacements.py b/pymatgen/phonon/thermal_displacements.py index 3df4e1ff2e0..dffab4c8439 100644 --- a/pymatgen/phonon/thermal_displacements.py +++ b/pymatgen/phonon/thermal_displacements.py @@ -37,7 +37,7 @@ sub_spgrp = partial(re.sub, r"[\s_]", "") -space_groups = {sub_spgrp(k): k for k in SYMM_DATA["space_group_encoding"]} # type: ignore +space_groups = {sub_spgrp(k): k for k in SYMM_DATA["space_group_encoding"]} class ThermalDisplacementMatrices(MSONable): @@ -97,19 +97,19 @@ def get_full_matrix(thermal_displacement: ArrayLike[ArrayLike]) -> np.ndarray[np Returns: 3d numpy array including thermal displacements, first dimensions are the atoms """ - matrixform = np.zeros((len(thermal_displacement), 3, 3)) - for imat, mat in enumerate(thermal_displacement): + matrix_form = np.zeros((len(thermal_displacement), 3, 3)) + for idx, mat in enumerate(thermal_displacement): # xx, yy, zz, yz, xz, xy - matrixform[imat][0][0] = mat[0] - matrixform[imat][1][1] = mat[1] - matrixform[imat][2][2] = mat[2] - matrixform[imat][1][2] = mat[3] - matrixform[imat][2][1] = mat[3] - matrixform[imat][0][2] = mat[4] - matrixform[imat][2][0] = mat[4] - matrixform[imat][0][1] = mat[5] - matrixform[imat][1][0] = mat[5] - return matrixform + matrix_form[idx][0][0] = mat[0] + matrix_form[idx][1][1] = mat[1] + matrix_form[idx][2][2] = mat[2] + matrix_form[idx][1][2] = mat[3] + matrix_form[idx][2][1] = mat[3] + matrix_form[idx][0][2] = mat[4] + matrix_form[idx][2][0] = mat[4] + matrix_form[idx][0][1] = mat[5] + matrix_form[idx][1][0] = mat[5] + return matrix_form @staticmethod def get_reduced_matrix(thermal_displacement: ArrayLike[ArrayLike]) -> np.ndarray[np.ndarray]: @@ -203,20 +203,20 @@ def U1U2U3(self) -> list: Returns: np.array: eigenvalues of Ucart. First dimension are the atoms in the structure. """ - U1U2U3 = [] + u1u2u3_eig_vals = [] for mat in self.thermal_displacement_matrix_cart_matrixform: - U1U2U3.append(np.linalg.eig(mat)[0]) - return U1U2U3 + u1u2u3_eig_vals.append(np.linalg.eig(mat)[0]) + return u1u2u3_eig_vals def write_cif(self, filename: str) -> None: - """Write a cif including thermal displacements. + """Write a CIF including thermal displacements. Args: - filename: name of the cif file + filename: name of the CIF file """ writer = CifWriter(self.structure) writer.write_file(filename) - # This will simply append the thermal displacement part to the cif from the CifWriter + # This will simply append the thermal displacement part to the CIF from the CifWriter # In the long run, CifWriter could be extended to handle thermal displacement matrices with open(filename, mode="a") as file: file.write("loop_ \n") @@ -396,7 +396,7 @@ def visualize_directionality_quality_criterion( counter = 1 # two vectors per atom - for _i in range(len(result)): + for _ in range(len(result)): file.write(f"{counter} 0.2 255 0 0 1\n") counter += 1 file.write(f"{counter} 0.2 0 0 255 1\n") @@ -514,7 +514,7 @@ def from_structure_with_site_properties_Ucif(cls, structure: Structure, temperat @staticmethod def from_cif_P1(filename: str) -> list[ThermalDisplacementMatrices]: - """Reads a cif with P1 symmetry including positions and ADPs. + """Reads a CIF with P1 symmetry including positions and ADPs. Currently, no check of symmetry is performed as CifParser methods cannot be easily reused. Args: diff --git a/pymatgen/symmetry/groups.py b/pymatgen/symmetry/groups.py index d9fbc66cfdb..3ecaf8ac1d1 100644 --- a/pymatgen/symmetry/groups.py +++ b/pymatgen/symmetry/groups.py @@ -268,15 +268,15 @@ def __init__(self, int_symbol: str) -> None: def _generate_full_symmetry_ops(self) -> np.ndarray: symm_ops = np.array(self.generators) for op in symm_ops: - op[0:3, 3] = np.mod(op[0:3, 3], 1) + op[:3, 3] = np.mod(op[:3, 3], 1) new_ops = symm_ops while len(new_ops) > 0 and len(symm_ops) < self.order: gen_ops = [] for g in new_ops: temp_ops = np.einsum("ijk,kl", symm_ops, g) for op in temp_ops: - op[0:3, 3] = np.mod(op[0:3, 3], 1) - ind = np.where(np.abs(1 - op[0:3, 3]) < 1e-5) + op[:3, 3] = np.mod(op[:3, 3], 1) + ind = np.where(np.abs(1 - op[:3, 3]) < 1e-5) op[ind, 3] = 0 if not in_array_list(symm_ops, op): gen_ops.append(op) diff --git a/pymatgen/symmetry/kpath.py b/pymatgen/symmetry/kpath.py index 3d4ad5ea1f3..ff555acc7fe 100644 --- a/pymatgen/symmetry/kpath.py +++ b/pymatgen/symmetry/kpath.py @@ -25,7 +25,7 @@ if TYPE_CHECKING: from typing import Any - from pymatgen.core import Structure + from pymatgen.core import Composition, Structure from pymatgen.util.typing import SpeciesLike __author__ = "Geoffroy Hautier, Katherine Latimer, Jason Munro" @@ -890,11 +890,11 @@ def __init__(self, structure: Structure, symprec: float = 0.01, angle_tolerance= sp = structure.site_properties species = [site.species for site in structure] - site_data = species + site_data: list[Composition] = species if not system_is_tri: warn("Non-zero 'magmom' data will be used to define unique atoms in the cell.") - site_data = zip(species, [tuple(vec) for vec in sp["magmom"]]) # type: ignore + site_data = zip(species, [tuple(vec) for vec in sp["magmom"]]) # type: ignore[assignment] unique_species: list[SpeciesLike] = [] numbers = [] diff --git a/pymatgen/transformations/advanced_transformations.py b/pymatgen/transformations/advanced_transformations.py index 3e44b713df6..fa1b209915f 100644 --- a/pymatgen/transformations/advanced_transformations.py +++ b/pymatgen/transformations/advanced_transformations.py @@ -461,7 +461,7 @@ def sort_func(struct): self._all_structures = sorted(all_structures, key=sort_func) if return_ranked_list: - return self._all_structures[0:num_to_return] + return self._all_structures[:num_to_return] return self._all_structures[0]["structure"] def __repr__(self): @@ -638,7 +638,7 @@ def __init__(self, mag_species_spin, order_parameter=0.5, energy_model=None, **k if not any(ops): raise ValueError("Order parameter not correctly defined.") else: - raise ValueError("Order parameter not correctly defined.") + raise ValueError("Order parameter not correctly defined.") # noqa: TRY004 self.mag_species_spin = mag_species_spin # store order parameter constraints as dicts to save implementing @@ -860,9 +860,9 @@ def apply_transformation( alls = self._remove_dummy_species(alls) alls = self._add_spin_magnitudes(alls) # type: ignore[arg-type] else: - for idx in range(len(alls)): - alls[idx]["structure"] = self._remove_dummy_species(alls[idx]["structure"]) # type: ignore[index] - alls[idx]["structure"] = self._add_spin_magnitudes(alls[idx]["structure"]) # type: ignore[index, arg-type] + for idx, struct in enumerate(alls): + alls[idx]["structure"] = self._remove_dummy_species(struct["structure"]) # type: ignore[index] + alls[idx]["structure"] = self._add_spin_magnitudes(struct["structure"]) # type: ignore[index, arg-type] try: num_to_return = int(return_ranked_list) @@ -872,7 +872,7 @@ def apply_transformation( if num_to_return == 1 or not return_ranked_list: return alls[0]["structure"] if num_to_return else alls # type: ignore[return-value, index] - # remove duplicate structures and group according to energy model + # Remove duplicate structures and group according to energy model matcher = StructureMatcher(comparator=SpinComparator()) def key(struct: Structure) -> int: @@ -880,13 +880,13 @@ def key(struct: Structure) -> int: out = [] for _, group in groupby(sorted((dct["structure"] for dct in alls), key=key), key): # type: ignore[arg-type, index] - group = list(group) # type: ignore + group = list(group) # type: ignore[assignment] grouped = matcher.group_structures(group) out.extend([{"structure": g[0], "energy": self.energy_model.get_energy(g[0])} for g in grouped]) self._all_structures = sorted(out, key=lambda dct: dct["energy"]) - return self._all_structures[0:num_to_return] # type: ignore + return self._all_structures[:num_to_return] # type: ignore[return-value] @property def is_one_to_many(self) -> bool: @@ -1034,13 +1034,13 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | supercell = structure * scaling nsp = supercell.composition[sp] if sp.oxi_state == ox: - supercell.replace_species({sp: {sp: (nsp - 1) / nsp, self.dopant: 1 / nsp}}) # type: ignore + supercell.replace_species({sp: {sp: (nsp - 1) / nsp, self.dopant: 1 / nsp}}) logger.info(f"Doping {sp} for {self.dopant} at level {1 / nsp:.3f}") elif self.codopant: - codopant = find_codopant(sp, 2 * sp.oxi_state - ox) # type: ignore - supercell.replace_species({sp: {sp: (nsp - 2) / nsp, self.dopant: 1 / nsp, codopant: 1 / nsp}}) # type: ignore + codopant = find_codopant(sp, 2 * sp.oxi_state - ox) # type: ignore[arg-type, operator] + supercell.replace_species({sp: {sp: (nsp - 2) / nsp, self.dopant: 1 / nsp, codopant: 1 / nsp}}) logger.info(f"Doping {sp} for {self.dopant} + {codopant} at level {1 / nsp:.3f}") - elif abs(sp.oxi_state) < abs(ox): # type: ignore + elif abs(sp.oxi_state) < abs(ox): # type: ignore[arg-type] # Strategy: replace the target species with a # combination of dopant and vacancy. # We will choose the lowest oxidation state species as a @@ -1048,20 +1048,18 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | # energy sp_to_remove = min( (s for s in comp if s.oxi_state * ox > 0), - key=lambda ss: abs(ss.oxi_state), # type: ignore + key=lambda ss: abs(ss.oxi_state), # type: ignore[arg-type] ) if sp_to_remove == sp: - common_charge = lcm(int(abs(sp.oxi_state)), int(abs(ox))) # type: ignore + common_charge = lcm(int(abs(sp.oxi_state)), int(abs(ox))) # type: ignore[arg-type] n_dopant = common_charge / abs(ox) - nsp_to_remove = common_charge / abs(sp.oxi_state) # type: ignore + nsp_to_remove = common_charge / abs(sp.oxi_state) # type: ignore[arg-type] logger.info(f"Doping {nsp_to_remove} {sp} with {n_dopant} {self.dopant}.") - supercell.replace_species( - {sp: {sp: (nsp - nsp_to_remove) / nsp, self.dopant: n_dopant / nsp}} # type: ignore - ) + supercell.replace_species({sp: {sp: (nsp - nsp_to_remove) / nsp, self.dopant: n_dopant / nsp}}) else: ox_diff = int(abs(round(sp.oxi_state - ox))) - vac_ox = int(abs(sp_to_remove.oxi_state)) * ox_diff # type: ignore + vac_ox = int(abs(sp_to_remove.oxi_state)) * ox_diff # type: ignore[arg-type] common_charge = lcm(vac_ox, ox_diff) n_dopant = common_charge / ox_diff nx_to_remove = common_charge / vac_ox @@ -1071,11 +1069,11 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | ) supercell.replace_species( { - sp: {sp: (nsp - n_dopant) / nsp, self.dopant: n_dopant / nsp}, # type: ignore - sp_to_remove: {sp_to_remove: (nx - nx_to_remove) / nx}, # type: ignore + sp: {sp: (nsp - n_dopant) / nsp, self.dopant: n_dopant / nsp}, + sp_to_remove: {sp_to_remove: (nx - nx_to_remove) / nx}, } ) - elif abs(sp.oxi_state) > abs(ox): # type: ignore + elif abs(sp.oxi_state) > abs(ox): # type: ignore[arg-type] # Strategy: replace the target species with dopant and also # remove some opposite charged species for charge neutrality if ox > 0: @@ -1083,10 +1081,10 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | else: sp_to_remove = min(supercell.composition, key=lambda el: el.X) # Confirm species are of opposite oxidation states. - assert sp_to_remove.oxi_state * sp.oxi_state < 0 # type: ignore + assert sp_to_remove.oxi_state * sp.oxi_state < 0 # type: ignore[operator] ox_diff = int(abs(round(sp.oxi_state - ox))) - anion_ox = int(abs(sp_to_remove.oxi_state)) # type: ignore + anion_ox = int(abs(sp_to_remove.oxi_state)) # type: ignore[arg-type] nx = supercell.composition[sp_to_remove] common_charge = lcm(anion_ox, ox_diff) n_dopant = common_charge / ox_diff @@ -1094,8 +1092,8 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | logger.info(f"Doping {n_dopant} {sp} with {self.dopant} and removing {nx_to_remove} {sp_to_remove}.") supercell.replace_species( { - sp: {sp: (nsp - n_dopant) / nsp, self.dopant: n_dopant / nsp}, # type: ignore - sp_to_remove: {sp_to_remove: (nx - nx_to_remove) / nx}, # type: ignore + sp: {sp: (nsp - n_dopant) / nsp, self.dopant: n_dopant / nsp}, + sp_to_remove: {sp_to_remove: (nx - nx_to_remove) / nx}, } ) @@ -1233,7 +1231,7 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | if not return_ranked_list: return disordered_structures[0]["structure"] if len(disordered_structures) > return_ranked_list: - disordered_structures = disordered_structures[0:return_ranked_list] + disordered_structures = disordered_structures[:return_ranked_list] return disordered_structures @property @@ -1494,7 +1492,7 @@ def apply_transformation(self, structure: Structure) -> Structure: target_sc_size = self.min_length while sc_not_found: target_sc_lat_vecs = np.eye(3, 3) * target_sc_size - self.transformation_matrix = target_sc_lat_vecs @ np.linalg.inv(lat_vecs) # type: ignore + self.transformation_matrix = target_sc_lat_vecs @ np.linalg.inv(lat_vecs) # round the entries of T and force T to be non-singular self.transformation_matrix = _round_and_make_arr_singular( # type: ignore[assignment] diff --git a/pymatgen/transformations/site_transformations.py b/pymatgen/transformations/site_transformations.py index 189adbbcda0..220769fd0f4 100644 --- a/pymatgen/transformations/site_transformations.py +++ b/pymatgen/transformations/site_transformations.py @@ -442,7 +442,7 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | raise ValueError("Invalid algo.") opt_s = all_structures[0]["structure"] - return opt_s if not return_ranked_list else all_structures[0:num_to_return] + return opt_s if not return_ranked_list else all_structures[:num_to_return] def __repr__(self): return f"PartialRemoveSitesTransformation : Indices and fraction to remove = {self.indices}, ALGO = {self.algo}" diff --git a/pymatgen/transformations/standard_transformations.py b/pymatgen/transformations/standard_transformations.py index ec5fa46e020..92bbe883da7 100644 --- a/pymatgen/transformations/standard_transformations.py +++ b/pymatgen/transformations/standard_transformations.py @@ -218,7 +218,7 @@ def from_boundary_distance( # Try to find a scaling_matrix satisfying the required boundary distance with smaller cell. if allow_rotation and sum(min_expand != 0) > 1: - min1, min2, min3 = map(int, min_expand) # type: ignore # map(int) just for mypy's sake + min1, min2, min3 = map(int, min_expand) scaling_matrix = [ [min1 or 1, 1 if min1 and min2 else 0, 1 if min1 and min3 else 0], [-1 if min2 and min1 else 0, min2 or 1, 1 if min2 and min3 else 0], @@ -279,9 +279,9 @@ def __init__( """ self.species_map = species_map self._species_map = dict(species_map) - for k, v in self._species_map.items(): - if isinstance(v, (tuple, list)): - self._species_map[k] = dict(v) # type: ignore[assignment] + for key, val in self._species_map.items(): + if isinstance(val, (tuple, list)): + self._species_map[key] = dict(val) # type: ignore[assignment] def apply_transformation(self, structure: Structure) -> Structure: """Apply the transformation. diff --git a/pymatgen/util/due.py b/pymatgen/util/due.py index 62e27c63766..2f77758a45c 100644 --- a/pymatgen/util/due.py +++ b/pymatgen/util/due.py @@ -51,7 +51,7 @@ def _donothing_func(*args, **kwargs): raise RuntimeError("Imported due lacks .cite. DueCredit is now disabled") except Exception as exc: if not isinstance(exc, ImportError): - logging.getLogger("duecredit").error(f"Failed to import duecredit due to {exc}") + logging.getLogger("duecredit").exception("Failed to import duecredit") # Initiate due stub due = InactiveDueCreditCollector() BibTeX = Doi = Url = Text = _donothing_func diff --git a/pymatgen/util/provenance.py b/pymatgen/util/provenance.py index 4402653b9b5..7fcb5c54a4b 100644 --- a/pymatgen/util/provenance.py +++ b/pymatgen/util/provenance.py @@ -214,7 +214,7 @@ def __init__( # check that references are valid BibTeX if not isinstance(references, str): - raise ValueError("Invalid format for SNL reference! Should be empty string or BibTeX string.") + raise TypeError("Invalid format for SNL reference! Should be empty string or BibTeX string.") if references and not is_valid_bibtex(references): raise ValueError("Invalid format for SNL reference! Should be BibTeX string.") if len(references) > MAX_BIBTEX_CHARS: diff --git a/pymatgen/util/string.py b/pymatgen/util/string.py index c8d1703bb87..48a681c40cc 100644 --- a/pymatgen/util/string.py +++ b/pymatgen/util/string.py @@ -71,13 +71,13 @@ def to_unicode_string(self): with systems where the sub and superscripts are pure integers. """ str_ = self.to_latex_string() - for m in re.finditer(r"\$_\{(\d+)\}\$", str_): - s1 = m.group() - s2 = [SUBSCRIPT_UNICODE[s] for s in m.group(1)] + for match in re.finditer(r"\$_\{(\d+)\}\$", str_): + s1 = match.group() + s2 = [SUBSCRIPT_UNICODE[s] for s in match[1]] str_ = str_.replace(s1, "".join(s2)) - for m in re.finditer(r"\$\^\{([\d\+\-]+)\}\$", str_): - s1 = m.group() - s2 = [SUPERSCRIPT_UNICODE[s] for s in m.group(1)] + for match in re.finditer(r"\$\^\{([\d\+\-]+)\}\$", str_): + s1 = match.group() + s2 = [SUPERSCRIPT_UNICODE[s] for s in match[1]] str_ = str_.replace(s1, "".join(s2)) return str_ @@ -416,4 +416,4 @@ def disordered_formula(disordered_struct, symbols=("x", "y", "z"), fmt="plain"): disordered_formula.append(" ") disordered_formula += [f"{key}={formula_double_format(val)} " for key, val in variable_map.items()] - return "".join(map(str, disordered_formula))[0:-1] + return "".join(map(str, disordered_formula))[:-1] diff --git a/pymatgen/vis/plotters.py b/pymatgen/vis/plotters.py index 1692c923562..5670e24f8ae 100644 --- a/pymatgen/vis/plotters.py +++ b/pymatgen/vis/plotters.py @@ -10,9 +10,10 @@ class SpectrumPlotter: - """Plot Spectrum objects and subclasses. Note that the interface - is extremely flexible given that there are many different ways in which - people want to view spectra. The typical usage is: + """Plot Spectrum objects and subclasses. + + Note that the interface is extremely flexible given that there are many + different ways in which people want to view spectra. The typical usage is: # Initializes plotter with some optional args. Defaults are usually # fine, @@ -129,6 +130,7 @@ def save_plot(self, filename: str, **kwargs): Args: filename (str): Filename to write to. Must include extension to specify image format. + kwargs: passed to get_plot. """ self.get_plot(**kwargs) plt.savefig(filename) diff --git a/pymatgen/vis/structure_vtk.py b/pymatgen/vis/structure_vtk.py index b309372422c..c2329591744 100644 --- a/pymatgen/vis/structure_vtk.py +++ b/pymatgen/vis/structure_vtk.py @@ -629,11 +629,11 @@ def add_faces(self, faces, color, opacity=0.35): else: raise ValueError("Number of points for a face should be >= 3") - def add_edges(self, edges, type="line", linewidth=2, color=(0.0, 0.0, 0.0)): + def add_edges(self, edges, type="line", linewidth=2, color=(0.0, 0.0, 0.0)): # noqa: A002 """ Args: edges (): List of edges - type (): + type (): placeholder linewidth (): Width of line color (nd.array/tuple): RGB color. """ @@ -702,7 +702,7 @@ def add_bonds(self, neighbors, center, color=None, opacity=None, radius=0.1): self.ren.AddActor(actor) def add_picker_fixed(self): - """Create a cell picker.Returns:""" + """Create a cell picker.""" picker = vtk.vtkCellPicker() # Create a Python function to create the text for the text mapper used @@ -772,6 +772,7 @@ class StructureInteractorStyle(TrackballCamera): """A custom interactor style for visualizing structures.""" def __init__(self, parent): + """Initialize StructureInteractorStyle.""" self.parent = parent self.AddObserver("LeftButtonPressEvent", self.leftButtonPressEvent) self.AddObserver("MouseMoveEvent", self.mouseMoveEvent) @@ -779,14 +780,17 @@ def __init__(self, parent): self.AddObserver("KeyPressEvent", self.keyPressEvent) def leftButtonPressEvent(self, obj, event): + """Left mouse button press event.""" self.mouse_motion = 0 self.OnLeftButtonDown() def mouseMoveEvent(self, obj, event): + """Mouse move event.""" self.mouse_motion = 1 self.OnMouseMove() def leftButtonReleaseEvent(self, obj, event): + """Left mouse button release event.""" ren = obj.GetCurrentRenderer() iren = ren.GetRenderWindow().GetInteractor() if self.mouse_motion == 0: @@ -795,6 +799,7 @@ def leftButtonReleaseEvent(self, obj, event): self.OnLeftButtonUp() def keyPressEvent(self, obj, _event): + """Key press event.""" parent = obj.GetCurrentRenderer().parent sym = parent.iren.GetKeySym() @@ -873,19 +878,19 @@ def make_movie(structures, output_filename="movie.mp4", zoom=1.0, fps=20, bitrat vis.write_image(filename.format(idx), 3) filename = f"image%0{sig_fig}d.png" args = ["ffmpeg", "-y", "-i", filename, "-q:v", str(quality), "-r", str(fps), "-b:v", str(bitrate), output_filename] - with subprocess.Popen(args) as p: - p.communicate() + with subprocess.Popen(args) as process: + process.communicate() class MultiStructuresVis(StructureVis): """Visualization for multiple structures.""" - DEFAULT_ANIMATED_MOVIE_OPTIONS: ClassVar[dict[str, str | float]] = dict( - time_between_frames=0.1, - looping_type="restart", - number_of_loops=1, - time_between_loops=1.0, - ) + DEFAULT_ANIMATED_MOVIE_OPTIONS: ClassVar[dict[str, str | float]] = { + "time_between_frames": 0.1, + "looping_type": "restart", + "number_of_loops": 1, + "time_between_loops": 1.0, + } def __init__( self, @@ -1049,7 +1054,7 @@ def apply_tags(self): def set_animated_movie_options(self, animated_movie_options=None): """ Args: - animated_movie_options (): + animated_movie_options (): animated movie options. """ if animated_movie_options is None: self.animated_movie_options = self.DEFAULT_ANIMATED_MOVIE_OPTIONS.copy() @@ -1138,9 +1143,11 @@ class MultiStructuresInteractorStyle(StructureInteractorStyle): """Interactor for MultiStructureVis.""" def __init__(self, parent) -> None: + """Initialize MultiStructuresInteractorStyle.""" StructureInteractorStyle.__init__(self, parent=parent) def keyPressEvent(self, obj, event): + """Key press event.""" parent = obj.GetCurrentRenderer().parent sym = parent.iren.GetKeySym() diff --git a/pyproject.toml b/pyproject.toml index 0fbc3fe9d70..e520c857330 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -188,57 +188,54 @@ target-version = "py39" line-length = 120 [tool.ruff.lint] -select = [ - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "D", # pydocstyle - "E", # pycodestyle error - "EXE", # flake8-executable - "F", # pyflakes - "FA", # flake8-future-annotations - "FBT003", # boolean-positional-value-in-call - "FLY", # flynt - "I", # isort - "ICN", # flake8-import-conventions - "ISC", # flake8-implicit-str-concat - "NPY201", # numpy 2.0 - "PD", # pandas-vet - "PERF", # perflint - "PIE", # flake8-pie - "PL", # pylint - "PLR0402", - "PLR1714", - "PLR5501", - "PT", # flake8-pytest-style - "PYI", # flakes8-pyi - "Q", # flake8-quotes - "RET", # flake8-return - "RSE", # flake8-raise - "RUF", # Ruff-specific rules - "SIM", # flake8-simplify - "SLOT", # flake8-slots - "TCH", # flake8-type-checking - "TID", # flake8-tidy-imports - "UP", # pyupgrade - "W", # pycodestyle warning - "YTT", # flake8-2020 -] +select = ["ALL"] ignore = [ - "B023", # Function definition does not bind loop variable - "B028", # No explicit stacklevel keyword argument found - "B904", # Within an except clause, raise exceptions with ... - "C408", # unnecessary-collection-call - "D105", # Missing docstring in magic method - "D205", # 1 blank line required between summary line and description - "D212", # Multi-line docstring summary should start at the first line - "PD901", # pandas-df-variable-name - "PERF203", # try-except-in-loop - "PERF401", # manual-list-comprehension - "PLR", # pylint refactor - "PLW2901", # Outer for loop variable overwritten by inner assignment target - "PT013", # pytest-incorrect-pytest-import - "PTH", # prefer pathlib to os.path - "SIM105", # Use contextlib.suppress() instead of try-except-pass + # Rule families + "ANN", # flake8-annotations (not ready, require types for ALL args) + "ARG", # Check for unused function arguments + "BLE", # General catch of Exception + "C90", # Check for functions with a high McCabe complexity + "COM", # flake8-commas (conflict with line wrapper) + "CPY", # Missing copyright notice at top of file (need preview mode) + "EM", # Format nice error messages + "ERA", # Check for commented-out code + "FIX", # Check for FIXME, TODO and other developer notes + "FURB", # refurb (need preview mode, too many preview errors) + "G", # validate logging format strings + "INP", # Ban PEP-420 implicit namespace packages + "N", # pep8-naming (many var/arg names are intended) + "NPY", # NumPy-specific rules (TODO: enable this) + "PTH", # Prefer pathlib over os.path + "S", # flake8-bandit (TODO: enable this) + "SLF", # Access "private" class members + "T20", # Check for print/pprint + "TD", # TODO tags related + + # Single rules + "B023", # Function definition does not bind loop variable + "B028", # No explicit stacklevel keyword argument found + "B904", # Within an except clause, raise exceptions with ... + "C408", # unnecessary-collection-call + "D105", # Missing docstring in magic method + "D205", # 1 blank line required between summary line and description + "D212", # Multi-line docstring summary should start at the first line + "DTZ003", # TODO: fix this (issue #3791) + "FBT001", # Boolean-typed positional argument in function definition + "FBT002", # Boolean default positional argument in function + "PD901", # pandas-df-variable-name + "PERF203", # try-except-in-loop + "PERF401", # manual-list-comprehension + "PLR0911", # too many return statements + "PLR0912", # too many branches + "PLR0913", # too many arguments + "PLR0915", # too many statements + "PLR2004", # magic values in comparison + "PLW2901", # Outer for loop variable overwritten by inner assignment target + "PT013", # pytest-incorrect-pytest-import + "SIM105", # Use contextlib.suppress() instead of try-except-pass + "TRY003", # Avoid specifying long messages outside the exception class + "TRY300", # Checks for return statements in try blocks + "TRY301", # Checks for raise statements within try blocks ] pydocstyle.convention = "google" isort.required-imports = ["from __future__ import annotations"] @@ -249,10 +246,9 @@ docstring-code-format = true [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] -"tests/**" = ["ANN201", "D", "S101"] +"tests/**" = ["ANN201", "D", "PLR0124"] "tasks.py" = ["D"] "pymatgen/analysis/*" = ["D"] -"pymatgen/vis/*" = ["D"] "pymatgen/io/*" = ["D"] "dev_scripts/*" = ["D"] diff --git a/tasks.py b/tasks.py index 33220fc4871..3303ed7043e 100644 --- a/tasks.py +++ b/tasks.py @@ -89,11 +89,11 @@ def publish(ctx: Context) -> None: @task def set_ver(ctx: Context, version: str): - with open("setup.py") as file: + with open("setup.py", encoding="utf-8") as file: contents = file.read() contents = re.sub(r"version=([^,]+),", f"version={version!r},", contents) - with open("setup.py", mode="w") as file: + with open("setup.py", mode="w", encoding="utf-8") as file: file.write(contents) @@ -105,7 +105,7 @@ def release_github(ctx: Context, version: str) -> None: Args: version (str): The version. """ - with open("docs/CHANGES.md") as file: + with open("docs/CHANGES.md", encoding="utf-8") as file: contents = file.read() tokens = re.split(r"\-+", contents) desc = tokens[1].strip() @@ -123,6 +123,7 @@ def release_github(ctx: Context, version: str) -> None: "https://api.github.com/repos/materialsproject/pymatgen/releases", data=json.dumps(payload), headers={"Authorization": f"token {os.environ['GITHUB_RELEASES_TOKEN']}"}, + timeout=600, ) print(response.text) @@ -134,7 +135,7 @@ def post_discourse(version: str) -> None: Args: version (str): The version. """ - with open("CHANGES.rst") as file: + with open("CHANGES.rst", encoding="utf-8") as file: contents = file.read() tokens = re.split(r"\-+", contents) desc = tokens[1].strip() @@ -152,6 +153,7 @@ def post_discourse(version: str) -> None: "api_username": os.environ["DISCOURSE_API_USERNAME"], "api_key": os.environ["DISCOURSE_API_KEY"], }, + timeout=600, ) print(response.text) @@ -167,15 +169,15 @@ def update_changelog(ctx: Context, version: str | None = None, dry_run: bool = F dry_run (bool, optional): If True, the function will only print the changes without updating the actual change log file. Defaults to False. """ - version = version or f"{datetime.datetime.now():%Y.%-m.%-d}" + version = version or f"{datetime.datetime.now(tz=datetime.timezone.utc):%Y.%-m.%-d}" output = subprocess.check_output(["git", "log", "--pretty=format:%s", f"v{__version__}..HEAD"]) lines = [] ignored_commits = [] for line in output.decode("utf-8").strip().split("\n"): re_match = re.match(r"Merge pull request \#(\d+) from (.*)", line) if re_match and "materialsproject/dependabot/pip" not in line: - pr_number = re_match.group(1) - contributor, pr_name = re_match.group(2).split("/", 1) + pr_number = re_match[1] + contributor, pr_name = re_match[2].split("/", 1) response = requests.get( f"https://api.github.com/repos/materialsproject/pymatgen/pulls/{pr_number}", timeout=600 ) @@ -189,7 +191,7 @@ def update_changelog(ctx: Context, version: str | None = None, dry_run: bool = F break lines += [f" {ll}"] ignored_commits += [line] - with open("docs/CHANGES.md") as file: + with open("docs/CHANGES.md", encoding="utf-8") as file: contents = file.read() delim = "##" tokens = contents.split(delim) @@ -197,7 +199,7 @@ def update_changelog(ctx: Context, version: str | None = None, dry_run: bool = F if dry_run: print(tokens[0] + "##".join(tokens[1:])) else: - with open("docs/CHANGES.md", mode="w") as file: + with open("docs/CHANGES.md", mode="w", encoding="utf-8") as file: file.write(tokens[0] + "##".join(tokens[1:])) ctx.run("open docs/CHANGES.md") print("The following commit messages were not included...") @@ -214,7 +216,7 @@ def release(ctx: Context, version: str | None = None, nodoc: bool = False) -> No version (str, optional): The version to release. nodoc (bool, optional): Whether to skip documentation generation. """ - version = version or f"{datetime.datetime.now():%Y.%-m.%-d}" + version = version or f"{datetime.datetime.now(tz=datetime.timezone.utc):%Y.%-m.%-d}" ctx.run("rm -r dist build pymatgen.egg-info", warn=True) set_ver(ctx, version) if not nodoc: diff --git a/tests/analysis/test_interface_reactions.py b/tests/analysis/test_interface_reactions.py index 9b4483ba2c0..3c47a6f9f3c 100644 --- a/tests/analysis/test_interface_reactions.py +++ b/tests/analysis/test_interface_reactions.py @@ -143,12 +143,12 @@ def setUp(self): use_hull_energy=False, ) with pytest.raises( - ValueError, + TypeError, match="Please use the GrandPotentialInterfacialReactivity " "class for interfacial reactions with open elements!", ): _ = InterfacialReactivity(Composition("Li2O2"), Composition("Li"), pd=self.gpd, norm=True) - with pytest.raises(ValueError, match="Please provide non-grand phase diagram to compute no_mixing_energy!"): + with pytest.raises(TypeError, match="Please provide non-grand phase diagram to compute no_mixing_energy!"): _ = GrandPotentialInterfacialReactivity( Composition("O2"), Composition("Mn"), diff --git a/tests/core/test_composition.py b/tests/core/test_composition.py index e55860df0d0..f520438c15b 100644 --- a/tests/core/test_composition.py +++ b/tests/core/test_composition.py @@ -633,7 +633,7 @@ def test_oxi_state_guesses(self): {"V": 5, "O": -2}, ) - expected_oxi_guesses = dict(Li=1, Fe=2, P=5, O=-2) + expected_oxi_guesses = {"Li": 1, "Fe": 2, "P": 5, "O": -2} # max_sites for very large composition - should timeout if incorrect assert Composition("Li10000Fe10000P10000O40000").oxi_state_guesses(max_sites=7)[0] == expected_oxi_guesses diff --git a/tests/core/test_tensors.py b/tests/core/test_tensors.py index ec794da99f5..28548c3c3ba 100644 --- a/tests/core/test_tensors.py +++ b/tests/core/test_tensors.py @@ -159,7 +159,7 @@ def test_einsum_sequence(self): test = Tensor(np.arange(0, 3**4).reshape((3, 3, 3, 3))) assert_allclose([0, 27, 54], test.einsum_sequence([x] * 3)) assert test.einsum_sequence([np.eye(3)] * 2) == 360 - with pytest.raises(ValueError, match="other tensors must be list of tensors or tensor input"): + with pytest.raises(TypeError, match="other tensors must be list of tensors or tensor input"): test.einsum_sequence(Tensor(np.zeros(3))) def test_symmetrized(self): diff --git a/tests/core/test_xcfunc.py b/tests/core/test_xcfunc.py index be6b89c812d..1cc64bbebc8 100644 --- a/tests/core/test_xcfunc.py +++ b/tests/core/test_xcfunc.py @@ -1,20 +1,25 @@ from __future__ import annotations +import pytest + from pymatgen.core.xcfunc import XcFunc from pymatgen.util.testing import PymatgenTest class TestLibxcFunc(PymatgenTest): - def test_xcfunc_api(self): - """Testing XcFunc API.""" + def setUp(self) -> None: + self.ixc_11 = XcFunc.from_abinit_ixc(11) + + def test_aliases(self): # Aliases should be unique assert len(XcFunc.aliases()) == len(set(XcFunc.aliases())) + def test_lda(self): # LDA-Teter ixc_1 = XcFunc.from_abinit_ixc(1) assert ixc_1.type == "LDA" assert ixc_1.name == "LDA_XC_TETER93" - assert ixc_1 == ixc_1 + assert ixc_1 == ixc_1 # test __eq__ assert ixc_1 == "LDA_XC_TETER93" assert ixc_1 != "PBE" assert ixc_1.name not in XcFunc.aliases() @@ -28,7 +33,9 @@ def test_xcfunc_api(self): assert ixc_7.name == XcFunc.from_name(ixc_7.name) assert ixc_7 != ixc_1 + def test_gga_pbe(self): # GGA-PBE from ixc == 11 (in aliases) + ixc_1 = XcFunc.from_abinit_ixc(1) ixc_11 = XcFunc.from_abinit_ixc(11) assert ixc_11.type == "GGA" assert ixc_11.name == "PBE" @@ -42,25 +49,29 @@ def test_xcfunc_api(self): assert "PBE" in dct assert ixc_11 in dct - # Test if object can be serialized with Pickle. - self.serialize_with_pickle(ixc_11) + def test_pickle_serialize(self): + # Test if object can be serialized with Pickle + self.serialize_with_pickle(self.ixc_11) + @pytest.mark.skip() + def test_msonable(self): # Test if object supports MSONable # TODO - # ixc_11.x.as_dict() - # self.assertMSONable(ixc_11) + self.ixc_11.x.as_dict() + self.assertMSONable(self.ixc_11) + def test_from(self): # GGA-PBE from ixc given in abinit-libxc mode ixc_101130 = XcFunc.from_abinit_ixc(-101130) assert ixc_101130.type == "GGA" assert ixc_101130.name == "PBE" - assert ixc_101130 == ixc_11 + assert ixc_101130 == self.ixc_11 # GGA-PBE built from name gga_pbe = XcFunc.from_name("PBE") assert gga_pbe.type == "GGA" assert gga_pbe.name == "PBE" - assert ixc_11 == gga_pbe + assert self.ixc_11 == gga_pbe # Use X from GGA and C from LDA! unknown_xc = XcFunc.from_name("GGA_X_PBE+ LDA_C_PW") diff --git a/tests/io/aims/test_aims_inputs.py b/tests/io/aims/test_aims_inputs.py index 47c0f59d792..d39baafd277 100644 --- a/tests/io/aims/test_aims_inputs.py +++ b/tests/io/aims/test_aims_inputs.py @@ -77,23 +77,23 @@ def test_read_h2o_in(tmp_path: Path): assert h2o.structure == h2o_from_dct.structure -def check_wrong_type_aims_cube(type, exp_err): +def check_wrong_type_aims_cube(cube_type, exp_err): with pytest.raises(ValueError, match=exp_err): - AimsCube(type=type) + AimsCube(type=cube_type) def test_aims_cube(): - check_wrong_type_aims_cube(type="INCORRECT_TYPE", exp_err="Cube type undefined") + check_wrong_type_aims_cube(cube_type="INCORRECT_TYPE", exp_err="Cube type undefined") for cube_type in ALLOWED_AIMS_CUBE_TYPES_STATE: check_wrong_type_aims_cube( - type=cube_type, + cube_type=cube_type, exp_err=f"{cube_type=} must have a state associated with it", ) for cube_type in ALLOWED_AIMS_CUBE_TYPES: check_wrong_type_aims_cube( - type=f"{cube_type} 1", + cube_type=f"{cube_type} 1", exp_err=f"{cube_type=} can not have a state associated with it", ) diff --git a/tests/io/lobster/test_inputs.py b/tests/io/lobster/test_inputs.py index 574676952d6..646a2f70eb3 100644 --- a/tests/io/lobster/test_inputs.py +++ b/tests/io/lobster/test_inputs.py @@ -1839,10 +1839,10 @@ def test_dict_functionality(self): assert len_after == len_before - 1 # Test case sensitivity of |= operator - self.Lobsterin["skipCOHP"] = True # Camel case + self.Lobsterin |= {"skipCOHP": True} # Camel case assert self.Lobsterin["skipcohp"] is True - self.Lobsterin["skipcohp"] = False # lower case + self.Lobsterin |= {"skipcohp": False} # lower case assert self.Lobsterin["skipcohp"] is False def test_read_write_lobsterin(self): diff --git a/tests/io/test_cif.py b/tests/io/test_cif.py index b9d8644bc6a..f536a4f4021 100644 --- a/tests/io/test_cif.py +++ b/tests/io/test_cif.py @@ -163,7 +163,7 @@ class TestCifIO(PymatgenTest): def test_cif_parser(self): parser = CifParser(f"{TEST_FILES_DIR}/cif/LiFePO4.cif") for struct in parser.parse_structures(): - assert struct.formula == "Li4 Fe4 P4 O16", "Incorrectly parsed cif." + assert struct.formula == "Li4 Fe4 P4 O16", "Incorrectly parsed CIF" parser = CifParser(f"{TEST_FILES_DIR}/cif/V2O3.cif") for struct in parser.parse_structures(): diff --git a/tests/io/vasp/test_sets.py b/tests/io/vasp/test_sets.py index d0a8312ba87..ceb2d8e5424 100644 --- a/tests/io/vasp/test_sets.py +++ b/tests/io/vasp/test_sets.py @@ -170,7 +170,6 @@ class TestMITMPRelaxSet(PymatgenTest): def setUpClass(cls): cls.set = MITRelaxSet cls.mp_set = MPRelaxSet - cls.monkeypatch = MonkeyPatch() filepath = f"{VASP_IN_DIR}/POSCAR" cls.structure = Structure.from_file(filepath) @@ -256,8 +255,8 @@ def test_potcar_validation(self): structure = Structure(self.lattice, ["P", "Fe"], self.coords) # Use pytest's monkeypatch to temporarily point pymatgen to a directory # containing the wrong POTCARs (LDA potcars in a PBE directory) - with self.monkeypatch.context() as m: - m.setitem(SETTINGS, "PMG_VASP_PSP_DIR", str(f"{VASP_IN_DIR}/wrong_potcars")) + with MonkeyPatch().context() as monkeypatch: + monkeypatch.setitem(SETTINGS, "PMG_VASP_PSP_DIR", str(f"{VASP_IN_DIR}/wrong_potcars")) with pytest.warns(BadInputSetWarning, match="not known by pymatgen"): _ = self.set(structure).potcar diff --git a/tests/symmetry/test_analyzer.py b/tests/symmetry/test_analyzer.py index b4d602d75e9..a1a19edc4ba 100644 --- a/tests/symmetry/test_analyzer.py +++ b/tests/symmetry/test_analyzer.py @@ -263,76 +263,75 @@ def test_get_ir_reciprocal_mesh_map(self): def test_get_conventional_standard_structure(self): structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/bcc_1927.cif") - assert structure == structure spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == (90, 90, 90) - assert conv.lattice.lengths == approx([9.1980270633769461] * 3) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == (90, 90, 90) + assert conventional.lattice.lengths == approx([9.1980270633769461] * 3) structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/btet_1915.cif") spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == (90, 90, 90) - assert conv.lattice.a == approx(5.0615106678044235) - assert conv.lattice.b == approx(5.0615106678044235) - assert conv.lattice.c == approx(4.2327080177761687) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == (90, 90, 90) + assert conventional.lattice.a == approx(5.0615106678044235) + assert conventional.lattice.b == approx(5.0615106678044235) + assert conventional.lattice.c == approx(4.2327080177761687) structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/orci_1010.cif") spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == (90, 90, 90) - assert conv.lattice.a == approx(2.9542233922299999) - assert conv.lattice.b == approx(4.6330325651443296) - assert conv.lattice.c == approx(5.373703587040775) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == (90, 90, 90) + assert conventional.lattice.a == approx(2.9542233922299999) + assert conventional.lattice.b == approx(4.6330325651443296) + assert conventional.lattice.c == approx(5.373703587040775) structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/orcc_1003.cif") spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == (90, 90, 90) - assert conv.lattice.a == approx(4.1430033493799998) - assert conv.lattice.b == approx(31.437979757624728) - assert conv.lattice.c == approx(3.99648651) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == (90, 90, 90) + assert conventional.lattice.a == approx(4.1430033493799998) + assert conventional.lattice.b == approx(31.437979757624728) + assert conventional.lattice.c == approx(3.99648651) structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/orac_632475.cif") spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == (90, 90, 90) - assert conv.lattice.lengths == approx([3.1790663399999999, 9.9032878699999998, 3.5372412099999999]) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == (90, 90, 90) + assert conventional.lattice.lengths == approx([3.1790663399999999, 9.9032878699999998, 3.5372412099999999]) structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/monoc_1028.cif") spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == approx([90, 117.53832420192903, 90]) - assert conv.lattice.lengths == approx([14.033435583000625, 3.96052850731, 6.8743926325200002]) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == approx([90, 117.53832420192903, 90]) + assert conventional.lattice.lengths == approx([14.033435583000625, 3.96052850731, 6.8743926325200002]) structure = Structure.from_file(f"{TEST_FILES_DIR}/cif/hex_1170.cif") spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.angles == approx([90, 90, 120]) - assert conv.lattice.lengths == approx([3.699919902005897, 3.699919902005897, 6.9779585500000003]) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.angles == approx([90, 90, 120]) + assert conventional.lattice.lengths == approx([3.699919902005897, 3.699919902005897, 6.9779585500000003]) STRUCTURE = f"{TEST_FILES_DIR}/symmetry/analyzer/tric_684654.json" structure = Structure.from_file(STRUCTURE) spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure() - assert conv.lattice.alpha == approx(74.09581916308757) - assert conv.lattice.beta == approx(75.72817279281173) - assert conv.lattice.gamma == approx(63.63234318667333) - assert conv.lattice.a == approx(3.741372924048738) - assert conv.lattice.b == approx(3.9883228679270686) - assert conv.lattice.c == approx(7.288495840048958) + conventional = spga.get_conventional_standard_structure() + assert conventional.lattice.alpha == approx(74.09581916308757) + assert conventional.lattice.beta == approx(75.72817279281173) + assert conventional.lattice.gamma == approx(63.63234318667333) + assert conventional.lattice.a == approx(3.741372924048738) + assert conventional.lattice.b == approx(3.9883228679270686) + assert conventional.lattice.c == approx(7.288495840048958) structure = Structure.from_file(STRUCTURE) structure.add_site_property("magmom", [1.0] * len(structure)) spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure(keep_site_properties=True) - assert conv.site_properties["magmom"] == [1.0] * len(conv) + conventional = spga.get_conventional_standard_structure(keep_site_properties=True) + assert conventional.site_properties["magmom"] == [1.0] * len(conventional) structure = Structure.from_file(STRUCTURE) structure.add_site_property("magmom", [1.0] * len(structure)) spga = SpacegroupAnalyzer(structure, symprec=1e-2) - conv = spga.get_conventional_standard_structure(keep_site_properties=False) - assert conv.site_properties.get("magmom") is None + conventional = spga.get_conventional_standard_structure(keep_site_properties=False) + assert conventional.site_properties.get("magmom") is None def test_get_primitive_standard_structure(self): for file_name, expected_angles, expected_abc in [ diff --git a/tests/util/test_provenance.py b/tests/util/test_provenance.py index 08bc1c0cedc..12ebbb2b13b 100644 --- a/tests/util/test_provenance.py +++ b/tests/util/test_provenance.py @@ -1,6 +1,8 @@ +"""Unit tests for StructureNL (SNL) format.""" + from __future__ import annotations -import datetime +from datetime import datetime, timedelta, timezone from unittest import TestCase import numpy as np @@ -9,10 +11,6 @@ from pymatgen.core.structure import Molecule, Structure from pymatgen.util.provenance import Author, HistoryNode, StructureNL -""" -Unit tests for StructureNL (SNL) format -""" - __author__ = "Anubhav Jain" __credits__ = "Shyue Ping Ong" __copyright__ = "Copyright 2012, The Materials Project" @@ -98,7 +96,7 @@ def test_references(self): # An empty list should not work with pytest.raises( - ValueError, + TypeError, match="Invalid format for SNL reference! Should be empty string or BibTeX string.", ): StructureNL(self.struct, self.hulk, references=[]) @@ -155,7 +153,7 @@ def test_remarks(self): def test_eq(self): # test basic Equal() - created_at = datetime.datetime.now() + created_at = datetime.now(tz=timezone.utc) struct_nl = StructureNL( self.struct, self.hulk, @@ -179,7 +177,7 @@ def test_eq(self): assert struct_nl == struct_nl2 # change the created at date, now they are no longer equal - created_at = datetime.datetime.now() + datetime.timedelta(days=-1) + created_at = datetime.now(tz=timezone.utc) + timedelta(days=-1) snl_new_date = StructureNL( self.struct, self.hulk, From a1aecb914341d2ae1831be02c556fe67dfc58e96 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Fri, 21 Jun 2024 08:38:09 -0700 Subject: [PATCH 27/54] Generated locked dependencies using uv. --- requirements.txt | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000000..62faf1e6ecb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,88 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements.txt +certifi==2024.6.2 + # via requests +charset-normalizer==3.3.2 + # via requests +contourpy==1.2.1 + # via matplotlib +cycler==0.12.1 + # via matplotlib +fonttools==4.53.0 + # via matplotlib +idna==3.7 + # via requests +joblib==1.4.2 + # via pymatgen (pyproject.toml) +kiwisolver==1.4.5 + # via matplotlib +latexcodec==3.0.0 + # via pybtex +matplotlib==3.9.0 + # via pymatgen (pyproject.toml) +monty==2024.5.24 + # via pymatgen (pyproject.toml) +mpmath==1.3.0 + # via sympy +networkx==3.3 + # via pymatgen (pyproject.toml) +numpy==2.0.0 + # via + # pymatgen (pyproject.toml) + # contourpy + # matplotlib + # pandas + # scipy + # spglib +packaging==24.1 + # via + # matplotlib + # plotly +palettable==3.3.3 + # via pymatgen (pyproject.toml) +pandas==2.2.2 + # via pymatgen (pyproject.toml) +pillow==10.3.0 + # via matplotlib +plotly==5.22.0 + # via pymatgen (pyproject.toml) +pybtex==0.24.0 + # via pymatgen (pyproject.toml) +pyparsing==3.1.2 + # via matplotlib +python-dateutil==2.9.0.post0 + # via + # matplotlib + # pandas +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via pybtex +requests==2.32.3 + # via pymatgen (pyproject.toml) +ruamel-yaml==0.18.6 + # via pymatgen (pyproject.toml) +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +scipy==1.13.1 + # via pymatgen (pyproject.toml) +six==1.16.0 + # via + # pybtex + # python-dateutil +spglib==2.4.0 + # via pymatgen (pyproject.toml) +sympy==1.12.1 + # via pymatgen (pyproject.toml) +tabulate==0.9.0 + # via pymatgen (pyproject.toml) +tenacity==8.4.1 + # via plotly +tqdm==4.66.4 + # via pymatgen (pyproject.toml) +tzdata==2024.1 + # via pandas +uncertainties==3.2.1 + # via pymatgen (pyproject.toml) +urllib3==2.2.2 + # via requests From 6d2ea8223779b9356ce33c9866cfb9ee1932ff2e Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Fri, 21 Jun 2024 10:03:07 -0700 Subject: [PATCH 28/54] Update developer guide with a workflow. --- docs/contributing.md | 92 +++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 22 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index b568dacc247..6654f01f446 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -4,55 +4,90 @@ title: Contributing nav_order: 6 --- -# Collaborative Github Workflow +# Recommended developer workflow -For developers interested in expanding `pymatgen` for their own purposes, we recommend forking `pymatgen` directly from the [`pymatgen` GitHub repo](https://github.com/materialsproject/pymatgen). Here's a typical workflow: +For developers interested in expanding `pymatgen` for their own purposes, we recommend forking `pymatgen` directly from +the [`pymatgen` GitHub repo](https://github.com/materialsproject/pymatgen). Here's a recommended workflow (updated Jun +2024): -1. Create a free GitHub account (if you don't already have one) and perform the necessary setup (e.g., install SSH keys etc.). +1. Create a free GitHub account (if you don't already have one) and perform the necessary setup (e.g., install SSH keys + etc.). -1. Fork the `pymatgen` GitHub repo, i.e., go to the main [`pymatgen` GitHub repo](https://github.com/materialsproject/pymatgen) and click fork to create a copy of the `pymatgen` code base on your own GitHub account. +1. Fork the `pymatgen` GitHub repo, i.e., go to the + main [`pymatgen` GitHub repo](https://github.com/materialsproject/pymatgen) and click fork to create a copy of + the `pymatgen` code base on your own GitHub account. 1. Install `git` on your local machine (if you don't already have it). -1. Clone *your forked repo* to your local machine. You will work mostly with your local repo and only publish changes when they are ready to be merged: +1. Clone *your forked repo* to your local machine. You will work mostly with your local repo and only publish changes + when they are ready to be merged: ```sh git clone https://github.com//pymatgen + cd pymatgen # Go into pmg directory. ``` - Note that the entire Github repo is fairly large because of the presence of test files, but these are necessary for rigorous testing. + Note that the entire Github repo is fairly large because of the presence of test files, but these are necessary for + rigorous testing. + +1. Install the [uv package manager](https://github.com/astral-sh/uv): + + ```sh + pip install uv + ``` + +1. Create a virtual env for pymatgen. + + ```sh + uv create venv # A virtual env will be created in the .venv directory in the repo. + source .venv/bin/activate + ``` + +1. Install pymatgen in editable mode with dev and optional dependencies: + + ```sh + uv pip install -e .[ci,optional] + ``` 1. Make a new branch for your contributions ```sh - git checkout -b my-new-fix-or-feature # should be run from up-to-date master + git checkout -b my-new-fix-or-feature # should be run from up-to-date master ``` -1. Code (see [Coding Guidelines](#coding-guidelines)). Commit early and commit often. Keep your code up to date. You need to add the main repository to the list of your remotes. +1. Code (see [Coding Guidelines](#coding-guidelines)). Commit early and commit often. Keep your code up to date. You + need to add the main repository to the list of your remotes. ```sh git remote add upstream https://github.com/materialsproject/pymatgen ``` - Make sure your repository is clean (no uncommitted changes) and is currently on the master branch. If not, commit or stash any changes and switch to the master. + Make sure your repository is clean (no uncommitted changes) and is currently on the master branch. If not, commit or + stash any changes and switch to the master. ```sh git checkout master ``` - Then you can pull all the new commits from the main line + Then you can pull all the new commits from the main line ```sh git pull upstream master ``` - Remember, pull is a combination of the commands fetch and merge, so there may be merge conflicts to be manually resolved. + Remember, pull is a combination of the commands fetch and merge, so there may be merge conflicts to be manually + resolved. -1. Publish your contributions. Assuming that you now have a couple of commits that you would like to contribute to the main repository. Please follow the following steps: +1. Publish your contributions. Assuming that you now have a couple of commits that you would like to contribute to the + main repository. Please follow the following steps: - 1. If your change is based on a relatively old state of the main repository, then you should probably bring your repository up-to-date first to see if the change is not creating any merge conflicts. + 1. If your change is based on a relatively old state of the main repository, then you should probably bring your + repository up-to-date first to see if the change is not creating any merge conflicts. - 1. Check that everything compiles cleanly and passes all tests. The `pymatgen` repo comes with a complete set of tests for all modules. If you have written new modules or methods, you must write tests for the new code as well (see [Coding Guidelines](#coding-guidelines)). Install and run `pytest` in your local repo directory and fix all errors before continuing further. + 1. Check that everything compiles cleanly and passes all tests. The `pymatgen` repo comes with a complete set of + tests for all modules. If you have written new modules or methods, you must write tests for the new code as + well (see [Coding Guidelines](#coding-guidelines)). Install and run `pytest` in your local repo directory and fix + all errors before continuing further. 1. If everything is ok, publish the commits to your GitHub repository. @@ -60,25 +95,38 @@ For developers interested in expanding `pymatgen` for their own purposes, we rec git push origin master ``` -1. Now that your commit is published, it doesn't mean that it has already been merged into the main repository. You should issue a merge request to `pymatgen` maintainers. They will pull your commits and run their own tests before releasing. +1. Now that your commit is published, it doesn't mean that it has already been merged into the main repository. You + should issue a merge request to `pymatgen` maintainers. They will pull your commits and run their own tests before + releasing. -"Work-in-progress" pull requests are encouraged, especially if this is your first time contributing to `pymatgen`, and the maintainers will be happy to help or provide code review as necessary. Put "\[WIP\]" in the title of your pull request to indicate it's not ready to be merged. +"Work-in-progress" pull requests are encouraged, especially if this is your first time contributing to `pymatgen`, and +the maintainers will be happy to help or provide code review as necessary. Put "\[WIP\]" in the title of your pull +request to indicate it's not ready to be merged. ## Coding Guidelines -Given that `pymatgen` is intended to be a long-term code base, we adopt very strict quality control and coding guidelines for all contributions to `pymatgen`. The following must be satisfied for your contributions to be accepted into `pymatgen`. +Given that `pymatgen` is intended to be a long-term code base, we adopt very strict quality control and coding +guidelines for all contributions to `pymatgen`. The following must be satisfied for your contributions to be accepted +into `pymatgen`. -1. **Unit tests** are required for all new modules and methods. The only way to minimize code regression is to ensure that all code is well tested. Untested contributions will not be accepted. -1. **Python PEP 8** [code style](https://python.org/dev/peps/pep-0008). We allow a few exceptions when they are well-justified (e.g., Element's atomic number is given a variable name of capital Z, in line with accepted scientific convention), but generally, PEP 8 must be observed. Code style will be automatically checked for all PRs and must pass before any PR is merged. To aid you, you can install and run the same set of formatters and linters that will run in CI using +1. **Unit tests** are required for all new modules and methods. The only way to minimize code regression is to ensure + that all code is well tested. Untested contributions will not be accepted. +1. **Python PEP 8** [code style](https://python.org/dev/peps/pep-0008). We allow a few exceptions when they are + well-justified (e.g., Element's atomic number is given a variable name of capital Z, in line with accepted scientific + convention), but generally, PEP 8 must be observed. Code style will be automatically checked for all PRs and must + pass before any PR is merged. To aid you, you can install and run the same set of formatters and linters that will + run in CI using ```sh pre-commit install # ensures linters are run prior to all future commits pre-commit run --files path/to/changed/files # ensure your current uncommitted changes don't offend linters # or - pre-commit run --all-files # ensure your entire codebase passes linters + pre-commit run --all-files # ensure your entire codebase passes linters ``` -1. **Python 3**. We only support Python 3.8+. -1. **Documentation** is required for all modules, classes and methods. In particular, the method doc strings should make clear the arguments expected and the return values. For complex algorithms (e.g., an Ewald summation), a summary of the algorithm should be provided and preferably with a link to a publication outlining the method in detail. +1. **Python 3**. Check the `pyproject.toml` for the supported Python versions. +1. **Documentation** is required for all modules, classes and methods. In particular, the method doc strings should make + clear the arguments expected and the return values. For complex algorithms (e.g., an Ewald summation), a summary of + the algorithm should be provided and preferably with a link to a publication outlining the method in detail. For the above, if in doubt, please refer to the core classes in `pymatgen` for examples of what is expected. From 1b2b029e56ab5d9dca0f08ee82992fa8e3922451 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Fri, 21 Jun 2024 10:05:51 -0700 Subject: [PATCH 29/54] Add pre-commit. --- docs/contributing.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing.md b/docs/contributing.md index 6654f01f446..b7c11f37478 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -47,6 +47,7 @@ the [`pymatgen` GitHub repo](https://github.com/materialsproject/pymatgen). Here ```sh uv pip install -e .[ci,optional] + pre-commit install # Install pre-commit hook for linters. ``` 1. Make a new branch for your contributions From d3c3b65826f29b485a141649db913db742502a55 Mon Sep 17 00:00:00 2001 From: Shyue Ping Ong Date: Fri, 21 Jun 2024 10:11:23 -0700 Subject: [PATCH 30/54] Updated docs. --- docs/contributing.md | 2 +- docs/modules.html | 9 +- docs/pymatgen.alchemy.html | 127 +- ...ymatgen.analysis.chemenv.connectivity.html | 132 +- ...onments.coordination_geometries_files.html | 6 +- ...sis.chemenv.coordination_environments.html | 742 ++--- docs/pymatgen.analysis.chemenv.html | 6 +- docs/pymatgen.analysis.chemenv.utils.html | 294 +- docs/pymatgen.analysis.diffraction.html | 80 +- docs/pymatgen.analysis.elasticity.html | 174 +- docs/pymatgen.analysis.ferroelectricity.html | 44 +- docs/pymatgen.analysis.gb.html | 6 +- docs/pymatgen.analysis.html | 1648 +++++------ docs/pymatgen.analysis.interfaces.html | 82 +- docs/pymatgen.analysis.magnetism.html | 132 +- docs/pymatgen.analysis.solar.html | 18 +- ...ymatgen.analysis.structure_prediction.html | 46 +- docs/pymatgen.analysis.topological.html | 14 +- docs/pymatgen.analysis.xas.html | 28 +- docs/pymatgen.apps.battery.html | 228 +- docs/pymatgen.apps.borg.html | 54 +- docs/pymatgen.apps.html | 6 +- docs/pymatgen.cli.html | 64 +- docs/pymatgen.command_line.html | 170 +- docs/pymatgen.core.html | 2522 +++++++++-------- docs/pymatgen.electronic_structure.html | 608 ++-- docs/pymatgen.entries.html | 230 +- docs/pymatgen.ext.html | 86 +- docs/pymatgen.html | 21 +- docs/pymatgen.io.abinit.html | 694 ++--- docs/pymatgen.io.aims.html | 425 ++- docs/pymatgen.io.aims.sets.html | 114 +- docs/pymatgen.io.cp2k.html | 592 ++-- docs/pymatgen.io.exciting.html | 28 +- docs/pymatgen.io.feff.html | 162 +- docs/pymatgen.io.html | 872 +++--- docs/pymatgen.io.lammps.html | 198 +- docs/pymatgen.io.lobster.html | 365 +-- docs/pymatgen.io.pwmat.html | 128 +- docs/pymatgen.io.qchem.html | 144 +- docs/pymatgen.io.vasp.html | 1228 ++++---- docs/pymatgen.io.xtb.html | 14 +- docs/pymatgen.optimization.html | 10 +- docs/pymatgen.phonon.html | 256 +- docs/pymatgen.symmetry.html | 240 +- docs/pymatgen.transformations.html | 248 +- docs/pymatgen.util.html | 198 +- docs/pymatgen.util.testing.html | 34 +- docs/pymatgen.vis.html | 132 +- 49 files changed, 6922 insertions(+), 6739 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index b7c11f37478..3080cdb14d1 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -46,7 +46,7 @@ the [`pymatgen` GitHub repo](https://github.com/materialsproject/pymatgen). Here 1. Install pymatgen in editable mode with dev and optional dependencies: ```sh - uv pip install -e .[ci,optional] + uv pip install -e '.[ci,optional]' pre-commit install # Install pre-commit hook for linters. ``` diff --git a/docs/modules.html b/docs/modules.html index 9b2c893e40b..8176ffd9a89 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -4,7 +4,7 @@ - pymatgen — pymatgen 2024.6.4 documentation + pymatgen — pymatgen 2024.6.10 documentation @@ -15,7 +15,7 @@ - + @@ -36,7 +36,7 @@
- 2024.6.4 + 2024.6.10
@@ -2762,6 +2762,7 @@

pymatgen
  • IStructure.frac_coords
  • IStructure.from_dict()
  • IStructure.from_file()
  • +
  • IStructure.from_id()
  • IStructure.from_magnetic_spacegroup()
  • IStructure.from_sites()
  • IStructure.from_spacegroup()
  • @@ -3804,6 +3805,8 @@

    pymatgen
  • AimsControlIn
  • AimsCube
  • AimsGeometryIn
  • +
  • AimsSpeciesFile
  • +
  • SpeciesDefaults
  • pymatgen.io.aims.outputs module