Skip to content

Commit 49e6396

Browse files
Housekeeping: Update package versions / lint workflow (#533)
* Add a linting workflow * Partial mypy fixes * Bumping versions of packages dependencies to keep in sync with emmet-core
1 parent 49f9581 commit 49e6396

File tree

14 files changed

+99
-59
lines changed

14 files changed

+99
-59
lines changed

.github/workflows/lint.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Linting
2+
3+
on: [push]
4+
5+
permissions:
6+
contents: read
7+
8+
jobs:
9+
lint:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up Python
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.10"
18+
cache: pip
19+
20+
- name: Install dependencies
21+
run: |
22+
pip install pre-commit
23+
24+
- name: Run pre-commit
25+
run: |
26+
pre-commit run --all-files --show-diff-on-failure

.github/workflows/tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@ jobs:
1313
uses: conda-incubator/setup-miniconda@v3
1414
with:
1515
python-version: "3.10"
16+
auto-update-conda: true
17+
channels: anaconda, conda-forge
1618

1719
- name: Install dependencies
20+
shell: bash -l {0}
1821
run: |
1922
conda install --quiet --yes -c conda-forge openbabel pip ruamel.yaml
2023
pip install -r requirements.txt
2124
pip install -e .[tests,cli]
2225
2326
- name: Test
27+
shell: bash -l {0}
2428
run: pytest --cov=robocrys --cov-report=xml --cov-config=.coveragerc tests/
2529

2630
docs:

.pre-commit-config.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
exclude: ^(docs|tests|dev_scripts|.github)
22

3-
default_language_version:
4-
python: python3.11
5-
63
ci:
74
autoupdate_schedule: yearly
85
skip: [flake8, autoflake, mypy]

requirements.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
spglib==2.5.0
1+
spglib==2.6.0
22
numpy==1.26.4
3-
scipy==1.14.1
4-
pymatgen==2024.4.13
5-
inflect==7.4.0
6-
networkx==3.3
7-
matminer==0.9.2
8-
monty==2024.7.30
3+
scipy==1.15.2
4+
pymatgen==2025.3.10
5+
inflect==7.5.0
6+
networkx==3.4.2
7+
matminer==0.9.3
8+
monty==2025.3.3
99
pubchempy==1.0.4
1010
pybtex==0.24.0

robocrys/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pymatgen.core.structure import Structure
1010

1111
try:
12-
from mp_api.client import MPRestError
12+
from mp_api.client import MPRestError # type:ignore[import-untyped]
1313
except ImportError:
1414
MPRestError = None
1515

robocrys/condense/fingerprint.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
from collections.abc import Iterable
44

55
import numpy as np
6-
from matminer.featurizers.site import CrystalNNFingerprint
7-
from matminer.featurizers.structure import SiteStatsFingerprint
6+
from matminer.featurizers.site import (
7+
CrystalNNFingerprint,
8+
) # type:ignore[import-untyped]
9+
from matminer.featurizers.structure import (
10+
SiteStatsFingerprint,
11+
) # type:ignore[import-untyped]
812
from pymatgen.core.structure import IStructure
913

1014

@@ -42,7 +46,7 @@ def get_site_fingerprints(
4246

4347
if as_dict:
4448
labels = ssf.feature_labels()
45-
site_fingerprints = [dict(zip(labels, x)) for x in site_fingerprints]
49+
return [dict(zip(labels, x)) for x in site_fingerprints]
4650

4751
return site_fingerprints
4852

@@ -107,13 +111,13 @@ def get_fingerprint_distance(
107111
The euclidean distance between fingerprints as a :class:`numpy.ndarray`.
108112
"""
109113
if issubclass(type(structure_a), IStructure):
110-
fingerprint_a = get_structure_fingerprint(structure_a)
114+
fingerprint_a = get_structure_fingerprint(structure_a) # type: ignore[arg-type]
111115
else:
112116
fingerprint_a = np.array(structure_a)
113117

114118
if issubclass(type(structure_b), IStructure):
115-
fingerprint_b = get_structure_fingerprint(structure_b)
119+
fingerprint_b = get_structure_fingerprint(structure_b) # type: ignore[arg-type]
116120
else:
117121
fingerprint_b = np.array(structure_b)
118122

119-
return np.linalg.norm(fingerprint_a - fingerprint_b)
123+
return np.linalg.norm(fingerprint_a - fingerprint_b) # type: ignore[return-value]

robocrys/condense/mineral.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,25 @@
55
from importlib.resources import files as import_resource_file
66
from itertools import islice
77
from pathlib import Path
8-
from typing import TYPE_CHECKING, Any
8+
from typing import TYPE_CHECKING
99

1010
import numpy as np
11-
from matminer.utils.io import load_dataframe_from_json
11+
from matminer.utils.io import load_dataframe_from_json # type:ignore[import-untyped]
1212
from pymatgen.analysis.prototypes import AflowPrototypeMatcher
13-
from pymatgen.core.structure import IStructure
1413
from robocrys.condense.fingerprint import (
1514
get_fingerprint_distance,
1615
get_structure_fingerprint,
1716
)
1817

1918

2019
if TYPE_CHECKING:
20+
from typing import Any
2121
import pandas as pd
2222

23-
_mineral_db_file = import_resource_file("robocrys.condense") / "mineral_db.json.gz"
23+
from pymatgen.core.structure import Structure
24+
25+
26+
_mineral_db_file = str(import_resource_file("robocrys.condense") / "mineral_db.json.gz")
2427

2528

2629
class MineralMatcher:
@@ -60,9 +63,11 @@ def __init__(
6063
fingerprint_distance_cutoff: float = 0.4,
6164
mineral_db: str | Path | pd.DataFrame | None = None,
6265
):
63-
self.mineral_db = mineral_db if mineral_db is not None else _mineral_db_file
64-
if isinstance(self.mineral_db, (str, Path)):
65-
self.mineral_db = load_dataframe_from_json(self.mineral_db, pbar=False)
66+
mineral_db = mineral_db or _mineral_db_file
67+
if isinstance(mineral_db, (str, Path)):
68+
self.mineral_db = load_dataframe_from_json(mineral_db, pbar=False)
69+
else:
70+
self.mineral_db = mineral_db
6671

6772
self.initial_ltol = initial_ltol
6873
self.initial_stol = initial_stol
@@ -72,7 +77,7 @@ def __init__(
7277
self._structure = None
7378
self._mineral_db = None
7479

75-
def get_best_mineral_name(self, structure: IStructure) -> dict[str, Any]:
80+
def get_best_mineral_name(self, structure: Structure) -> dict[str, Any]:
7681
"""Gets the "best" mineral name for a structure.
7782
7883
Uses a combination of AFLOW prototype matching and fingerprinting to
@@ -138,7 +143,7 @@ def get_best_mineral_name(self, structure: IStructure) -> dict[str, Any]:
138143

139144
def get_aflow_matches(
140145
self,
141-
structure: IStructure,
146+
structure: Structure,
142147
) -> list[dict[str, Any]] | None:
143148
"""Gets minerals for a structure by matching to AFLOW prototypes.
144149
@@ -190,7 +195,7 @@ def _match_prototype(structure_matcher, s):
190195

191196
def get_fingerprint_matches(
192197
self,
193-
structure: IStructure,
198+
structure: Structure,
194199
max_n_matches: int | None = None,
195200
match_n_sp: bool = True,
196201
mineral_name_constraint: str | None = None,
@@ -240,7 +245,7 @@ def get_fingerprint_matches(
240245

241246
return minerals if minerals else None
242247

243-
def _set_distance_matrix(self, structure: IStructure):
248+
def _set_distance_matrix(self, structure: Structure):
244249
"""Utility func to calculate distance between structure and minerals.
245250
246251
First checks to see if the distances have already been calculated for

robocrys/condense/molecule.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from monty.serialization import loadfn
1111
from importlib.resources import files as import_resource_file
12-
from pubchempy import BadRequestError, get_compounds
12+
from pubchempy import BadRequestError, get_compounds # type:ignore[import-untyped]
1313
from pymatgen.analysis.graphs import MoleculeGraph
1414
from pymatgen.io.babel import BabelMolAdaptor
1515

@@ -20,7 +20,7 @@ class MoleculeNamer:
2020
def __init__(
2121
self,
2222
use_online_pubchem: bool = True,
23-
name_preference: tuple[str] = name_sources,
23+
name_preference: tuple[str, ...] = name_sources,
2424
):
2525
"""Class to match molecule graphs to known molecule names.
2626
@@ -36,8 +36,8 @@ def __init__(
3636
to last.
3737
"""
3838
db_file = import_resource_file("robocrys.condense") / "molecule_db.json.gz"
39-
self.molecule_db = loadfn(db_file)
40-
self.matched_molecules = {}
39+
self.molecule_db: dict[str, dict[str, str]] = loadfn(str(db_file))
40+
self.matched_molecules: dict[str, str] = {}
4141
self.use_online_pubchem = use_online_pubchem
4242

4343
# append the sources list to the end in case the user only supplies
@@ -122,7 +122,7 @@ def molecule_graph_to_smiles(molecule_graph: MoleculeGraph) -> str | None:
122122
try:
123123
bma = BabelMolAdaptor.from_molecule_graph(molecule_graph)
124124
pbmol = bma.pybel_mol
125-
return pbmol.write("smi").split()[0]
125+
return pbmol.write("smi").split()[0] # type: ignore[attr-defined]
126126
except RuntimeError:
127127
warnings.warn(
128128
"Molecule naming requires openbabel to be installed "

robocrys/describe/adapter.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
from __future__ import annotations
66

77
from collections import defaultdict, namedtuple
8-
from typing import Any
8+
from typing import TYPE_CHECKING
99

1010
import numpy as np
1111
from pymatgen.core.periodic_table import get_el_sp
1212

1313
from robocrys.adapter import BaseAdapter
1414

15+
if TYPE_CHECKING:
16+
from typing import Any
17+
1518
ComponentDetails = namedtuple(
1619
"ComponentDetails",
1720
[
@@ -178,7 +181,7 @@ def get_next_nearest_neighbor_details(
178181
geometry = self.sites[nnn_site]["geometry"]["type"]
179182

180183
if group:
181-
identity = (element, connectivity, geometry)
184+
identity: tuple[Any, ...] = (element, connectivity, geometry)
182185
else:
183186
identity = (element, connectivity, geometry, labels)
184187

robocrys/describe/describer.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,7 @@ def get_component_makeup_summary(self) -> str:
198198
if self._da.dimensionality == 3:
199199
desc = "The structure consists of "
200200
else:
201-
desc = "The structure is {}-dimensional and consists of ".format(
202-
en.number_to_words(self._da.dimensionality)
203-
)
201+
desc = f"The structure is {en.number_to_words(self._da.dimensionality)}-dimensional and consists of "
204202

205203
component_makeup_summaries = []
206204
nframeworks = len(

0 commit comments

Comments
 (0)