diff --git a/.ci_support/environment.yml b/.ci_support/environment.yml index 06938bf7a..bc3dd8bcb 100644 --- a/.ci_support/environment.yml +++ b/.ci_support/environment.yml @@ -8,7 +8,6 @@ dependencies: - codacy-coverage - matplotlib-base =3.7.0 - numpy =1.24.2 -- pandas =1.5.3 - phonopy =2.17.1 - pymatgen =2022.11.7 - pyscal =2.10.18 diff --git a/.github/workflows/mini.yml b/.github/workflows/mini.yml new file mode 100644 index 000000000..980a95508 --- /dev/null +++ b/.github/workflows/mini.yml @@ -0,0 +1,49 @@ +# This workflow is used to run the unittest of pyiron + +name: Minimal Installation Test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup environment + run: | + cp .ci_support/environment.yml environment.yml + sed -i '/aimsgb/d' environment.yml + sed -i '/phonopy/d' environment.yml + sed -i '/pymatgen/d' environment.yml + sed -i '/pyscal/d' environment.yml + sed -i '/scikit-learn/d' environment.yml + sed -i '/spglib/d' environment.yml + sed -i '/sqsgenerator/d' environment.yml + - name: Setup Mambaforge + uses: conda-incubator/setup-miniconda@v2 + with: + python-version: '3.11' + miniforge-variant: Mambaforge + channels: conda-forge + channel-priority: strict + activate-environment: my-env + use-mamba: true + - name: Update environment + run: mamba env update -n my-env -f environment.yml + - name: Setup + shell: bash -l {0} + run: | + pip install --no-deps . + - name: Test + shell: bash -l {0} + timeout-minutes: 30 + run: python -m unittest discover tests diff --git a/tests/test_aimsgb.py b/tests/test_aimsgb.py index f4ab57cc1..215eb04b1 100644 --- a/tests/test_aimsgb.py +++ b/tests/test_aimsgb.py @@ -6,7 +6,14 @@ from ase.build import bulk import structuretoolkit as stk +try: + import aimsgb + skip_aimsgb_test = False +except ImportError: + skip_aimsgb_test = True + +@unittest.skipIf(skip_aimsgb_test, "aimsgb is not installed, so the aimsgb tests are skipped.") class TestAimsgb(unittest.TestCase): @classmethod def setUpClass(cls): diff --git a/tests/test_analyse.py b/tests/test_analyse.py index b39dacf58..28ea8feb9 100644 --- a/tests/test_analyse.py +++ b/tests/test_analyse.py @@ -9,11 +9,25 @@ from ase.atoms import Atoms from scipy.spatial import Voronoi from ase.lattice.cubic import BodyCenteredCubic -from sklearn.cluster import AgglomerativeClustering, DBSCAN import structuretoolkit as stk +try: + from sklearn.cluster import AgglomerativeClustering, DBSCAN + skip_cluster_test = False +except ImportError: + skip_cluster_test = True + + +try: + import pyscal + skip_pyscal_test = False +except ImportError: + skip_pyscal_test = True + + class TestAtoms(unittest.TestCase): + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_layers(self): a_0 = 4 struct = bulk(name='Al', a=a_0, crystalstructure='fcc', cubic=True).repeat(10) @@ -54,11 +68,13 @@ def test_get_layers(self): "Overriding cluster method with DBSCAN does not return the same results for symmetric structure." ) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_layers_other_planes(self): structure = bulk(name='Fe', a=3.5, crystalstructure='fcc', cubic=True).repeat(2) layers = stk.analyse.get_layers(structure=structure, planes=[1, 1, 1]) self.assertEqual(np.unique(layers).tolist(), [0, 1, 2, 3, 4]) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_layers_with_strain(self): structure = bulk(name='Fe', a=2.8, crystalstructure='bcc', cubic=True).repeat(2) layers = stk.analyse.get_layers(structure=structure).tolist() @@ -67,6 +83,7 @@ def test_get_layers_with_strain(self): layers, stk.analyse.get_layers(structure=structure, planes=np.linalg.inv(structure.cell).T).tolist() ) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_layers_across_pbc(self): structure = bulk(name='Fe', a=2.8, crystalstructure='bcc', cubic=True).repeat(2) layers = stk.analyse.get_layers(structure=structure) @@ -74,6 +91,7 @@ def test_get_layers_across_pbc(self): structure = stk.common.center_coordinates_in_unit_cell(structure=structure) self.assertEqual(len(np.unique(layers[stk.analyse.get_layers(structure=structure)[:, 0] == 0, 0])), 1) + @unittest.skipIf(skip_pyscal_test, "pyscal is not installed, so the pyscal tests are skipped.") def test_pyscal_cna_adaptive(self): basis = Atoms( "FeFe", scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)], cell=np.identity(3) @@ -82,17 +100,20 @@ def test_pyscal_cna_adaptive(self): stk.analyse.get_adaptive_cna_descriptors(structure=basis)["bcc"] == 2 ) + @unittest.skipIf(skip_pyscal_test, "pyscal is not installed, so the pyscal tests are skipped.") def test_pyscal_centro_symmetry(self): basis = bulk(name='Fe', a=2.8, crystalstructure='bcc', cubic=True) self.assertTrue( all([np.isclose(v, 0.0) for v in stk.analyse.get_centro_symmetry_descriptors(structure=basis, num_neighbors=8)]) ) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_voronoi_vertices(self): basis = bulk(name='Al', a=4, crystalstructure='fcc', cubic=True) self.assertEqual(len(stk.analyse.get_voronoi_vertices(structure=basis)), 12) self.assertEqual(len(stk.analyse.get_voronoi_vertices(structure=basis, distance_threshold=2)), 1) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_interstitials_bcc(self): bcc = bulk('Fe', cubic=True) x_octa_ref = bcc.positions[:, None, :]+0.5*bcc.cell[None, :, :] @@ -114,6 +135,7 @@ def test_get_interstitials_bcc(self): ).min(axis=0).sum(), 0 ) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_get_interstitials_fcc(self): fcc = bulk('Al', cubic=True) a_0 = fcc.cell[0, 0] @@ -190,6 +212,7 @@ def test_tessellations(self): structure.positions[stk.analyse.get_voronoi_neighbors(structure=structure)], axis=-2 )), axis=-1).flatten().max(), a_0) + @unittest.skipIf(skip_cluster_test, "sklearn is not installed, so the cluster tests are skipped.") def test_cluster_positions(self): structure_bulk = bulk('Fe', cubic=True) self.assertEqual(len(stk.analyse.get_cluster_positions(structure=structure_bulk)), len(structure_bulk)) diff --git a/tests/test_compound.py b/tests/test_compound.py index 4c8f44b75..1b8b9bd00 100644 --- a/tests/test_compound.py +++ b/tests/test_compound.py @@ -8,6 +8,12 @@ import numpy as np import structuretoolkit as stk +try: + import spglib + skip_spglib_test = False +except ImportError: + skip_spglib_test = True + class TestCompound(unittest.TestCase): def test_B2(self): @@ -31,6 +37,7 @@ def test_C14(self): self.assertEqual(len(c14), 12, "Wrong number of atoms in C14 structure.") self.assertEqual(c14.get_chemical_formula(), "Cu8Mg4", "Wrong chemical formula.") + @unittest.skipIf(skip_spglib_test, "spglib is not installed, so the C15 tests are skipped.") def test_C15(self): """ Tests based on Xie et al., JMR 2021 (DOI:10.1557/s43578-021-00237-y). diff --git a/tests/test_high_index_surface.py b/tests/test_high_index_surface.py index d9b569909..b6db50f34 100644 --- a/tests/test_high_index_surface.py +++ b/tests/test_high_index_surface.py @@ -1,8 +1,22 @@ import unittest import structuretoolkit as stk +try: + import pymatgen + skip_pymatgen_test = False +except ImportError: + skip_pymatgen_test = True + + +try: + import spglib + skip_spglib_test = False +except ImportError: + skip_spglib_test = True + class TestHighIndexSurface(unittest.TestCase): + @unittest.skipIf(skip_pymatgen_test, "pymatgen is not installed, so the surface tests are skipped.") def test_high_index_surface(self): slab = stk.build.high_index_surface( element='Ni', @@ -20,6 +34,7 @@ def test_high_index_surface(self): self.assertEqual(len(slab), 60) + @unittest.skipIf(skip_spglib_test, "spglib is not installed, so the surface info tests are skipped.") def test_high_index_surface_info(self): h, s, k = stk.build.get_high_index_surface_info( element='Ni', diff --git a/tests/test_neighbors.py b/tests/test_neighbors.py index 8cb1a34ec..b56a3d4b0 100644 --- a/tests/test_neighbors.py +++ b/tests/test_neighbors.py @@ -9,6 +9,19 @@ from ase.atoms import Atoms import warnings +try: + import pyscal + skip_pyscal_test = False +except ImportError: + skip_pyscal_test = True + + +try: + import sklearn + skip_sklearn_test = False +except ImportError: + skip_sklearn_test = True + class TestAtoms(unittest.TestCase): @classmethod @@ -150,6 +163,10 @@ def test_wrapped_positions(self): np.all(np.isclose(distances, neigh.get_neighborhood(new_positions, num_neighbors=13).distances[:,1:])) ) + @unittest.skipIf( + skip_sklearn_test, + "scikit-learn is not installed, so the clustering tests are skipped." + ) def test_get_global_shells(self): structure = bulk('Al', a=4, cubic=True).repeat(2) neigh = stk.analyse.get_neighbors(structure=structure) @@ -172,6 +189,10 @@ def test_get_global_shells(self): self.assertTrue(np.array_equal(shells, neigh.get_global_shells(cluster_by_vecs=True))) self.assertFalse(np.array_equal(shells, neigh.get_global_shells())) + @unittest.skipIf( + skip_sklearn_test, + "scikit-learn is not installed, so the clustering tests are skipped." + ) def test_get_local_shells(self): structure = bulk('Al', a=4, cubic=True).repeat(2) neigh = stk.analyse.get_neighbors(structure=structure) @@ -187,6 +208,10 @@ def test_get_local_shells(self): self.assertTrue(np.array_equal(shells, neigh.get_local_shells(cluster_by_vecs=True))) self.assertFalse(np.array_equal(shells, neigh.get_local_shells())) + @unittest.skipIf( + skip_sklearn_test, + "scikit-learn is not installed, so the clustering tests are skipped." + ) def test_get_global_shells_ragged(self): structure = bulk('Al', a=4, cubic=True).repeat(2) del structure[0] @@ -203,6 +228,10 @@ def test_get_global_shells_ragged(self): self.assertEqual(np.sum([len(s) == 11 for s in neigh.get_global_shells(cluster_by_vecs=True)]), 12) self.assertEqual(np.sum([len(s) == 11 for s in neigh.get_global_shells(cluster_by_distances=True, cluster_by_vecs=True)]), 12) + @unittest.skipIf( + skip_sklearn_test, + "scikit-learn is not installed, so the clustering tests are skipped." + ) def test_get_local_shells_ragged(self): structure = bulk('Al', a=4, cubic=True).repeat(2) del structure[0] @@ -379,6 +408,10 @@ def test_modes(self): with self.assertRaises(KeyError): neigh = stk.analyse.get_neighbors(structure=basis, mode='random_key') + @unittest.skipIf( + skip_pyscal_test, + "pyscal is not installed, so the centro symmetry descriptor based tests are skipped." + ) def test_centrosymmetry(self): structure = bulk('Fe').repeat(4) cs = stk.analyse.get_neighbors(structure=structure, num_neighbors=8).centrosymmetry diff --git a/tests/test_pyscal.py b/tests/test_pyscal.py index 3c53f24d0..63bdc298f 100644 --- a/tests/test_pyscal.py +++ b/tests/test_pyscal.py @@ -8,7 +8,14 @@ from ase.atoms import Atoms import structuretoolkit as stk +try: + import pyscal + skip_pyscal_test = False +except ImportError: + skip_pyscal_test = True + +@unittest.skipIf(skip_pyscal_test, "pyscal is not installed, so the pyscal tests are skipped.") class Testpyscal(unittest.TestCase): @classmethod def setUpClass(cls): @@ -71,6 +78,7 @@ def test_volume(self): self.assertLess(np.abs(np.mean(vols) - 16.0), 1E-3) +@unittest.skipIf(skip_pyscal_test, "pyscal is not installed, so the pyscal tests are skipped.") class Testpyscalatoms(unittest.TestCase): @classmethod def setUpClass(cls): diff --git a/tests/test_strain.py b/tests/test_strain.py index 4a6cc4a18..d2c456959 100644 --- a/tests/test_strain.py +++ b/tests/test_strain.py @@ -4,6 +4,12 @@ from ase.build import bulk import structuretoolkit as stk +try: + import pyscal + skip_pyscal_test = False +except ImportError: + skip_pyscal_test = True + class TestAtoms(unittest.TestCase): @classmethod @@ -11,6 +17,7 @@ def setUpClass(cls): bulk_structure = bulk('Fe', cubic=True) cls.strain = stk.analyse.get_strain(structure=bulk_structure, ref_structure=bulk_structure, return_object=True) + @unittest.skipIf(skip_pyscal_test, "pyscal is not installed, so the pyscal tests are skipped.") def test_number_of_neighbors(self): self.assertEqual(self.strain.num_neighbors, 8) bulk_structure = bulk('Al', cubic=True) diff --git a/tests/test_symmetry.py b/tests/test_symmetry.py index defd8d326..d31127235 100644 --- a/tests/test_symmetry.py +++ b/tests/test_symmetry.py @@ -8,7 +8,20 @@ from ase.atoms import Atoms import structuretoolkit as stk +try: + import pyscal + skip_pyscal_test = False +except ImportError: + skip_pyscal_test = True + +try: + import spglib + skip_spglib_test = False +except ImportError: + skip_spglib_test = True + +@unittest.skipIf(skip_spglib_test, "spglib is not installed, so the spglib tests are skipped.") class TestAtoms(unittest.TestCase): def test_get_arg_equivalent_sites(self): a_0 = 4.0