Skip to content

Commit e301acd

Browse files
Deprecate PymatgenTest, migrate tests to pytest from unittest (#4212)
* revert for a separate migration PR * Revert "revert for a separate migration PR" This reverts commit 6f95ba8. * remove hard-coded and failing test * batch remove PymatgenTest inheritance and see what fail * migrate alchemy and command_line * deprecate pymatgen with matscitest * migrate utils * migrate optimization * migrate vis * global replacement of setUp and TearDown, setupClass * revert all changes to before global replace PymatgenTest * deprecate pymatgen with matscitest * global replace setUp with setup_method * replace tearDown * replace setUpClass(cls) with setup_class(cls) * global remove inheritance from TestCase * global replace inheritance from PymatgenTest * global replace PymatgenTest import * global replace get_structure * global replace PymatgenTest with MatSciTest * fix tests * fix internal index and add require for pytest style * fix test * remove seemingly unused conftest * add deprecated decorator and enhance docstring * inherit to reduce code duplicate * add some test for legacy tester * also check future warning * remove unnecessary chdir * prep for merge * fix bad merge behaviour * pre-commit auto-fixes * fix merge * migrate recently added tests --------- Signed-off-by: Haoyu (Daniel) YANG <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5891dcd commit e301acd

File tree

190 files changed

+975
-1066
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

190 files changed

+975
-1066
lines changed

docs/contributing.md

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/pymatgen/util/testing.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
"""This module implements testing utilities for materials science codes.
22
3-
While the primary use is within pymatgen, the functionality is meant to
4-
be useful for external materials science codes as well. For instance, obtaining
5-
example crystal structures to perform tests, specialized assert methods for
3+
While the primary use is within pymatgen, the functionality is meant to be useful for external materials science
4+
codes as well. For instance, obtaining example crystal structures to perform tests, specialized assert methods for
65
materials science, etc.
76
"""
87

@@ -16,6 +15,7 @@
1615
from unittest import TestCase
1716

1817
import pytest
18+
from monty.dev import deprecated
1919
from monty.json import MontyDecoder, MontyEncoder, MSONable
2020
from monty.serialization import loadfn
2121

@@ -42,12 +42,14 @@
4242
FAKE_POTCAR_DIR: str = f"{VASP_IN_DIR}/fake_potcars"
4343

4444

45-
class PymatgenTest(TestCase):
46-
"""Extends unittest.TestCase with several convenient methods for testing:
47-
- assert_msonable: Test if an object is MSONable and return the serialized object.
48-
- assert_str_content_equal: Test if two string are equal (ignore whitespaces).
49-
- get_structure: Load a Structure with its formula.
50-
- serialize_with_pickle: Test if object(s) can be (de)serialized with `pickle`.
45+
class MatSciTest:
46+
"""`pytest` based test framework extended to facilitate testing with
47+
the following methods:
48+
- tmp_path (attribute): Temporary directory.
49+
- get_structure: Load a Structure from `util.structures` with its name.
50+
- assert_str_content_equal: Check if two strings are equal (ignore whitespaces).
51+
- serialize_with_pickle: Test whether object(s) can be (de)serialized with pickle.
52+
- assert_msonable: Test if obj is MSONable and return its serialized string.
5153
"""
5254

5355
# dict of lazily-loaded test structures (initialized to None)
@@ -201,7 +203,15 @@ def serialize_with_pickle(
201203
if errors:
202204
raise ValueError("\n".join(errors))
203205

204-
# Return list so that client code can perform additional tests
206+
# Return nested list so that client code can perform additional tests.
205207
if got_single_object:
206208
return [o[0] for o in objects_by_protocol]
207209
return objects_by_protocol
210+
211+
212+
@deprecated(MatSciTest, deadline=(2026, 1, 1))
213+
class PymatgenTest(TestCase, MatSciTest):
214+
"""Extends unittest.TestCase with several assert methods for array and str comparison.
215+
216+
Deprecated: please use `MatSciTest` instead (migrate from `unittest` to `pytest`).
217+
"""

tests/alchemy/test_filters.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import json
4-
from unittest import TestCase
54

65
from monty.json import MontyDecoder
76

@@ -14,10 +13,10 @@
1413
from pymatgen.alchemy.transmuters import StandardTransmuter
1514
from pymatgen.analysis.structure_matcher import StructureMatcher
1615
from pymatgen.core import Lattice, Species, Structure
17-
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
16+
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest
1817

1918

20-
class TestContainsSpecieFilter(PymatgenTest):
19+
class TestContainsSpecieFilter(MatSciTest):
2120
def test_filtering(self):
2221
coords = [[0, 0, 0], [0.75, 0.75, 0.75], [0.5, 0.5, 0.5], [0.25, 0.25, 0.25]]
2322
lattice = Lattice([[3.0, 0.0, 0.0], [1.0, 3.0, 0], [0, -2.0, 3.0]])
@@ -52,7 +51,7 @@ def test_as_from_dict(self):
5251
assert isinstance(ContainsSpecieFilter.from_dict(dct), ContainsSpecieFilter)
5352

5453

55-
class TestSpecieProximityFilter(PymatgenTest):
54+
class TestSpecieProximityFilter(MatSciTest):
5655
def test_filter(self):
5756
struct = self.get_structure("Li10GeP2S12")
5857
sf = SpecieProximityFilter({"Li": 1})
@@ -70,8 +69,8 @@ def test_as_from_dict(self):
7069
assert isinstance(SpecieProximityFilter.from_dict(dct), SpecieProximityFilter)
7170

7271

73-
class TestRemoveDuplicatesFilter(TestCase):
74-
def setUp(self):
72+
class TestRemoveDuplicatesFilter:
73+
def setup_method(self):
7574
with open(f"{TEST_FILES_DIR}/entries/TiO2_entries.json", encoding="utf-8") as file:
7675
entries = json.load(file, cls=MontyDecoder)
7776
self._struct_list = [entry.structure for entry in entries]
@@ -89,8 +88,8 @@ def test_as_from_dict(self):
8988
assert isinstance(RemoveDuplicatesFilter().from_dict(dct), RemoveDuplicatesFilter)
9089

9190

92-
class TestRemoveExistingFilter(TestCase):
93-
def setUp(self):
91+
class TestRemoveExistingFilter:
92+
def setup_method(self):
9493
with open(f"{TEST_FILES_DIR}/entries/TiO2_entries.json", encoding="utf-8") as file:
9594
entries = json.load(file, cls=MontyDecoder)
9695
self._struct_list = [entry.structure for entry in entries]

tests/alchemy/test_materials.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
SupercellTransformation,
1717
)
1818
from pymatgen.util.provenance import StructureNL
19-
from pymatgen.util.testing import FAKE_POTCAR_DIR, TEST_FILES_DIR, PymatgenTest
19+
from pymatgen.util.testing import FAKE_POTCAR_DIR, TEST_FILES_DIR, MatSciTest
2020

2121
TEST_DIR = f"{TEST_FILES_DIR}/alchemy"
2222

2323

24-
class TestTransformedStructure(PymatgenTest):
25-
def setUp(self):
26-
structure = PymatgenTest.get_structure("LiFePO4")
24+
class TestTransformedStructure(MatSciTest):
25+
def setup_method(self):
26+
structure = MatSciTest.get_structure("LiFePO4")
2727
self.structure = structure
2828
trafos = [SubstitutionTransformation({"Li": "Na"})]
2929
self.trans = TransformedStructure(structure, trafos)

tests/alchemy/test_transmuters.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
RemoveSpeciesTransformation,
99
SubstitutionTransformation,
1010
)
11-
from pymatgen.util.testing import TEST_FILES_DIR, VASP_IN_DIR, PymatgenTest
11+
from pymatgen.util.testing import TEST_FILES_DIR, VASP_IN_DIR, MatSciTest
1212

1313

14-
class TestCifTransmuter(PymatgenTest):
14+
class TestCifTransmuter(MatSciTest):
1515
def test_init(self):
1616
trafos = [SubstitutionTransformation({"Fe": "Mn", "Fe2+": "Mn2+"})]
1717
tsc = CifTransmuter.from_filenames([f"{TEST_FILES_DIR}/cif/MultiStructure.cif"], trafos)
@@ -22,7 +22,7 @@ def test_init(self):
2222
assert expected == els
2323

2424

25-
class TestPoscarTransmuter(PymatgenTest):
25+
class TestPoscarTransmuter(MatSciTest):
2626
def test_init(self):
2727
trafos = [SubstitutionTransformation({"Fe": "Mn"})]
2828
tsc = PoscarTransmuter.from_filenames([f"{VASP_IN_DIR}/POSCAR", f"{VASP_IN_DIR}/POSCAR"], trafos)

tests/analysis/chemenv/connectivity/test_connected_components.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
from pymatgen.core.lattice import Lattice
2121
from pymatgen.core.sites import PeriodicSite
2222
from pymatgen.core.structure import Structure
23-
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
23+
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest
2424

2525
__author__ = "waroquiers"
2626

2727

28-
class TestConnectedComponent(PymatgenTest):
28+
class TestConnectedComponent(MatSciTest):
2929
def test_init(self):
3030
# Generic connected component not using EnvironmentNodes
3131
# (as_dict won't work on such a ConnectedComponent instance)

tests/analysis/chemenv/connectivity/test_environment_nodes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44

55
from pymatgen.analysis.chemenv.connectivity.environment_nodes import EnvironmentNode
6-
from pymatgen.util.testing import PymatgenTest
6+
from pymatgen.util.testing import MatSciTest
77

88
try:
99
import bson
@@ -13,7 +13,7 @@
1313
__author__ = "waroquiers"
1414

1515

16-
class TestEnvironmentNodes(PymatgenTest):
16+
class TestEnvironmentNodes(MatSciTest):
1717
def test_equal(self):
1818
struct = self.get_structure("SiO2")
1919
en = EnvironmentNode(central_site=struct[0], i_central_site=0, ce_symbol="T:4")

tests/analysis/chemenv/connectivity/test_structure_connectivity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
LightStructureEnvironments,
1010
StructureEnvironments,
1111
)
12-
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
12+
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest
1313

1414
__author__ = "waroquiers"
1515

1616

17-
class TestStructureConnectivity(PymatgenTest):
17+
class TestStructureConnectivity(MatSciTest):
1818
def test_serialization(self):
1919
BaTiO3_se_fpath = f"{TEST_FILES_DIR}/analysis/chemenv/structure_environments/se_mp-5020.json"
2020
with open(BaTiO3_se_fpath, encoding="utf-8") as file:

tests/analysis/chemenv/coordination_environments/test_chemenv_strategies.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
DistanceCutoffFloat,
1111
SimplestChemenvStrategy,
1212
)
13-
from pymatgen.util.testing import PymatgenTest
13+
from pymatgen.util.testing import MatSciTest
1414

1515
__author__ = "waroquiers"
1616

1717

18-
class TestStrategyOptions(PymatgenTest):
18+
class TestStrategyOptions(MatSciTest):
1919
def test_options(self):
2020
# DistanceCutoffFloat
2121
with pytest.raises(ValueError, match=r"Distance cutoff should be between 1 and \+infinity"):

tests/analysis/chemenv/coordination_environments/test_coordination_geometries.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
ExplicitPermutationsAlgorithm,
1212
SeparationPlane,
1313
)
14-
from pymatgen.util.testing import PymatgenTest
14+
from pymatgen.util.testing import MatSciTest
1515

1616
__author__ = "waroquiers"
1717

@@ -23,7 +23,7 @@ def __init__(self, coords):
2323
self.coords = coords
2424

2525

26-
class TestCoordinationGeometries(PymatgenTest):
26+
class TestCoordinationGeometries(MatSciTest):
2727
def test_algorithms(self):
2828
expl_algo = ExplicitPermutationsAlgorithm(permutations=[[0, 1, 2], [1, 2, 3]])
2929
expl_algo2 = ExplicitPermutationsAlgorithm.from_dict(expl_algo.as_dict())

tests/analysis/chemenv/coordination_environments/test_coordination_geometry_finder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
symmetry_measure,
2020
)
2121
from pymatgen.core.structure import Lattice, Structure
22-
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
22+
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest
2323

2424
__author__ = "waroquiers"
2525

2626
json_dir = f"{TEST_FILES_DIR}/analysis/chemenv/json"
2727

2828

29-
class TestCoordinationGeometryFinder(PymatgenTest):
30-
def setUp(self):
29+
class TestCoordinationGeometryFinder(MatSciTest):
30+
def setup_method(self):
3131
self.lgf = LocalGeometryFinder()
3232
self.lgf.setup_parameters(
3333
centering_type="standard",

tests/analysis/chemenv/coordination_environments/test_read_write.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@
2222
)
2323
from pymatgen.analysis.chemenv.coordination_environments.voronoi import DetailedVoronoiContainer
2424
from pymatgen.core.structure import Structure
25-
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
25+
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest
2626

2727
__author__ = "waroquiers"
2828

2929
json_dir = f"{TEST_FILES_DIR}/analysis/chemenv/json"
3030
struct_env_dir = f"{TEST_FILES_DIR}/analysis/chemenv/structure_environments"
3131

3232

33-
class TestReadWriteChemenv(PymatgenTest):
33+
class TestReadWriteChemenv(MatSciTest):
3434
@classmethod
35-
def setUpClass(cls):
35+
def setup_class(cls):
3636
cls.lgf = LocalGeometryFinder()
3737
cls.lgf.setup_parameters(centering_type="standard")
3838

tests/analysis/chemenv/coordination_environments/test_structure_environments.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
StructureEnvironments,
1818
)
1919
from pymatgen.core import Species, Structure
20-
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
20+
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest
2121

2222
__author__ = "waroquiers"
2323

2424
TEST_DIR = f"{TEST_FILES_DIR}/analysis/chemenv/structure_environments"
2525

2626

27-
class TestStructureEnvironments(PymatgenTest):
27+
class TestStructureEnvironments(MatSciTest):
2828
def test_structure_environments(self):
2929
with open(f"{TEST_DIR}/se_mp-7000.json", encoding="utf-8") as file:
3030
dct = json.load(file)

0 commit comments

Comments
 (0)