11from __future__ import annotations
22
3+ import importlib
34from importlib .metadata import PackageNotFoundError
5+ from unittest import mock
46
57import numpy as np
68import pytest
1113from pymatgen .io .ase import AseAtomsAdaptor , MSONAtoms
1214from pymatgen .util .testing import TEST_FILES_DIR , VASP_IN_DIR , VASP_OUT_DIR
1315
14- try :
15- import ase
16- except ImportError :
17- ase = None
16+ ase = pytest .importorskip ("ase" , reason = "ase not installed" )
1817
1918STRUCTURE = Structure .from_file (f"{ VASP_IN_DIR } /POSCAR" )
2019XYZ_STRUCTURE = f"{ TEST_FILES_DIR } /io/xyz/acetylene.xyz"
2120
22- skip_if_no_ase = pytest .mark .skipif (ase is None , reason = "ase not installed" )
2321
24-
25- @skip_if_no_ase
2622def test_get_atoms_from_structure ():
2723 atoms = AseAtomsAdaptor .get_atoms (STRUCTURE )
2824 ase_composition = Composition (atoms .get_chemical_formula ())
@@ -42,7 +38,6 @@ def test_get_atoms_from_structure():
4238 assert atoms .get_array ("prop" ).tolist () == prop
4339
4440
45- @skip_if_no_ase
4641def test_get_atoms_from_structure_mags ():
4742 mags = [1.0 ] * len (STRUCTURE )
4843 STRUCTURE .add_site_property ("final_magmom" , mags )
@@ -64,7 +59,6 @@ def test_get_atoms_from_structure_mags():
6459 assert atoms .get_magnetic_moments ().tolist (), mags
6560
6661
67- @skip_if_no_ase
6862def test_get_atoms_from_structure_charge ():
6963 charges = [1.0 ] * len (STRUCTURE )
7064 STRUCTURE .add_site_property ("final_charge" , charges )
@@ -86,22 +80,19 @@ def test_get_atoms_from_structure_charge():
8680 assert atoms .get_charges ().tolist (), charges
8781
8882
89- @skip_if_no_ase
9083def test_get_atoms_from_structure_oxi_states ():
9184 oxi_states = [1.0 ] * len (STRUCTURE )
9285 STRUCTURE .add_oxidation_state_by_site (oxi_states )
9386 atoms = AseAtomsAdaptor .get_atoms (STRUCTURE )
9487 assert atoms .get_array ("oxi_states" ).tolist () == oxi_states
9588
9689
97- @skip_if_no_ase
9890def test_get_atoms_from_structure_dyn ():
9991 STRUCTURE .add_site_property ("selective_dynamics" , [[False ] * 3 ] * len (STRUCTURE ))
10092 atoms = AseAtomsAdaptor .get_atoms (STRUCTURE )
10193 assert atoms .constraints [0 ].get_indices ().tolist () == [atom .index for atom in atoms ]
10294
10395
104- @skip_if_no_ase
10596def test_get_atoms_from_molecule ():
10697 mol = Molecule .from_file (XYZ_STRUCTURE )
10798 atoms = AseAtomsAdaptor .get_atoms (mol )
@@ -113,7 +104,6 @@ def test_get_atoms_from_molecule():
113104 assert not atoms .has ("initial_magmoms" )
114105
115106
116- @skip_if_no_ase
117107def test_get_atoms_from_molecule_mags ():
118108 molecule = Molecule .from_file (XYZ_STRUCTURE )
119109 atoms = AseAtomsAdaptor .get_atoms (molecule )
@@ -139,15 +129,13 @@ def test_get_atoms_from_molecule_mags():
139129 assert atoms .spin_multiplicity == 3
140130
141131
142- @skip_if_no_ase
143132def test_get_atoms_from_molecule_dyn ():
144133 molecule = Molecule .from_file (XYZ_STRUCTURE )
145134 molecule .add_site_property ("selective_dynamics" , [[False ] * 3 ] * len (molecule ))
146135 atoms = AseAtomsAdaptor .get_atoms (molecule )
147136 assert atoms .constraints [0 ].get_indices ().tolist () == [atom .index for atom in atoms ]
148137
149138
150- @skip_if_no_ase
151139def test_get_structure ():
152140 atoms = ase .io .read (f"{ VASP_IN_DIR } /POSCAR" )
153141 struct = AseAtomsAdaptor .get_structure (atoms )
@@ -170,7 +158,6 @@ def test_get_structure():
170158 struct = AseAtomsAdaptor .get_structure (atoms , validate_proximity = True )
171159
172160
173- @skip_if_no_ase
174161def test_get_structure_mag ():
175162 atoms = ase .io .read (f"{ VASP_IN_DIR } /POSCAR" )
176163 mags = [1.0 ] * len (atoms )
@@ -187,7 +174,6 @@ def test_get_structure_mag():
187174 assert "initial_magmoms" not in structure .site_properties
188175
189176
190- @skip_if_no_ase
191177@pytest .mark .parametrize (
192178 "select_dyn" ,
193179 [[True , True , True ], [False , False , False ], np .array ([True , True , True ]), np .array ([False , False , False ])],
@@ -212,7 +198,6 @@ def test_get_structure_dyn(select_dyn):
212198 assert len (ase_atoms ) == len (structure )
213199
214200
215- @skip_if_no_ase
216201def test_get_molecule ():
217202 atoms = ase .io .read (XYZ_STRUCTURE )
218203 molecule = AseAtomsAdaptor .get_molecule (atoms )
@@ -240,7 +225,6 @@ def test_get_molecule():
240225 assert molecule .spin_multiplicity == 3
241226
242227
243- @skip_if_no_ase
244228@pytest .mark .parametrize ("filename" , ["io/vasp/outputs/OUTCAR.gz" , "cif/V2O3.cif" ])
245229def test_back_forth (filename ):
246230 # Atoms --> Structure --> Atoms --> Structure
@@ -259,7 +243,6 @@ def test_back_forth(filename):
259243 assert str (atoms_back .todict ()[key ]) == str (val )
260244
261245
262- @skip_if_no_ase
263246def test_back_forth_v2 ():
264247 # Structure --> Atoms --> Structure --> Atoms
265248 structure = Structure .from_file (f"{ VASP_IN_DIR } /POSCAR" )
@@ -281,7 +264,6 @@ def test_back_forth_v2():
281264 MontyDecoder ().process_decoded (dct )
282265
283266
284- @skip_if_no_ase
285267def test_back_forth_v3 ():
286268 # Atoms --> Molecule --> Atoms --> Molecule
287269 atoms = ase .io .read (XYZ_STRUCTURE )
@@ -299,7 +281,6 @@ def test_back_forth_v3():
299281 assert molecule_back == molecule
300282
301283
302- @skip_if_no_ase
303284def test_back_forth_v4 ():
304285 # Molecule --> Atoms --> Molecule --> Atoms
305286 molecule = Molecule .from_file (XYZ_STRUCTURE )
@@ -317,7 +298,6 @@ def test_back_forth_v4():
317298 MontyDecoder ().process_decoded (dct )
318299
319300
320- @skip_if_no_ase
321301def test_back_forth_v5 ():
322302 # Structure --> Atoms --> Structure --> Atoms
323303 structure = Structure .from_file (f"{ VASP_IN_DIR } /POSCAR" )
@@ -331,7 +311,6 @@ def test_back_forth_v5():
331311 assert str (atoms_back .todict ()[key ]) == str (val )
332312
333313
334- @skip_if_no_ase
335314def test_msonable_atoms ():
336315 structure = Structure .from_file (f"{ VASP_IN_DIR } /POSCAR" )
337316
@@ -369,10 +348,12 @@ def test_msonable_atoms():
369348 assert isinstance (atoms , ase .Atoms )
370349
371350
372- @pytest .mark .skipif (ase is not None , reason = "ase is present" )
373351def test_no_ase_err ():
374352 import pymatgen .io .ase
375353
376- expected_msg = str (pymatgen .io .ase .NO_ASE_ERR )
377- with pytest .raises (PackageNotFoundError , match = expected_msg ):
378- pymatgen .io .ase .MSONAtoms ()
354+ with mock .patch .dict ("sys.modules" , {"ase.atoms" : None }):
355+ importlib .reload (pymatgen .io .ase )
356+ from pymatgen .io .ase import MSONAtoms
357+
358+ with pytest .raises (PackageNotFoundError , match = "AseAtomsAdaptor requires the ASE package." ):
359+ MSONAtoms ()
0 commit comments