Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate PymatgenTest, migrate pymatgen tests to pytest from unittest #4212

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
08aebc1
revert for a separate migration PR
DanielYang59 Dec 1, 2024
21a36f5
Revert "revert for a separate migration PR"
DanielYang59 Dec 1, 2024
8bacdbc
remove hard-coded and failing test
DanielYang59 Dec 1, 2024
344a872
batch remove PymatgenTest inheritance and see what fail
DanielYang59 Dec 3, 2024
ab8bb0e
migrate alchemy and command_line
DanielYang59 Dec 4, 2024
9ed871d
deprecate pymatgen with matscitest
DanielYang59 Dec 4, 2024
2666983
migrate utils
DanielYang59 Dec 4, 2024
21123bd
migrate optimization
DanielYang59 Dec 4, 2024
614f4f7
migrate vis
DanielYang59 Dec 4, 2024
a2ea374
global replacement of setUp and TearDown, setupClass
DanielYang59 Dec 4, 2024
6f2bfe9
revert all changes to before global replace PymatgenTest
DanielYang59 Dec 4, 2024
9d33460
deprecate pymatgen with matscitest
DanielYang59 Dec 4, 2024
be187d0
global replace setUp with setup_method
DanielYang59 Dec 4, 2024
7366ec7
replace tearDown
DanielYang59 Dec 4, 2024
3239fd5
replace setUpClass(cls) with setup_class(cls)
DanielYang59 Dec 4, 2024
4429546
global remove inheritance from TestCase
DanielYang59 Dec 4, 2024
98f7fc7
global replace inheritance from PymatgenTest
DanielYang59 Dec 4, 2024
dfb616c
global replace PymatgenTest import
DanielYang59 Dec 4, 2024
9ae0deb
global replace get_structure
DanielYang59 Dec 4, 2024
42f9fb6
global replace PymatgenTest with MatSciTest
DanielYang59 Dec 4, 2024
96ccce4
fix tests
DanielYang59 Dec 4, 2024
631ef93
fix internal index and add require for pytest style
DanielYang59 Dec 4, 2024
5c89fc0
fix test
DanielYang59 Dec 4, 2024
e4ac465
remove seemingly unused conftest
DanielYang59 Dec 4, 2024
4292f38
add deprecated decorator and enhance docstring
DanielYang59 Dec 5, 2024
027f84b
inherit to reduce code duplicate
DanielYang59 Dec 5, 2024
73328d0
add some test for legacy tester
DanielYang59 Dec 5, 2024
ebd48ce
also check future warning
DanielYang59 Dec 5, 2024
f6bda1e
remove unnecessary chdir
DanielYang59 Dec 5, 2024
58dc537
prep for merge
DanielYang59 Dec 11, 2024
ec33a39
Merge branch 'master' into real-real-real-migrate-pmg-tests-to-pytest
DanielYang59 Dec 12, 2024
def9886
fix bad merge behaviour
DanielYang59 Dec 12, 2024
881e092
Merge remote-tracking branch 'upstream/master' into real-real-real-mi…
DanielYang59 Dec 13, 2024
13dfc2e
Merge remote-tracking branch 'upstream/master' into real-real-real-mi…
DanielYang59 Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions docs/contributing.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 20 additions & 10 deletions src/pymatgen/util/testing.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"""This module implements testing utilities for materials science codes.

While the primary use is within pymatgen, the functionality is meant to
be useful for external materials science codes as well. For instance, obtaining
example crystal structures to perform tests, specialized assert methods for
While the primary use is within pymatgen, the functionality is meant to be useful for external materials science
codes as well. For instance, obtaining example crystal structures to perform tests, specialized assert methods for
materials science, etc.
"""

Expand All @@ -16,6 +15,7 @@
from unittest import TestCase

import pytest
from monty.dev import deprecated
from monty.json import MontyDecoder, MontyEncoder, MSONable
from monty.serialization import loadfn

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


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

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

# Return list so that client code can perform additional tests
# Return nested list so that client code can perform additional tests.
if got_single_object:
return [o[0] for o in objects_by_protocol]
return objects_by_protocol


@deprecated(MatSciTest, deadline=(2026, 1, 1))
class PymatgenTest(TestCase, MatSciTest):
"""Extends unittest.TestCase with several assert methods for array and str comparison.

Deprecated: please use `MatSciTest` instead (migrate from `unittest` to `pytest`).
"""
15 changes: 7 additions & 8 deletions tests/alchemy/test_filters.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import json
from unittest import TestCase

from monty.json import MontyDecoder

Expand All @@ -14,10 +13,10 @@
from pymatgen.alchemy.transmuters import StandardTransmuter
from pymatgen.analysis.structure_matcher import StructureMatcher
from pymatgen.core import Lattice, Species, Structure
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest


class TestContainsSpecieFilter(PymatgenTest):
class TestContainsSpecieFilter(MatSciTest):
def test_filtering(self):
coords = [[0, 0, 0], [0.75, 0.75, 0.75], [0.5, 0.5, 0.5], [0.25, 0.25, 0.25]]
lattice = Lattice([[3.0, 0.0, 0.0], [1.0, 3.0, 0], [0, -2.0, 3.0]])
Expand Down Expand Up @@ -52,7 +51,7 @@ def test_as_from_dict(self):
assert isinstance(ContainsSpecieFilter.from_dict(dct), ContainsSpecieFilter)


class TestSpecieProximityFilter(PymatgenTest):
class TestSpecieProximityFilter(MatSciTest):
def test_filter(self):
struct = self.get_structure("Li10GeP2S12")
sf = SpecieProximityFilter({"Li": 1})
Expand All @@ -70,8 +69,8 @@ def test_as_from_dict(self):
assert isinstance(SpecieProximityFilter.from_dict(dct), SpecieProximityFilter)


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


class TestRemoveExistingFilter(TestCase):
def setUp(self):
class TestRemoveExistingFilter:
def setup_method(self):
with open(f"{TEST_FILES_DIR}/entries/TiO2_entries.json") as file:
entries = json.load(file, cls=MontyDecoder)
self._struct_list = [entry.structure for entry in entries]
Expand Down
8 changes: 4 additions & 4 deletions tests/alchemy/test_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
SupercellTransformation,
)
from pymatgen.util.provenance import StructureNL
from pymatgen.util.testing import FAKE_POTCAR_DIR, TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import FAKE_POTCAR_DIR, TEST_FILES_DIR, MatSciTest

TEST_DIR = f"{TEST_FILES_DIR}/alchemy"


class TestTransformedStructure(PymatgenTest):
def setUp(self):
structure = PymatgenTest.get_structure("LiFePO4")
class TestTransformedStructure(MatSciTest):
def setup_method(self):
structure = MatSciTest.get_structure("LiFePO4")
self.structure = structure
trafos = [SubstitutionTransformation({"Li": "Na"})]
self.trans = TransformedStructure(structure, trafos)
Expand Down
6 changes: 3 additions & 3 deletions tests/alchemy/test_transmuters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
RemoveSpeciesTransformation,
SubstitutionTransformation,
)
from pymatgen.util.testing import TEST_FILES_DIR, VASP_IN_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, VASP_IN_DIR, MatSciTest


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


class TestPoscarTransmuter(PymatgenTest):
class TestPoscarTransmuter(MatSciTest):
def test_init(self):
trafos = [SubstitutionTransformation({"Fe": "Mn"})]
tsc = PoscarTransmuter.from_filenames([f"{VASP_IN_DIR}/POSCAR", f"{VASP_IN_DIR}/POSCAR"], trafos)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
from pymatgen.core.lattice import Lattice
from pymatgen.core.sites import PeriodicSite
from pymatgen.core.structure import Structure
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest

__author__ = "waroquiers"


class TestConnectedComponent(PymatgenTest):
class TestConnectedComponent(MatSciTest):
def test_init(self):
# Generic connected component not using EnvironmentNodes
# (as_dict won't work on such a ConnectedComponent instance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json

from pymatgen.analysis.chemenv.connectivity.environment_nodes import EnvironmentNode
from pymatgen.util.testing import PymatgenTest
from pymatgen.util.testing import MatSciTest

try:
import bson
Expand All @@ -13,7 +13,7 @@
__author__ = "waroquiers"


class TestEnvironmentNodes(PymatgenTest):
class TestEnvironmentNodes(MatSciTest):
def test_equal(self):
struct = self.get_structure("SiO2")
en = EnvironmentNode(central_site=struct[0], i_central_site=0, ce_symbol="T:4")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
LightStructureEnvironments,
StructureEnvironments,
)
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest

__author__ = "waroquiers"


class TestStructureConnectivity(PymatgenTest):
class TestStructureConnectivity(MatSciTest):
def test_serialization(self):
BaTiO3_se_fpath = f"{TEST_FILES_DIR}/analysis/chemenv/structure_environments/se_mp-5020.json"
with open(BaTiO3_se_fpath) as file:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
DistanceCutoffFloat,
SimplestChemenvStrategy,
)
from pymatgen.util.testing import PymatgenTest
from pymatgen.util.testing import MatSciTest

__author__ = "waroquiers"


class TestStrategyOptions(PymatgenTest):
class TestStrategyOptions(MatSciTest):
def test_options(self):
# DistanceCutoffFloat
with pytest.raises(ValueError, match=r"Distance cutoff should be between 1 and \+infinity"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
ExplicitPermutationsAlgorithm,
SeparationPlane,
)
from pymatgen.util.testing import PymatgenTest
from pymatgen.util.testing import MatSciTest

__author__ = "waroquiers"

Expand All @@ -23,7 +23,7 @@ def __init__(self, coords):
self.coords = coords


class TestCoordinationGeometries(PymatgenTest):
class TestCoordinationGeometries(MatSciTest):
def test_algorithms(self):
expl_algo = ExplicitPermutationsAlgorithm(permutations=[[0, 1, 2], [1, 2, 3]])
expl_algo2 = ExplicitPermutationsAlgorithm.from_dict(expl_algo.as_dict())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
symmetry_measure,
)
from pymatgen.core.structure import Lattice, Structure
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest

__author__ = "waroquiers"

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


class TestCoordinationGeometryFinder(PymatgenTest):
def setUp(self):
class TestCoordinationGeometryFinder(MatSciTest):
def setup_method(self):
self.lgf = LocalGeometryFinder()
self.lgf.setup_parameters(
centering_type="standard",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
)
from pymatgen.analysis.chemenv.coordination_environments.voronoi import DetailedVoronoiContainer
from pymatgen.core.structure import Structure
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest

__author__ = "waroquiers"

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


class TestReadWriteChemenv(PymatgenTest):
class TestReadWriteChemenv(MatSciTest):
@classmethod
def setUpClass(cls):
def setup_class(cls):
cls.lgf = LocalGeometryFinder()
cls.lgf.setup_parameters(centering_type="standard")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
StructureEnvironments,
)
from pymatgen.core import Species, Structure
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
from pymatgen.util.testing import TEST_FILES_DIR, MatSciTest

__author__ = "waroquiers"

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


class TestStructureEnvironments(PymatgenTest):
class TestStructureEnvironments(MatSciTest):
def test_structure_environments(self):
with open(f"{TEST_DIR}/se_mp-7000.json") as file:
dct = json.load(file)
Expand Down
Loading
Loading