• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

materialsproject / pymatgen / 4075885785

pending completion
4075885785

push

github

Shyue Ping Ong
Merge branch 'master' of github.com:materialsproject/pymatgen

96 of 96 new or added lines in 27 files covered. (100.0%)

81013 of 102710 relevant lines covered (78.88%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.72
/pymatgen/ext/tests/test_matproj.py
1
# Copyright (c) Pymatgen Development Team.
2
# Distributed under the terms of the MIT License.
3
from __future__ import annotations
1✔
4

5
import os
1✔
6
import random
1✔
7
import re
1✔
8
import unittest
1✔
9
import warnings
1✔
10

11
import pytest
1✔
12
import requests
1✔
13
from ruamel.yaml import YAML
1✔
14

15
from pymatgen.analysis.phase_diagram import PhaseDiagram
1✔
16
from pymatgen.analysis.pourbaix_diagram import PourbaixDiagram, PourbaixEntry
1✔
17
from pymatgen.analysis.reaction_calculator import Reaction
1✔
18
from pymatgen.analysis.wulff import WulffShape
1✔
19
from pymatgen.core import SETTINGS
1✔
20
from pymatgen.core.periodic_table import Element
1✔
21
from pymatgen.core.structure import Composition, Structure
1✔
22
from pymatgen.electronic_structure.bandstructure import (
1✔
23
    BandStructure,
24
    BandStructureSymmLine,
25
)
26
from pymatgen.electronic_structure.dos import CompleteDos
1✔
27
from pymatgen.entries.compatibility import MaterialsProject2020Compatibility
1✔
28
from pymatgen.entries.computed_entries import ComputedEntry
1✔
29
from pymatgen.ext.matproj import MP_LOG_FILE, MPRestError, TaskType, _MPResterLegacy
1✔
30
from pymatgen.io.cif import CifParser
1✔
31
from pymatgen.phonon.bandstructure import PhononBandStructureSymmLine
1✔
32
from pymatgen.phonon.dos import CompletePhononDos
1✔
33
from pymatgen.util.testing import PymatgenTest
1✔
34

35
try:
1✔
36
    website_down = requests.get("https://materialsproject.org").status_code != 200
1✔
37
except requests.exceptions.ConnectionError:
×
38
    website_down = True
×
39

40

41
PMG_MAPI_KEY = SETTINGS.get("PMG_MAPI_KEY")
1✔
42
if PMG_MAPI_KEY and not 15 <= len(PMG_MAPI_KEY) <= 20:
1✔
43
    msg = f"Invalid legacy PMG_MAPI_KEY, should be 15-20 characters, got {len(PMG_MAPI_KEY)}"
×
44
    if len(PMG_MAPI_KEY) == 32:
×
45
        msg += " (this looks like a new API key)"
×
46
    if os.environ.get("CI"):
×
47
        raise ValueError(msg)
×
48

49

50
@unittest.skipIf(
1✔
51
    website_down or not PMG_MAPI_KEY,
52
    "PMG_MAPI_KEY environment variable not set or MP API is down.",
53
)
54
class MPResterOldTest(PymatgenTest):
1✔
55
    _multiprocess_shared_ = True
1✔
56

57
    def setUp(self):
1✔
58
        self.rester = _MPResterLegacy()
1✔
59
        warnings.simplefilter("ignore")
1✔
60

61
    def tearDown(self):
1✔
62
        warnings.simplefilter("default")
1✔
63
        self.rester.session.close()
1✔
64

65
    def test_get_all_materials_ids_doc(self):
1✔
66
        mids = self.rester.get_materials_ids("Al2O3")
1✔
67
        random.shuffle(mids)
1✔
68
        doc = self.rester.get_doc(mids.pop(0))
1✔
69
        assert doc["pretty_formula"] == "Al2O3"
1✔
70

71
    def test_get_xas_data(self):
1✔
72
        # Test getting XAS data
73
        data = self.rester.get_xas_data("mp-19017", "Li")
1✔
74
        assert "mp-19017,Li" == data["mid_and_el"]
1✔
75
        assert data["spectrum"]["x"][0] == pytest.approx(55.178)
1✔
76
        assert data["spectrum"]["y"][0] == pytest.approx(0.0164634)
1✔
77

78
    def test_get_data(self):
1✔
79
        props = {
1✔
80
            "energy",
81
            "energy_per_atom",
82
            "formation_energy_per_atom",
83
            "nsites",
84
            "unit_cell_formula",
85
            "pretty_formula",
86
            "is_hubbard",
87
            "elements",
88
            "nelements",
89
            "e_above_hull",
90
            "hubbards",
91
            "is_compatible",
92
            "task_ids",
93
            "density",
94
            "icsd_ids",
95
            "total_magnetization",
96
        }
97
        mpid = "mp-1143"
1✔
98
        vals = requests.get(f"http://legacy.materialsproject.org/materials/{mpid}/json/")
1✔
99
        expected_vals = vals.json()
1✔
100

101
        for prop in props:
1✔
102
            if prop not in [
1✔
103
                "hubbards",
104
                "unit_cell_formula",
105
                "elements",
106
                "icsd_ids",
107
                "task_ids",
108
            ]:
109
                val = self.rester.get_data(mpid, prop=prop)[0][prop]
1✔
110
                if prop in ["energy", "energy_per_atom"]:
1✔
111
                    prop = "final_" + prop
1✔
112
                assert expected_vals[prop] == pytest.approx(val), f"Failed with property {prop}"
1✔
113
            elif prop in ["elements", "icsd_ids", "task_ids"]:
1✔
114
                upstream_vals = set(self.rester.get_data(mpid, prop=prop)[0][prop])
1✔
115
                assert set(expected_vals[prop]) <= upstream_vals
1✔
116
            else:
117
                assert expected_vals[prop] == self.rester.get_data(mpid, prop=prop)[0][prop]
1✔
118

119
        props = ["structure", "initial_structure", "final_structure", "entry"]
1✔
120
        for prop in props:
1✔
121
            obj = self.rester.get_data(mpid, prop=prop)[0][prop]
1✔
122
            if prop.endswith("structure"):
1✔
123
                assert isinstance(obj, Structure)
1✔
124
            elif prop == "entry":
1✔
125
                obj = self.rester.get_data(mpid, prop=prop)[0][prop]
1✔
126
                assert isinstance(obj, ComputedEntry)
1✔
127

128
        # Test chemsys search
129
        data = self.rester.get_data("Fe-Li-O", prop="unit_cell_formula")
1✔
130
        assert len(data) > 1
1✔
131
        elements = {Element("Li"), Element("Fe"), Element("O")}
1✔
132
        for d in data:
1✔
133
            assert set(Composition(d["unit_cell_formula"]).elements).issubset(elements)
1✔
134

135
        with pytest.raises(MPRestError):
1✔
136
            self.rester.get_data("Fe2O3", "badmethod")
1✔
137

138
    def test_get_materials_id_from_task_id(self):
1✔
139
        assert self.rester.get_materials_id_from_task_id("mp-540081") == "mp-19017"
1✔
140

141
    def test_get_materials_id_references(self):
1✔
142
        # nosetests pymatgen/matproj/tests/test_matproj.py:MPResterOldTest.test_get_materials_id_references
143
        m = _MPResterLegacy()
1✔
144
        data = m.get_materials_id_references("mp-123")
1✔
145
        assert len(data) > 1000
1✔
146

147
    def test_find_structure(self):
1✔
148
        # nosetests pymatgen/matproj/tests/test_matproj.py:MPResterOldTest.test_find_structure
149
        m = _MPResterLegacy()
1✔
150
        ciffile = self.TEST_FILES_DIR / "Fe3O4.cif"
1✔
151
        data = m.find_structure(str(ciffile))
1✔
152
        assert len(data) > 1
1✔
153
        s = CifParser(ciffile).get_structures()[0]
1✔
154
        data = m.find_structure(s)
1✔
155
        assert len(data) > 1
1✔
156

157
    def test_get_entries_in_chemsys(self):
1✔
158
        syms = ["Li", "Fe", "O"]
1✔
159
        syms2 = "Li-Fe-O"
1✔
160
        entries = self.rester.get_entries_in_chemsys(syms)
1✔
161
        entries2 = self.rester.get_entries_in_chemsys(syms2)
1✔
162
        elements = {Element(sym) for sym in syms}
1✔
163
        for e in entries:
1✔
164
            assert isinstance(e, ComputedEntry)
1✔
165
            assert set(e.composition.elements).issubset(elements)
1✔
166

167
        e1 = {i.entry_id for i in entries}
1✔
168
        e2 = {i.entry_id for i in entries2}
1✔
169
        assert e1 == e2
1✔
170

171
        stable_entries = self.rester.get_entries_in_chemsys(syms, additional_criteria={"e_above_hull": {"$lte": 0.001}})
1✔
172
        assert len(stable_entries) < len(entries)
1✔
173

174
    def test_get_structure_by_material_id(self):
1✔
175
        s1 = self.rester.get_structure_by_material_id("mp-1")
1✔
176
        assert s1.formula == "Cs1"
1✔
177

178
        # requesting via task-id instead of mp-id
179
        with pytest.warns(Warning):
1✔
180
            self.rester.get_structure_by_material_id("mp-698856")
1✔
181

182
        # requesting unknown mp-id
183
        with pytest.raises(MPRestError):
1✔
184
            self.rester.get_structure_by_material_id("mp-does-not-exist")
1✔
185

186
    def test_get_entry_by_material_id(self):
1✔
187
        entry = self.rester.get_entry_by_material_id("mp-19017")
1✔
188
        assert isinstance(entry, ComputedEntry)
1✔
189
        assert entry.composition.reduced_formula, "LiFePO4"
1✔
190

191
        # "mp-2022" does not exist
192
        with pytest.raises(MPRestError):
1✔
193
            self.rester.get_entry_by_material_id("mp-2022")
1✔
194

195
    def test_query(self):
1✔
196
        criteria = {"elements": {"$in": ["Li", "Na", "K"], "$all": ["O"]}}
1✔
197
        props = ["pretty_formula", "energy"]
1✔
198
        data = self.rester.query(criteria=criteria, properties=props, chunk_size=0)
1✔
199
        assert len(data) > 6
1✔
200
        data = self.rester.query(criteria="*2O", properties=props, chunk_size=0)
1✔
201
        assert len(data) >= 52
1✔
202
        assert "Li2O" in (d["pretty_formula"] for d in data)
1✔
203

204
    def test_query_chunk_size(self):
1✔
205
        criteria = {"nelements": 2, "elements": "O"}
1✔
206
        props = ["pretty_formula"]
1✔
207
        data1 = self.rester.query(criteria=criteria, properties=props, chunk_size=0)
1✔
208
        data2 = self.rester.query(criteria=criteria, properties=props, chunk_size=500)
1✔
209
        assert {d["pretty_formula"] for d in data1} == {d["pretty_formula"] for d in data2}
1✔
210
        assert "Al2O3" in {d["pretty_formula"] for d in data1}
1✔
211

212
    def test_get_exp_thermo_data(self):
1✔
213
        data = self.rester.get_exp_thermo_data("Fe2O3")
1✔
214
        assert len(data) > 0
1✔
215
        for d in data:
1✔
216
            assert d.formula == "Fe2O3"
1✔
217

218
    def test_get_dos_by_id(self):
1✔
219
        dos = self.rester.get_dos_by_material_id("mp-2254")
1✔
220
        assert isinstance(dos, CompleteDos)
1✔
221

222
    def test_get_bandstructure_by_material_id(self):
1✔
223
        bs = self.rester.get_bandstructure_by_material_id("mp-2254")
1✔
224
        assert isinstance(bs, BandStructureSymmLine)
1✔
225
        bs_unif = self.rester.get_bandstructure_by_material_id("mp-2254", line_mode=False)
1✔
226
        assert isinstance(bs_unif, BandStructure)
1✔
227
        assert not isinstance(bs_unif, BandStructureSymmLine)
1✔
228

229
    def test_get_phonon_data_by_material_id(self):
1✔
230
        bs = self.rester.get_phonon_bandstructure_by_material_id("mp-661")
1✔
231
        assert isinstance(bs, PhononBandStructureSymmLine)
1✔
232
        dos = self.rester.get_phonon_dos_by_material_id("mp-661")
1✔
233
        assert isinstance(dos, CompletePhononDos)
1✔
234
        ddb_str = self.rester.get_phonon_ddb_by_material_id("mp-661")
1✔
235
        assert isinstance(ddb_str, str)
1✔
236

237
    def test_get_structures(self):
1✔
238
        structs = self.rester.get_structures("Mn3O4")
1✔
239
        assert len(structs) > 0
1✔
240

241
    def test_get_entries(self):
1✔
242
        entries = self.rester.get_entries("TiO2")
1✔
243
        assert len(entries) > 1
1✔
244
        for e in entries:
1✔
245
            assert e.composition.reduced_formula == "TiO2"
1✔
246

247
        entries = self.rester.get_entries("TiO2", inc_structure=True)
1✔
248
        assert len(entries) > 1
1✔
249
        for e in entries:
1✔
250
            assert e.structure.composition.reduced_formula == "TiO2"
1✔
251

252
        # all_entries = self.rester.get_entries("Fe", compatible_only=False)
253
        # entries = self.rester.get_entries("Fe", compatible_only=True)
254
        # self.assertTrue(len(entries) < len(all_entries))
255
        entries = self.rester.get_entries("Fe", compatible_only=True, property_data=["cif"])
1✔
256
        assert "cif" in entries[0].data
1✔
257

258
        for e in self.rester.get_entries("CdO2", inc_structure=False):
1✔
259
            assert e.data["oxide_type"] is not None
1✔
260

261
        # test if it will retrieve the conventional unit cell of Ni
262
        entry = self.rester.get_entry_by_material_id("mp-23", inc_structure=True, conventional_unit_cell=True)
1✔
263
        Ni = entry.structure
1✔
264
        assert Ni.lattice.a == Ni.lattice.b
1✔
265
        assert Ni.lattice.a == Ni.lattice.c
1✔
266
        assert Ni.lattice.alpha == 90
1✔
267
        assert Ni.lattice.beta == 90
1✔
268
        assert Ni.lattice.gamma == 90
1✔
269

270
        # Ensure energy per atom is same
271
        primNi = self.rester.get_entry_by_material_id("mp-23", inc_structure=True, conventional_unit_cell=False)
1✔
272
        assert primNi.energy_per_atom == entry.energy_per_atom
1✔
273

274
        Ni = self.rester.get_structure_by_material_id("mp-23", conventional_unit_cell=True)
1✔
275
        assert Ni.lattice.a == Ni.lattice.b
1✔
276
        assert Ni.lattice.a == Ni.lattice.c
1✔
277
        assert Ni.lattice.alpha == 90
1✔
278
        assert Ni.lattice.beta == 90
1✔
279
        assert Ni.lattice.gamma == 90
1✔
280

281
        # Test case where convs are different from initial and final
282
        # th = self.rester.get_structure_by_material_id(
283
        #     "mp-37", conventional_unit_cell=True)
284
        # th_entry = self.rester.get_entry_by_material_id(
285
        #     "mp-37", inc_structure=True, conventional_unit_cell=True)
286
        # th_entry_initial = self.rester.get_entry_by_material_id(
287
        #     "mp-37", inc_structure="initial", conventional_unit_cell=True)
288
        # self.assertEqual(th, th_entry.structure)
289
        # self.assertEqual(len(th_entry.structure), 4)
290
        # self.assertEqual(len(th_entry_initial.structure), 2)
291

292
        # Test if the polymorphs of Fe are properly sorted
293
        # by e_above_hull when sort_by_e_above_hull=True
294
        Fe_entries = self.rester.get_entries("Fe", sort_by_e_above_hull=True)
1✔
295
        assert Fe_entries[0].data["e_above_hull"] == 0
1✔
296

297
    def test_get_pourbaix_entries(self):
1✔
298
        # test input chemsys as a list of elements
299
        pbx_entries = self.rester.get_pourbaix_entries(["Fe", "Cr"])
1✔
300
        for pbx_entry in pbx_entries:
1✔
301
            assert isinstance(pbx_entry, PourbaixEntry)
1✔
302

303
        # test input chemsys as a string
304
        pbx_entries = self.rester.get_pourbaix_entries("Fe-Cr")
1✔
305
        for pbx_entry in pbx_entries:
1✔
306
            assert isinstance(pbx_entry, PourbaixEntry)
1✔
307

308
        # fe_two_plus = [e for e in pbx_entries if e.entry_id == "ion-0"][0]
309
        # self.assertAlmostEqual(fe_two_plus.energy, -1.12369, places=3)
310
        #
311
        # feo2 = [e for e in pbx_entries if e.entry_id == "mp-25332"][0]
312
        # self.assertAlmostEqual(feo2.energy, 3.56356, places=3)
313
        #
314
        # # Test S, which has Na in reference solids
315
        # pbx_entries = self.rester.get_pourbaix_entries(["S"])
316
        # so4_two_minus = pbx_entries[9]
317
        # self.assertAlmostEqual(so4_two_minus.energy, 0.301511, places=3)
318

319
        # Ensure entries are Pourbaix compatible
320
        PourbaixDiagram(pbx_entries)
1✔
321

322
    def test_get_exp_entry(self):
1✔
323
        entry = self.rester.get_exp_entry("Fe2O3")
1✔
324
        assert entry.energy == -825.5
1✔
325

326
    # def test_submit_query_delete_snl(self):
327
    # s = Structure([[5, 0, 0], [0, 5, 0], [0, 0, 5]], ["Fe"], [[0, 0, 0]])
328
    # d = self.rester.submit_snl(
329
    #     [s, s], remarks=["unittest"],
330
    #     authors="Test User <test@materialsproject.com>")
331
    # self.assertEqual(len(d), 2)
332
    # data = self.rester.query_snl({"about.remarks": "unittest"})
333
    # self.assertEqual(len(data), 2)
334
    # snlids = [d["_id"] for d in data]
335
    # self.rester.delete_snl(snlids)
336
    # data = self.rester.query_snl({"about.remarks": "unittest"})
337
    # self.assertEqual(len(data), 0)
338

339
    def test_get_stability(self):
1✔
340
        entries = self.rester.get_entries_in_chemsys(["Fe", "O"])
1✔
341
        modified_entries = []
1✔
342
        for entry in entries:
1✔
343
            # Create modified entries with energies that are 0.01eV higher
344
            # than the corresponding entries.
345
            if entry.composition.reduced_formula == "Fe2O3":
1✔
346
                modified_entries.append(
1✔
347
                    ComputedEntry(
348
                        entry.composition,
349
                        entry.uncorrected_energy + 0.01,
350
                        parameters=entry.parameters,
351
                        entry_id=f"mod_{entry.entry_id}",
352
                    )
353
                )
354
        rest_ehulls = self.rester.get_stability(modified_entries)
1✔
355
        all_entries = entries + modified_entries
1✔
356
        compat = MaterialsProject2020Compatibility()
1✔
357
        all_entries = compat.process_entries(all_entries)
1✔
358
        pd = PhaseDiagram(all_entries)
1✔
359
        for e in all_entries:
1✔
360
            if str(e.entry_id).startswith("mod"):
1✔
361
                for d in rest_ehulls:
1✔
362
                    if d["entry_id"] == e.entry_id:
1✔
363
                        data = d
1✔
364
                        break
1✔
365
                assert pd.get_e_above_hull(e) == pytest.approx(data["e_above_hull"])
1✔
366

367
    def test_get_reaction(self):
1✔
368
        rxn = self.rester.get_reaction(["Li", "O"], ["Li2O"])
1✔
369
        assert "Li2O" in rxn["Experimental_references"]
1✔
370

371
    def test_get_substrates(self):
1✔
372
        substrate_data = self.rester.get_substrates("mp-123", 5, [1, 0, 0])
1✔
373
        substrates = [sub_dict["sub_id"] for sub_dict in substrate_data]
1✔
374
        assert "mp-2534" in substrates
1✔
375

376
    def test_get_surface_data(self):
1✔
377
        data = self.rester.get_surface_data("mp-126")  # Pt
1✔
378
        one_surf = self.rester.get_surface_data("mp-129", miller_index=[-2, -3, 1])
1✔
379
        assert one_surf["surface_energy"] == pytest.approx(2.99156963)
1✔
380
        self.assertArrayAlmostEqual(one_surf["miller_index"], [3, 2, 1])
1✔
381
        assert "surfaces" in data
1✔
382
        surfaces = data["surfaces"]
1✔
383
        assert len(surfaces) > 0
1✔
384
        surface = surfaces.pop()
1✔
385
        assert "miller_index" in surface
1✔
386
        assert "surface_energy" in surface
1✔
387
        assert "is_reconstructed" in surface
1✔
388
        data_inc = self.rester.get_surface_data("mp-126", inc_structures=True)
1✔
389
        assert "structure" in data_inc["surfaces"][0]
1✔
390

391
    def test_get_wulff_shape(self):
1✔
392
        ws = self.rester.get_wulff_shape("mp-126")
1✔
393
        assert isinstance(ws, WulffShape)
1✔
394

395
    def test_get_cohesive_energy(self):
1✔
396
        ecoh = self.rester.get_cohesive_energy("mp-13")
1✔
397
        assert ecoh, 5.04543279
1✔
398

399
    def test_get_gb_data(self):
1✔
400
        mo_gbs = self.rester.get_gb_data(chemsys="Mo")
1✔
401
        assert len(mo_gbs) == 10
1✔
402
        mo_gbs_s5 = self.rester.get_gb_data(pretty_formula="Mo", sigma=5)
1✔
403
        assert len(mo_gbs_s5) == 3
1✔
404
        mo_s3_112 = self.rester.get_gb_data(
1✔
405
            material_id="mp-129",
406
            sigma=3,
407
            gb_plane=[1, -1, -2],
408
            include_work_of_separation=True,
409
        )
410
        assert len(mo_s3_112) == 1
1✔
411
        gb_f = mo_s3_112[0]["final_structure"]
1✔
412
        self.assertArrayAlmostEqual(gb_f.rotation_axis, [1, 1, 0])
1✔
413
        assert gb_f.rotation_angle == pytest.approx(109.47122)
1✔
414
        assert mo_s3_112[0]["gb_energy"] == pytest.approx(0.47965, rel=1e-4)
1✔
415
        assert mo_s3_112[0]["work_of_separation"] == pytest.approx(6.318144)
1✔
416
        assert "Mo24" in gb_f.formula
1✔
417
        hcp_s7 = self.rester.get_gb_data(material_id="mp-87", gb_plane=[0, 0, 0, 1], include_work_of_separation=True)
1✔
418
        assert hcp_s7[0]["gb_energy"] == pytest.approx(1.1206, rel=1e-4)
1✔
419
        assert hcp_s7[0]["work_of_separation"] == pytest.approx(2.4706, rel=1e-4)
1✔
420

421
    def test_get_interface_reactions(self):
1✔
422
        kinks = self.rester.get_interface_reactions("LiCoO2", "Li3PS4")
1✔
423
        assert len(kinks) > 0
1✔
424
        kink = kinks[0]
1✔
425
        assert "energy" in kink
1✔
426
        assert "ratio_atomic" in kink
1✔
427
        assert "rxn" in kink
1✔
428
        assert isinstance(kink["rxn"], Reaction)
1✔
429
        kinks_open_O = self.rester.get_interface_reactions("LiCoO2", "Li3PS4", open_el="O", relative_mu=-1)
1✔
430
        assert len(kinks_open_O) > 0
1✔
431
        with warnings.catch_warnings(record=True) as w:
1✔
432
            warnings.filterwarnings("always", message="The reactant.+")
1✔
433
            self.rester.get_interface_reactions("LiCoO2", "MnO9")
1✔
434
            assert "The reactant" in str(w[-1].message)
1✔
435

436
    def test_download_info(self):
1✔
437
        material_ids = ["mvc-2970"]
1✔
438
        task_types = [TaskType.GGA_OPT, TaskType.GGAU_UNIFORM]
1✔
439
        file_patterns = ["vasprun*", "OUTCAR*"]
1✔
440
        meta, urls = self.rester.get_download_info(material_ids, task_types=task_types, file_patterns=file_patterns)
1✔
441
        assert dict(meta) == {
1✔
442
            "mvc-2970": [{"task_id": "mp-1738602", "task_type": "GGA+U NSCF Uniform"}],
443
        }
444
        assert (
1✔
445
            urls[0] == "https://nomad-lab.eu/prod/rae/api/raw/query?file_pattern=vasprun*"
446
            "&file_pattern=OUTCAR*&external_id=mp-1738602"
447
        )
448

449
    def test_parse_criteria(self):
1✔
450
        crit = _MPResterLegacy.parse_criteria("mp-1234 Li-*")
1✔
451
        assert "Li-O" in crit["$or"][1]["chemsys"]["$in"]
1✔
452
        assert {"task_id": "mp-1234"} in crit["$or"]
1✔
453

454
        crit = _MPResterLegacy.parse_criteria("Li2*")
1✔
455
        assert "Li2O" in crit["pretty_formula"]["$in"]
1✔
456
        assert "Li2I" in crit["pretty_formula"]["$in"]
1✔
457
        assert "CsLi2" in crit["pretty_formula"]["$in"]
1✔
458

459
        crit = _MPResterLegacy.parse_criteria("Li-*-*")
1✔
460
        assert "Li-Re-Ru" in crit["chemsys"]["$in"]
1✔
461
        assert "Li-Li" not in crit["chemsys"]["$in"]
1✔
462

463
        comps = _MPResterLegacy.parse_criteria("**O3")["pretty_formula"]["$in"]
1✔
464
        for c in comps:
1✔
465
            assert len(Composition(c)) == 3, f"Failed in {c}"
1✔
466

467
        chemsys = _MPResterLegacy.parse_criteria("{Fe,Mn}-O")["chemsys"]["$in"]
1✔
468
        assert len(chemsys) == 2
1✔
469
        comps = _MPResterLegacy.parse_criteria("{Fe,Mn,Co}O")["pretty_formula"]["$in"]
1✔
470
        assert len(comps) == 3, comps
1✔
471

472
        # Let's test some invalid symbols
473

474
        with pytest.raises(ValueError):
1✔
475
            _MPResterLegacy.parse_criteria("li-fe")
1✔
476
        with pytest.raises(ValueError):
1✔
477
            _MPResterLegacy.parse_criteria("LO2")
1✔
478

479
        crit = _MPResterLegacy.parse_criteria("POPO2")
1✔
480
        assert "P2O3" in crit["pretty_formula"]["$in"]
1✔
481

482
    def test_include_user_agent(self):
1✔
483
        headers = self.rester.session.headers
1✔
484
        assert "user-agent" in headers, "Include user-agent header by default"
1✔
485
        m = re.match(
1✔
486
            r"pymatgen/(\d+)\.(\d+)\.(\d+)\.?(\d+)? \(Python/(\d+)\.(\d)+\.(\d+) ([^\/]*)/([^\)]*)\)",
487
            headers["user-agent"],
488
        )
489
        assert m is not None, f"Unexpected user-agent value {headers['user-agent']}"
1✔
490
        self.rester = _MPResterLegacy(include_user_agent=False)
1✔
491
        assert "user-agent" not in self.rester.session.headers, "user-agent header unwanted"
1✔
492

493
    def test_database_version(self):
1✔
494
        with _MPResterLegacy(notify_db_version=True) as mpr:
1✔
495
            db_version = mpr.get_database_version()
1✔
496

497
        assert isinstance(db_version, str)
1✔
498
        yaml = YAML()
1✔
499
        with open(MP_LOG_FILE) as f:
1✔
500
            d = yaml.load(f)
1✔
501

502
        assert d["MAPI_DB_VERSION"]["LAST_ACCESSED"] == db_version
1✔
503
        assert isinstance(d["MAPI_DB_VERSION"]["LOG"][db_version], int)
1✔
504

505
    def test_pourbaix_heavy(self):
1✔
506
        entries = self.rester.get_pourbaix_entries(["Li", "Mg", "Sn", "Pd"])
1✔
507
        _ = PourbaixDiagram(entries, nproc=4, filter_solids=False)
1✔
508
        entries = self.rester.get_pourbaix_entries(["Ba", "Ca", "V", "Cu", "F"])
1✔
509
        _ = PourbaixDiagram(entries, nproc=4, filter_solids=False)
1✔
510
        entries = self.rester.get_pourbaix_entries(["Ba", "Ca", "V", "Cu", "F", "Fe"])
1✔
511
        _ = PourbaixDiagram(entries, nproc=4, filter_solids=False)
1✔
512
        entries = self.rester.get_pourbaix_entries(["Na", "Ca", "Nd", "Y", "Ho", "F"])
1✔
513
        _ = PourbaixDiagram(entries, nproc=4, filter_solids=False)
1✔
514

515
    def test_pourbaix_mpr_pipeline(self):
1✔
516
        data = self.rester.get_pourbaix_entries(["Zn"])
1✔
517
        pbx = PourbaixDiagram(data, filter_solids=True, conc_dict={"Zn": 1e-8})
1✔
518
        pbx.find_stable_entry(10, 0)
1✔
519

520
        data = self.rester.get_pourbaix_entries(["Ag", "Te"])
1✔
521
        pbx = PourbaixDiagram(data, filter_solids=True, conc_dict={"Ag": 1e-8, "Te": 1e-8})
1✔
522
        assert len(pbx.stable_entries) == 29
1✔
523
        test_entry = pbx.find_stable_entry(8, 2)
1✔
524
        assert sorted(test_entry.entry_id) == ["ion-10", "mp-499"]
1✔
525

526
        # Test against ion sets with multiple equivalent ions (Bi-V regression)
527
        entries = self.rester.get_pourbaix_entries(["Bi", "V"])
1✔
528
        pbx = PourbaixDiagram(entries, filter_solids=True, conc_dict={"Bi": 1e-8, "V": 1e-8})
1✔
529
        assert all(["Bi" in entry.composition and "V" in entry.composition for entry in pbx.all_entries])
1✔
530

531

532
if __name__ == "__main__":
1✔
533
    unittest.main()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc