From 87c92e644248ce57940fdab3bbe9088db8d25262 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Thu, 2 May 2024 11:20:18 -0400 Subject: [PATCH] More type annotations (#3800) * add Self return anno to copy() methods * improve TestGrainBoundary.test_copy TestGrainBoundary setUpClass -> setUp, helps language server infer types of class attributes * add type annotations * remove boilerplate inverse(self) -> None and is_one_to_many(self) -> False properties on AbstractTransformation subclasses * is_one_to_many doc string to "Transform one structure to many." if returns True * format """Returns: ... doc str by replacing with 'Returns:'->'Get' for methods and 'Returns:'->'' for properties --- dev_scripts/potcar_scrambler.py | 2 +- dev_scripts/update_pt_data.py | 6 +- pymatgen/alchemy/filters.py | 6 +- .../coordination_geometries.py | 120 ++++++++-------- pymatgen/analysis/chempot_diagram.py | 2 +- pymatgen/analysis/elasticity/elastic.py | 11 +- pymatgen/analysis/ewald.py | 8 +- .../analysis/ferroelectricity/polarization.py | 2 +- .../analysis/molecule_structure_comparator.py | 2 +- pymatgen/analysis/nmr.py | 12 +- pymatgen/analysis/pourbaix_diagram.py | 2 +- pymatgen/analysis/structure_matcher.py | 8 +- .../structure_prediction/dopant_predictor.py | 6 +- .../substitution_probability.py | 2 +- .../structure_prediction/substitutor.py | 16 +-- pymatgen/analysis/surface_analysis.py | 6 +- pymatgen/analysis/thermochemistry.py | 2 +- pymatgen/apps/battery/battery_abc.py | 4 +- pymatgen/apps/battery/insertion_battery.py | 2 +- pymatgen/apps/borg/hive.py | 6 +- pymatgen/command_line/bader_caller.py | 4 +- pymatgen/command_line/chargemol_caller.py | 4 +- pymatgen/command_line/critic2_caller.py | 6 +- pymatgen/core/interface.py | 20 +-- pymatgen/core/lattice.py | 4 +- pymatgen/core/operations.py | 4 +- pymatgen/core/spectrum.py | 3 +- pymatgen/core/structure.py | 30 ++-- pymatgen/core/surface.py | 4 +- pymatgen/electronic_structure/boltztrap.py | 6 +- pymatgen/entries/correction_calculator.py | 10 +- pymatgen/ext/matproj_legacy.py | 2 +- pymatgen/io/abinit/abiobjects.py | 2 +- pymatgen/io/abinit/pseudos.py | 7 +- pymatgen/io/adf.py | 10 +- pymatgen/io/cif.py | 4 +- pymatgen/io/common.py | 4 +- pymatgen/io/feff/inputs.py | 12 +- pymatgen/io/feff/outputs.py | 8 +- pymatgen/io/icet.py | 4 +- pymatgen/io/lammps/outputs.py | 2 +- pymatgen/io/lobster/outputs.py | 62 ++++----- pymatgen/io/nwchem.py | 4 +- pymatgen/io/openff.py | 5 +- pymatgen/io/phonopy.py | 7 +- pymatgen/io/pwscf.py | 12 +- pymatgen/io/shengbte.py | 2 +- pymatgen/io/vasp/help.py | 2 +- pymatgen/io/vasp/inputs.py | 3 +- pymatgen/phonon/bandstructure.py | 2 +- pymatgen/phonon/gruneisen.py | 25 ++-- pymatgen/symmetry/settings.py | 4 +- pymatgen/symmetry/structure.py | 6 +- .../advanced_transformations.py | 126 ++--------------- .../transformations/site_transformations.py | 52 ------- .../standard_transformations.py | 129 +----------------- .../transformations/transformation_abc.py | 14 +- pymatgen/util/provenance.py | 6 +- tests/core/test_interface.py | 13 +- .../test_advanced_transformations.py | 3 +- 60 files changed, 279 insertions(+), 573 deletions(-) diff --git a/dev_scripts/potcar_scrambler.py b/dev_scripts/potcar_scrambler.py index f0a81da5f7c..fd93d3bd0b0 100644 --- a/dev_scripts/potcar_scrambler.py +++ b/dev_scripts/potcar_scrambler.py @@ -47,7 +47,7 @@ def __init__(self, potcars: Potcar | PotcarSingle) -> None: def _rand_float_from_str_with_prec(self, input_str: str, bloat: float = 1.5) -> float: n_prec = len(input_str.split(".")[1]) - bd = max(1, bloat * abs(float(input_str))) + bd = max(1, bloat * abs(float(input_str))) # ensure we don't get 0 return round(bd * np.random.rand(1)[0], n_prec) def _read_fortran_str_and_scramble(self, input_str: str, bloat: float = 1.5): diff --git a/dev_scripts/update_pt_data.py b/dev_scripts/update_pt_data.py index 58bdc301f99..5e5e7fe3831 100644 --- a/dev_scripts/update_pt_data.py +++ b/dev_scripts/update_pt_data.py @@ -1,7 +1,5 @@ -""" -Developer script to convert yaml periodic table to json format. -Created on Nov 15, 2011. -""" +"""Developer script to convert YAML periodic table to JSON format. +Created on 2011-11-15.""" from __future__ import annotations diff --git a/pymatgen/alchemy/filters.py b/pymatgen/alchemy/filters.py index fef3ed6bae9..a09af2bf192 100644 --- a/pymatgen/alchemy/filters.py +++ b/pymatgen/alchemy/filters.py @@ -95,7 +95,7 @@ def __repr__(self): ) def as_dict(self) -> dict: - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, @@ -159,7 +159,7 @@ def test(self, structure: Structure): return True def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, @@ -280,7 +280,7 @@ def get_sg(s): return True def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, diff --git a/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py b/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py index e1e1701b1f5..ba29aa5e0fe 100644 --- a/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py +++ b/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py @@ -682,16 +682,16 @@ def pauling_stability_ratio(self): return self._pauling_stability_ratio @property - def mp_symbol(self): + def mp_symbol(self) -> str: """Returns the MP symbol of this coordination geometry.""" return self._mp_symbol @property - def ce_symbol(self): - """Returns the symbol of this coordination geometry.""" + def ce_symbol(self) -> str: + """Returns the symbol of this coordination geometry. Same as the MP symbol.""" return self._mp_symbol - def get_coordination_number(self): + def get_coordination_number(self) -> int: """Returns the coordination number of this coordination geometry.""" return self.coordination @@ -699,22 +699,22 @@ def is_implemented(self) -> bool: """Returns True if this coordination geometry is implemented.""" return bool(self.points) - def get_name(self): + def get_name(self) -> str: """Returns the name of this coordination geometry.""" return self.name @property - def IUPAC_symbol(self): + def IUPAC_symbol(self) -> str: """Returns the IUPAC symbol of this coordination geometry.""" return self.IUPACsymbol @property - def IUPAC_symbol_str(self): + def IUPAC_symbol_str(self) -> str: """Returns a string representation of the IUPAC symbol of this coordination geometry.""" return str(self.IUPACsymbol) @property - def IUCr_symbol(self): + def IUCr_symbol(self) -> str: """Returns the IUCr symbol of this coordination geometry.""" return self.IUCrsymbol @@ -848,7 +848,7 @@ def __init__(self, permutations_safe_override=False, only_symbols=None): only_symbols: Whether to restrict the list of environments to be identified. """ dict.__init__(self) - self.cg_list = [] + self.cg_list: list[CoordinationGeometry] = [] if only_symbols is None: with open(f"{module_dir}/coordination_geometries_files/allcg.txt") as file: data = file.readlines() @@ -943,18 +943,18 @@ def get_geometries(self, coordination=None, returned="cg"): """ geom = [] if coordination is None: - for gg in self.cg_list: + for coord_geom in self.cg_list: if returned == "cg": - geom.append(gg) + geom.append(coord_geom) elif returned == "mp_symbol": - geom.append(gg.mp_symbol) + geom.append(coord_geom.mp_symbol) else: - for gg in self.cg_list: - if gg.get_coordination_number() == coordination: + for coord_geom in self.cg_list: + if coord_geom.get_coordination_number() == coordination: if returned == "cg": - geom.append(gg) + geom.append(coord_geom) elif returned == "mp_symbol": - geom.append(gg.mp_symbol) + geom.append(coord_geom.mp_symbol) return geom def get_symbol_name_mapping(self, coordination=None): @@ -969,12 +969,12 @@ def get_symbol_name_mapping(self, coordination=None): """ geom = {} if coordination is None: - for gg in self.cg_list: - geom[gg.mp_symbol] = gg.name + for coord_geom in self.cg_list: + geom[coord_geom.mp_symbol] = coord_geom.name else: - for gg in self.cg_list: - if gg.get_coordination_number() == coordination: - geom[gg.mp_symbol] = gg.name + for coord_geom in self.cg_list: + if coord_geom.get_coordination_number() == coordination: + geom[coord_geom.mp_symbol] = coord_geom.name return geom def get_symbol_cn_mapping(self, coordination=None): @@ -989,12 +989,12 @@ def get_symbol_cn_mapping(self, coordination=None): """ geom = {} if coordination is None: - for gg in self.cg_list: - geom[gg.mp_symbol] = gg.coordination_number + for coord_geom in self.cg_list: + geom[coord_geom.mp_symbol] = coord_geom.coordination_number else: - for gg in self.cg_list: - if gg.get_coordination_number() == coordination: - geom[gg.mp_symbol] = gg.coordination_number + for coord_geom in self.cg_list: + if coord_geom.get_coordination_number() == coordination: + geom[coord_geom.mp_symbol] = coord_geom.coordination_number return geom def get_implemented_geometries(self, coordination=None, returned="cg", include_deactivated=False): @@ -1008,23 +1008,23 @@ def get_implemented_geometries(self, coordination=None, returned="cg", include_d """ geom = [] if coordination is None: - for gg in self.cg_list: - if gg.points is not None and ((not gg.deactivate) or include_deactivated): + for coord_geom in self.cg_list: + if coord_geom.points is not None and ((not coord_geom.deactivate) or include_deactivated): if returned == "cg": - geom.append(gg) + geom.append(coord_geom) elif returned == "mp_symbol": - geom.append(gg.mp_symbol) + geom.append(coord_geom.mp_symbol) else: - for gg in self.cg_list: + for coord_geom in self.cg_list: if ( - gg.get_coordination_number() == coordination - and gg.points is not None - and ((not gg.deactivate) or include_deactivated) + coord_geom.get_coordination_number() == coordination + and coord_geom.points is not None + and ((not coord_geom.deactivate) or include_deactivated) ): if returned == "cg": - geom.append(gg) + geom.append(coord_geom) elif returned == "mp_symbol": - geom.append(gg.mp_symbol) + geom.append(coord_geom.mp_symbol) return geom def get_not_implemented_geometries(self, coordination=None, returned="mp_symbol"): @@ -1037,63 +1037,63 @@ def get_not_implemented_geometries(self, coordination=None, returned="mp_symbol" """ geom = [] if coordination is None: - for gg in self.cg_list: - if gg.points is None: + for coord_geom in self.cg_list: + if coord_geom.points is None: if returned == "cg": - geom.append(gg) + geom.append(coord_geom) elif returned == "mp_symbol": - geom.append(gg.mp_symbol) + geom.append(coord_geom.mp_symbol) else: - for gg in self.cg_list: - if gg.get_coordination_number() == coordination and gg.points is None: + for coord_geom in self.cg_list: + if coord_geom.get_coordination_number() == coordination and coord_geom.points is None: if returned == "cg": - geom.append(gg) + geom.append(coord_geom) elif returned == "mp_symbol": - geom.append(gg.mp_symbol) + geom.append(coord_geom.mp_symbol) return geom - def get_geometry_from_name(self, name): + def get_geometry_from_name(self, name: str) -> CoordinationGeometry: """Get the coordination geometry of the given name. Args: name: The name of the coordination geometry. """ - for gg in self.cg_list: - if gg.name == name or name in gg.alternative_names: - return gg + for coord_geom in self.cg_list: + if coord_geom.name == name or name in coord_geom.alternative_names: + return coord_geom raise LookupError(f"No coordination geometry found with name {name!r}") - def get_geometry_from_IUPAC_symbol(self, IUPAC_symbol): + def get_geometry_from_IUPAC_symbol(self, IUPAC_symbol: str) -> CoordinationGeometry: """Get the coordination geometry of the given IUPAC symbol. Args: IUPAC_symbol: The IUPAC symbol of the coordination geometry. """ - for gg in self.cg_list: - if gg.IUPAC_symbol == IUPAC_symbol: - return gg + for coord_geom in self.cg_list: + if coord_geom.IUPAC_symbol == IUPAC_symbol: + return coord_geom raise LookupError(f"No coordination geometry found with IUPAC symbol {IUPAC_symbol!r}") - def get_geometry_from_IUCr_symbol(self, IUCr_symbol): + def get_geometry_from_IUCr_symbol(self, IUCr_symbol: str) -> CoordinationGeometry: """Get the coordination geometry of the given IUCr symbol. Args: IUCr_symbol: The IUCr symbol of the coordination geometry. """ - for gg in self.cg_list: - if gg.IUCr_symbol == IUCr_symbol: - return gg + for coord_geom in self.cg_list: + if coord_geom.IUCr_symbol == IUCr_symbol: + return coord_geom raise LookupError(f"No coordination geometry found with IUCr symbol {IUCr_symbol!r}") - def get_geometry_from_mp_symbol(self, mp_symbol): + def get_geometry_from_mp_symbol(self, mp_symbol: str) -> CoordinationGeometry: """Get the coordination geometry of the given mp_symbol. Args: mp_symbol: The mp_symbol of the coordination geometry. """ - for gg in self.cg_list: - if gg.mp_symbol == mp_symbol: - return gg + for coord_geom in self.cg_list: + if coord_geom.mp_symbol == mp_symbol: + return coord_geom raise LookupError(f"No coordination geometry found with mp_symbol {mp_symbol!r}") def is_a_valid_coordination_geometry( diff --git a/pymatgen/analysis/chempot_diagram.py b/pymatgen/analysis/chempot_diagram.py index 68bba6a76ae..0a690370ee5 100644 --- a/pymatgen/analysis/chempot_diagram.py +++ b/pymatgen/analysis/chempot_diagram.py @@ -397,7 +397,7 @@ def _get_new_limits_from_padding( elem_indices: list[int], element_padding: float, default_min_limit: float, - ): + ) -> list[float]: """Get new minimum limits for each element by subtracting specified padding from the minimum for each axis found in any of the domains. """ diff --git a/pymatgen/analysis/elasticity/elastic.py b/pymatgen/analysis/elasticity/elastic.py index 4d86f57d40a..47ef5105b9f 100644 --- a/pymatgen/analysis/elasticity/elastic.py +++ b/pymatgen/analysis/elasticity/elastic.py @@ -742,15 +742,14 @@ def get_compliance_expansion(self): ce_exp.append(temp) return TensorCollection(ce_exp) - def get_strain_from_stress(self, stress): - """Get the strain from a stress state according - to the compliance expansion corresponding to the - tensor expansion. + def get_strain_from_stress(self, stress) -> float: + """Get the strain from a stress state according to the compliance + expansion corresponding to the tensor expansion. """ compl_exp = self.get_compliance_expansion() strain = 0 - for n, compl in enumerate(compl_exp, start=1): - strain += compl.einsum_sequence([stress] * (n)) / factorial(n) + for idx, compl in enumerate(compl_exp, start=1): + strain += compl.einsum_sequence([stress] * (idx)) / factorial(idx) return strain def get_effective_ecs(self, strain, order=2): diff --git a/pymatgen/analysis/ewald.py b/pymatgen/analysis/ewald.py index a0e2c9d9da6..5ff0d13f2ff 100644 --- a/pymatgen/analysis/ewald.py +++ b/pymatgen/analysis/ewald.py @@ -401,7 +401,7 @@ def _calc_real_and_point(self): @property def eta(self): - """Returns: eta value used in Ewald summation.""" + """Eta value used in Ewald summation.""" return self._eta def __str__(self): @@ -694,17 +694,17 @@ def _recurse(self, matrix, m_list, indices, output_m_list=None): @property def best_m_list(self): - """Returns: Best m_list found.""" + """The best manipulation list found.""" return self._best_m_list @property def minimized_sum(self): - """Returns: Minimized sum.""" + """The minimized Ewald sum.""" return self._minimized_sum @property def output_lists(self): - """Returns: output lists.""" + """Output lists.""" return self._output_lists diff --git a/pymatgen/analysis/ferroelectricity/polarization.py b/pymatgen/analysis/ferroelectricity/polarization.py index 2942e2b0b05..36fb5cb6717 100644 --- a/pymatgen/analysis/ferroelectricity/polarization.py +++ b/pymatgen/analysis/ferroelectricity/polarization.py @@ -69,7 +69,7 @@ __date__ = "April 15, 2017" -def zval_dict_from_potcar(potcar): +def zval_dict_from_potcar(potcar) -> dict[str, float]: """ Creates zval_dictionary for calculating the ionic polarization from Potcar object. diff --git a/pymatgen/analysis/molecule_structure_comparator.py b/pymatgen/analysis/molecule_structure_comparator.py index c77bb2babc5..eb1917bb7b7 100644 --- a/pymatgen/analysis/molecule_structure_comparator.py +++ b/pymatgen/analysis/molecule_structure_comparator.py @@ -254,7 +254,7 @@ def _get_bonds(self, mol): return [bond for bond, dist, cap in zip(all_pairs, pair_dists, max_length) if dist <= cap] def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "version": __version__, "@module": type(self).__module__, diff --git a/pymatgen/analysis/nmr.py b/pymatgen/analysis/nmr.py index a98515e57a2..945541a536c 100644 --- a/pymatgen/analysis/nmr.py +++ b/pymatgen/analysis/nmr.py @@ -72,7 +72,7 @@ def principal_axis_system(self): @property def haeberlen_values(self): - """Returns: the Chemical shielding tensor in Haeberlen Notation.""" + """The Chemical shielding tensor in Haeberlen Notation.""" pas = self.principal_axis_system sigma_iso = pas.trace() / 3 sigmas = np.diag(pas) @@ -85,7 +85,7 @@ def haeberlen_values(self): @property def mehring_values(self): - """Returns: the Chemical shielding tensor in Mehring Notation.""" + """The Chemical shielding tensor in Mehring Notation.""" pas = self.principal_axis_system sigma_iso = pas.trace() / 3 sigma_11, sigma_22, sigma_33 = np.diag(pas) @@ -93,7 +93,7 @@ def mehring_values(self): @property def maryland_values(self): - """Returns: the Chemical shielding tensor in Maryland Notation.""" + """The Chemical shielding tensor in Maryland Notation.""" pas = self.principal_axis_system sigma_iso = pas.trace() / 3 omega = np.diag(pas)[2] - np.diag(pas)[0] @@ -161,19 +161,19 @@ def principal_axis_system(self): @property def V_xx(self): - """Returns: First diagonal element.""" + """First diagonal element.""" diags = np.diag(self.principal_axis_system) return min(diags, key=np.abs) @property def V_yy(self): - """Returns: Second diagonal element.""" + """Second diagonal element.""" diags = np.diag(self.principal_axis_system) return sorted(diags, key=np.abs)[1] @property def V_zz(self): - """Returns: Third diagonal element.""" + """Third diagonal element.""" diags = np.diag(self.principal_axis_system) return sorted(diags, key=np.abs)[2] diff --git a/pymatgen/analysis/pourbaix_diagram.py b/pymatgen/analysis/pourbaix_diagram.py index f6f0c8928a3..79e71c2e7da 100644 --- a/pymatgen/analysis/pourbaix_diagram.py +++ b/pymatgen/analysis/pourbaix_diagram.py @@ -297,7 +297,7 @@ def __repr__(self): return f"Pourbaix{cls_name}({energy=:.4f}, {npH=}, {nPhi=}, {nH2O=}, {entry_id=}, {species=})" def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, diff --git a/pymatgen/analysis/structure_matcher.py b/pymatgen/analysis/structure_matcher.py index 8b3b6609d67..01d287a7543 100644 --- a/pymatgen/analysis/structure_matcher.py +++ b/pymatgen/analysis/structure_matcher.py @@ -126,7 +126,7 @@ def are_equal(self, sp1, sp2) -> bool: return sp1 == sp2 def get_hash(self, composition: Composition): - """Returns: Fractional composition.""" + """Get the fractional composition.""" return composition.fractional_composition @@ -165,7 +165,7 @@ def are_equal(self, sp1, sp2) -> bool: return True def get_hash(self, composition): - """Returns: Fractional composition.""" + """Get the fractional composition.""" return composition.fractional_composition @@ -195,7 +195,7 @@ def are_equal(self, sp1, sp2) -> bool: return comp1.get_el_amt_dict() == comp2.get_el_amt_dict() def get_hash(self, composition): - """Returns: Fractional element composition.""" + """Get the fractional element composition.""" return composition.element_composition.fractional_composition @@ -245,7 +245,7 @@ def are_equal(self, sp1, sp2) -> bool: return set1.issubset(set2) or set2.issubset(set1) def get_hash(self, composition): - """Returns: Fractional composition.""" + """Get the fractional composition.""" return composition.fractional_composition diff --git a/pymatgen/analysis/structure_prediction/dopant_predictor.py b/pymatgen/analysis/structure_prediction/dopant_predictor.py index bb7b306d3e4..7ddcc006fb7 100644 --- a/pymatgen/analysis/structure_prediction/dopant_predictor.py +++ b/pymatgen/analysis/structure_prediction/dopant_predictor.py @@ -10,7 +10,9 @@ from pymatgen.core import Element, Species -def get_dopants_from_substitution_probabilities(structure, num_dopants=5, threshold=0.001, match_oxi_sign=False): +def get_dopants_from_substitution_probabilities( + structure, num_dopants=5, threshold=0.001, match_oxi_sign=False +) -> dict: """ Get dopant suggestions based on substitution probabilities. @@ -123,7 +125,7 @@ def get_dopants_from_shannon_radii(bonded_structure, num_dopants=5, match_oxi_si return _get_dopants(possible_dopants, num_dopants, match_oxi_sign) -def _get_dopants(substitutions, num_dopants, match_oxi_sign): +def _get_dopants(substitutions, num_dopants, match_oxi_sign) -> dict: """Utility method to get n- and p-type dopants from a list of substitutions.""" n_type = [ pred diff --git a/pymatgen/analysis/structure_prediction/substitution_probability.py b/pymatgen/analysis/structure_prediction/substitution_probability.py index 5ae92fe2279..7c893191484 100644 --- a/pymatgen/analysis/structure_prediction/substitution_probability.py +++ b/pymatgen/analysis/structure_prediction/substitution_probability.py @@ -160,7 +160,7 @@ def cond_prob_list(self, l1, l2): return p def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "name": type(self).__name__, "version": __version__, diff --git a/pymatgen/analysis/structure_prediction/substitutor.py b/pymatgen/analysis/structure_prediction/substitutor.py index 45f847d1a0b..ca403a6e0c8 100644 --- a/pymatgen/analysis/structure_prediction/substitutor.py +++ b/pymatgen/analysis/structure_prediction/substitutor.py @@ -76,7 +76,7 @@ def pred_from_structures( structures_list, remove_duplicates=True, remove_existing=False, - ): + ) -> list[TransformedStructure]: """ Performs a structure prediction targeting compounds containing all of the target_species, based on a list of structure (those structures @@ -168,11 +168,11 @@ def _is_charge_balanced(struct) -> bool: return abs(sum(site.specie.oxi_state for site in struct)) < Substitutor.charge_balanced_tol @staticmethod - def _is_from_chemical_system(chemical_system, struct): + def _is_from_chemical_system(chemical_system, struct) -> bool: """Check if the structure object is from the given chemical system.""" return {sp.symbol for sp in struct.composition} == set(chemical_system) - def pred_from_list(self, species_list): + def pred_from_list(self, species_list) -> list[dict]: """ There are an exceptionally large number of substitutions to look at (260^n), where n is the number of species in the @@ -225,25 +225,25 @@ def _recurse(output_prob, output_species): logging.info(f"{len(output)} substitutions found") return output - def pred_from_comp(self, composition): + def pred_from_comp(self, composition) -> list[dict]: """Similar to pred_from_list except this method returns a list after checking that compositions are charge balanced. """ output = [] predictions = self.pred_from_list(composition.elements) - for p in predictions: - subs = p["substitutions"] + for pred in predictions: + subs = pred["substitutions"] charge = 0 for i_el in composition.elements: f_el = subs[i_el] charge += f_el.oxi_state * composition[i_el] if charge == 0: - output.append(p) + output.append(pred) logging.info(f"{len(output)} charge balanced compositions found") return output def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "name": type(self).__name__, "version": __version__, diff --git a/pymatgen/analysis/surface_analysis.py b/pymatgen/analysis/surface_analysis.py index 6a06ec83572..56228fcf7c6 100644 --- a/pymatgen/analysis/surface_analysis.py +++ b/pymatgen/analysis/surface_analysis.py @@ -494,7 +494,7 @@ def wulff_from_chempot( symprec=1e-5, no_clean=False, no_doped=False, - ): + ) -> WulffShape: """ Method to get the Wulff shape at a specific chemical potential. @@ -1290,7 +1290,7 @@ def set_all_variables(self, delu_dict, delu_default): return all_delu_dict -def entry_dict_from_list(all_slab_entries): +def entry_dict_from_list(all_slab_entries) -> dict: """ Converts a list of SlabEntry to an appropriate dictionary. It is assumed that if there is no adsorbate, then it is a clean SlabEntry @@ -1304,7 +1304,7 @@ def entry_dict_from_list(all_slab_entries): key to a dictionary with a clean SlabEntry as the key to a list of adsorbed SlabEntry. """ - entry_dict = {} + entry_dict: dict[tuple, dict] = {} for entry in all_slab_entries: hkl = tuple(entry.miller_index) diff --git a/pymatgen/analysis/thermochemistry.py b/pymatgen/analysis/thermochemistry.py index a5d4acdea6a..3c6f59486ae 100644 --- a/pymatgen/analysis/thermochemistry.py +++ b/pymatgen/analysis/thermochemistry.py @@ -89,7 +89,7 @@ def from_dict(cls, dct: dict) -> Self: ) def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, diff --git a/pymatgen/apps/battery/battery_abc.py b/pymatgen/apps/battery/battery_abc.py index b6d3df592fb..fb9eb7a3666 100644 --- a/pymatgen/apps/battery/battery_abc.py +++ b/pymatgen/apps/battery/battery_abc.py @@ -202,14 +202,14 @@ def max_voltage_step(self): @property def normalization_mass(self): - """Returns: Mass used for normalization. This is the mass of the discharged + """The mass used for normalization. This is the mass of the discharged electrode of the last voltage pair. """ return self.voltage_pairs[-1].mass_discharge @property def normalization_volume(self): - """Returns: Mass used for normalization. This is the vol of the discharged + """The mass used for normalization. This is the vol of the discharged electrode of the last voltage pair. """ return self.voltage_pairs[-1].vol_discharge diff --git a/pymatgen/apps/battery/insertion_battery.py b/pymatgen/apps/battery/insertion_battery.py index da13336e85a..887e5b03c60 100644 --- a/pymatgen/apps/battery/insertion_battery.py +++ b/pymatgen/apps/battery/insertion_battery.py @@ -372,7 +372,7 @@ def from_dict_legacy(cls, dct) -> Self: ) def as_dict_legacy(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, diff --git a/pymatgen/apps/borg/hive.py b/pymatgen/apps/borg/hive.py index 6129951fc95..a90380d0dee 100644 --- a/pymatgen/apps/borg/hive.py +++ b/pymatgen/apps/borg/hive.py @@ -166,7 +166,7 @@ def __str__(self): return " VaspToComputedEntryDrone" def as_dict(self): - """Returns: MSONABle dict.""" + """Get MSONable dict.""" return { "init_args": { "inc_structure": self._inc_structure, @@ -278,7 +278,7 @@ def __str__(self): return "SimpleVaspToComputedEntryDrone" def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "init_args": {"inc_structure": self._inc_structure}, "@module": type(self).__module__, @@ -392,7 +392,7 @@ def __str__(self): return " GaussianToComputedEntryDrone" def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "init_args": { "inc_structure": self._inc_structure, diff --git a/pymatgen/command_line/bader_caller.py b/pymatgen/command_line/bader_caller.py index ec0202421a4..2e4cf2afcd9 100644 --- a/pymatgen/command_line/bader_caller.py +++ b/pymatgen/command_line/bader_caller.py @@ -497,7 +497,7 @@ def _get_filepath(filename): ) -def bader_analysis_from_path(path: str, suffix: str = ""): +def bader_analysis_from_path(path: str, suffix: str = "") -> dict[str, Any]: """Convenience method to run Bader analysis on a folder containing typical VASP output files. @@ -560,7 +560,7 @@ def bader_analysis_from_objects( potcar: Potcar | None = None, aeccar0: Chgcar | None = None, aeccar2: Chgcar | None = None, -): +) -> dict[str, Any]: """Convenience method to run Bader analysis from a set of pymatgen Chgcar and Potcar objects. diff --git a/pymatgen/command_line/chargemol_caller.py b/pymatgen/command_line/chargemol_caller.py index b997bdbd227..6ee292859b6 100644 --- a/pymatgen/command_line/chargemol_caller.py +++ b/pymatgen/command_line/chargemol_caller.py @@ -532,7 +532,7 @@ def summary(self): return summary @staticmethod - def _get_data_from_xyz(xyz_path): + def _get_data_from_xyz(xyz_path) -> list[float]: """Internal command to process Chargemol XYZ files. Args: @@ -556,7 +556,7 @@ def _get_data_from_xyz(xyz_path): return props @staticmethod - def _get_cm5_data_from_output(ddec_analysis_path): + def _get_cm5_data_from_output(ddec_analysis_path) -> list[float]: """Internal command to process Chargemol CM5 data. Args: diff --git a/pymatgen/command_line/critic2_caller.py b/pymatgen/command_line/critic2_caller.py index e9451015ba3..21808ebe98d 100644 --- a/pymatgen/command_line/critic2_caller.py +++ b/pymatgen/command_line/critic2_caller.py @@ -388,8 +388,8 @@ def __init__( self.field_hessian = field_hessian @property - def type(self): - """Returns: Instance of CriticalPointType.""" + def type(self) -> CriticalPointType: + """Instance of CriticalPointType.""" return CriticalPointType(self._type) def __str__(self): @@ -397,7 +397,7 @@ def __str__(self): @property def laplacian(self) -> float: - """Returns: The Laplacian of the field at the critical point.""" + """The Laplacian of the field at the critical point.""" return np.trace(self.field_hessian) @property diff --git a/pymatgen/core/interface.py b/pymatgen/core/interface.py index e86fb4b5bf6..4cf4e231cd4 100644 --- a/pymatgen/core/interface.py +++ b/pymatgen/core/interface.py @@ -138,15 +138,8 @@ def __init__( properties=properties, ) - def copy(self): - """ - Convenience method to get a copy of the structure, with options to add - site properties. - - Returns: - A copy of the Structure, with optionally new site_properties and - optionally sanitized. - """ + def copy(self) -> Self: # type: ignore[override] + """Make a copy of the GrainBoundary object.""" return GrainBoundary( self.lattice, self.species_and_occu, @@ -398,7 +391,7 @@ def gb_from_parameters( tol_coi=1.0e-8, rm_ratio=0.7, quick_gen=False, - ): + ) -> GrainBoundary: """ Args: rotation_axis (list): Rotation axis of GB in the form of a list of integer @@ -2486,11 +2479,8 @@ def film(self) -> Structure: """A pymatgen Structure for just the film.""" return Structure.from_sites(self.film_sites) - def copy(self): - """ - Returns: - Interface: A copy of the Interface. - """ + def copy(self) -> Self: # type: ignore[override] + """Make a copy of the Interface.""" return Interface.from_dict(self.as_dict()) def get_sorted_structure(self, key=None, reverse=False) -> Structure: diff --git a/pymatgen/core/lattice.py b/pymatgen/core/lattice.py index d160076f442..6b6df2487ce 100644 --- a/pymatgen/core/lattice.py +++ b/pymatgen/core/lattice.py @@ -131,8 +131,8 @@ def __format__(self, fmt_spec: str = "") -> str: fmt = "{} {} {}\n{} {} {}\n{} {} {}" return fmt.format(*(format(c, fmt_spec) for row in matrix for c in row)) - def copy(self): - """Deep copy of self.""" + def copy(self) -> Self: + """Make a copy of this lattice.""" return type(self)(self.matrix.copy(), pbc=self.pbc) @property diff --git a/pymatgen/core/operations.py b/pymatgen/core/operations.py index aaacfaeeae5..3e3de6eebb5 100644 --- a/pymatgen/core/operations.py +++ b/pymatgen/core/operations.py @@ -233,10 +233,10 @@ def __mul__(self, other): return SymmOp(new_matrix) @property - def inverse(self) -> SymmOp: + def inverse(self) -> Self: """Returns inverse of transformation.""" inverse = np.linalg.inv(self.affine_matrix) - return SymmOp(inverse) + return type(self)(inverse) @staticmethod def from_axis_angle_and_translation( diff --git a/pymatgen/core/spectrum.py b/pymatgen/core/spectrum.py index 7b28553caeb..5fb46f5a18e 100644 --- a/pymatgen/core/spectrum.py +++ b/pymatgen/core/spectrum.py @@ -15,6 +15,7 @@ if TYPE_CHECKING: from numpy.typing import ArrayLike + from typing_extensions import Self def lorentzian(x, x_0: float = 0, sigma: float = 1.0): @@ -133,7 +134,7 @@ def get_interpolated_value(self, x: float) -> float | list[float]: return get_linear_interpolated_value(self.x, self.y, x) return [get_linear_interpolated_value(self.x, self.y[:, k], x) for k in range(self.ydim[1])] - def copy(self): + def copy(self) -> Self: """ Returns: Copy of Spectrum object. diff --git a/pymatgen/core/structure.py b/pymatgen/core/structure.py index ad783a9144c..995a8e5f86b 100644 --- a/pymatgen/core/structure.py +++ b/pymatgen/core/structure.py @@ -219,7 +219,7 @@ def sites(self, sites: Sequence[PeriodicSite]) -> None: self._sites = list(sites) if is_mutable else tuple(sites) @abstractmethod - def copy(self) -> SiteCollection: + def copy(self) -> Self: """Returns a copy of itself. Concrete subclasses should implement this method. """ @@ -2169,7 +2169,7 @@ def copy( site_properties: dict[str, Any] | None = None, sanitize: bool = False, properties: dict[str, Any] | None = None, - ) -> Structure: + ) -> Self: """Convenience method to get a copy of the structure, with options to add site properties. @@ -2208,25 +2208,23 @@ def copy( properties=props, ) reduced_latt = self._lattice.get_lll_reduced_lattice() - new_sites = [] + new_sites: list[PeriodicSite] = [] for idx, site in enumerate(self): frac_coords = reduced_latt.get_fractional_coords(site.coords) site_props = {} for prop, val in new_site_props.items(): site_props[prop] = val[idx] - new_sites.append( - PeriodicSite( - site.species, - frac_coords, - reduced_latt, - to_unit_cell=True, - properties=site_props, - label=site.label, - skip_checks=True, - ) + new_site = PeriodicSite( + site.species, + frac_coords, + reduced_latt, + to_unit_cell=True, + properties=site_props, + label=site.label, + skip_checks=True, ) - new_sites = sorted(new_sites) - return type(self).from_sites(new_sites, charge=self._charge, properties=props) + new_sites.append(new_site) + return type(self).from_sites(sorted(new_sites), charge=self._charge, properties=props) def interpolate( self, @@ -3187,7 +3185,7 @@ def center_of_mass(self) -> np.ndarray: total_weight += wt return center / total_weight - def copy(self) -> IMolecule | Molecule: + def copy(self) -> Self: """Convenience method to get a copy of the molecule. Returns: diff --git a/pymatgen/core/surface.py b/pymatgen/core/surface.py index 831b809f5ea..9f9d7bdf6da 100644 --- a/pymatgen/core/surface.py +++ b/pymatgen/core/surface.py @@ -252,8 +252,8 @@ def as_dict(self, **kwargs) -> dict: # type: ignore[override] dct["energy"] = self.energy return dct - def copy(self, site_properties: dict[str, Any] | None = None) -> Slab: # type: ignore[override] - """Get a copy of the structure, with options to update site properties. + def copy(self, site_properties: dict[str, Any] | None = None) -> Self: # type: ignore[override] + """Get a copy of the Slab, with options to update site properties. Args: site_properties (dict): Properties to update. The diff --git a/pymatgen/electronic_structure/boltztrap.py b/pymatgen/electronic_structure/boltztrap.py index cdf9700b183..a669298d64f 100644 --- a/pymatgen/electronic_structure/boltztrap.py +++ b/pymatgen/electronic_structure/boltztrap.py @@ -2277,7 +2277,7 @@ def seebeck_spb(eta, Lambda=0.5): ) -def eta_from_seebeck(seeb, Lambda): +def eta_from_seebeck(seeb, Lambda) -> float: """It takes a value of seebeck and adjusts the analytic seebeck until it's equal. Returns: @@ -2287,7 +2287,7 @@ def eta_from_seebeck(seeb, Lambda): return out[0][0] -def seebeck_eff_mass_from_carr(eta, n, T, Lambda): +def seebeck_eff_mass_from_carr(eta, n, T, Lambda) -> float: """Calculate seebeck effective mass at a certain carrier concentration eta in kB*T units, n in cm-3, T in K, returns mass in m0 units. """ @@ -2303,7 +2303,7 @@ def seebeck_eff_mass_from_carr(eta, n, T, Lambda): ) -def seebeck_eff_mass_from_seebeck_carr(seeb, n, T, Lambda): +def seebeck_eff_mass_from_seebeck_carr(seeb, n, T, Lambda) -> float: """Find the chemical potential where analytic and calculated seebeck are identical and then calculate the seebeck effective mass at that chemical potential and a certain carrier concentration n. diff --git a/pymatgen/entries/correction_calculator.py b/pymatgen/entries/correction_calculator.py index 070a5f0ef37..153c71a4b59 100644 --- a/pymatgen/entries/correction_calculator.py +++ b/pymatgen/entries/correction_calculator.py @@ -81,7 +81,7 @@ def __init__( if "S" in self.species: self.sulfides: list[str] = [] - def compute_from_files(self, exp_gz: str, comp_gz: str): + def compute_from_files(self, exp_gz: str, comp_gz: str) -> dict: """ Args: exp_gz: name of .json.gz file that contains experimental data @@ -100,9 +100,11 @@ def compute_corrections(self, exp_entries: list, calc_entries: dict) -> dict: """Compute the corrections and fills in correction, corrections_std_error, and corrections_dict. Args: - exp_entries: list of dictionary objects with the following keys/values: - {"formula": chemical formula, "exp energy": formation energy in eV/formula unit, - "uncertainty": uncertainty in formation energy} + exp_entries: list of dictionary objects with the following keys/values: { + "formula": chemical formula, + "exp energy": formation energy in eV/formula unit, + "uncertainty": uncertainty in formation energy + } calc_entries: dictionary of computed entries, of the form {chemical formula: ComputedEntry} Raises: diff --git a/pymatgen/ext/matproj_legacy.py b/pymatgen/ext/matproj_legacy.py index 8df0ec2ca12..7816f6d2891 100644 --- a/pymatgen/ext/matproj_legacy.py +++ b/pymatgen/ext/matproj_legacy.py @@ -289,7 +289,7 @@ def get_database_version(self) -> str: dct = self._make_request("/api_check") return dct["version"]["db"] - def get_materials_id_from_task_id(self, task_id): + def get_materials_id_from_task_id(self, task_id) -> str: """Returns a new MP materials id from a task id (which can be equivalent to an old materials id). diff --git a/pymatgen/io/abinit/abiobjects.py b/pymatgen/io/abinit/abiobjects.py index 79c25c4f782..62f2386e567 100644 --- a/pymatgen/io/abinit/abiobjects.py +++ b/pymatgen/io/abinit/abiobjects.py @@ -914,7 +914,7 @@ def _path(cls, ndivsm, structure=None, kpath_bounds=None, comment=None): ) @classmethod - def path_from_structure(cls, ndivsm, structure): + def path_from_structure(cls, ndivsm, structure) -> Self: """See _path for the meaning of the variables.""" return cls._path( ndivsm, diff --git a/pymatgen/io/abinit/pseudos.py b/pymatgen/io/abinit/pseudos.py index c10a7d6463d..1c8e794a144 100644 --- a/pymatgen/io/abinit/pseudos.py +++ b/pymatgen/io/abinit/pseudos.py @@ -587,7 +587,7 @@ def from_dict(cls, dct: dict) -> Self: return cls(**{k: v for k, v in dct.items() if not k.startswith("@")}) -def _dict_from_lines(lines, key_nums, sep=None): +def _dict_from_lines(lines, key_nums, sep=None) -> dict: """ Helper function to parse formatted text structured like: @@ -620,10 +620,9 @@ def _dict_from_lines(lines, key_nums, sep=None): line = lines[idx] tokens = [tok.strip() for tok in line.split()] - values, keys = tokens[:nk], "".join(tokens[nk:]) + values = tokens[:nk] # Sanitize keys: In some case we might get strings in the form: foo[,bar] - keys.replace("[", "").replace("]", "") - keys = keys.split(",") + keys = "".join(tokens[nk:]).replace("[", "").replace("]", "").split(",") if sep is not None: check = keys[0][0] diff --git a/pymatgen/io/adf.py b/pymatgen/io/adf.py index 2677d34420d..5e35b5f62f7 100644 --- a/pymatgen/io/adf.py +++ b/pymatgen/io/adf.py @@ -428,27 +428,27 @@ def __init__( @staticmethod def get_default_basis_set(): - """Returns: Default basis set.""" + """Get Default basis set.""" return AdfKey.from_str("Basis\ntype DZ\ncore small\nEND") @staticmethod def get_default_scf(): - """Returns: ADF using default SCF.""" + """Get ADF using default SCF.""" return AdfKey.from_str("SCF\niterations 300\nEND") @staticmethod def get_default_geo(): - """Returns: ADFKey using default geometry.""" + """Get ADFKey using default geometry.""" return AdfKey.from_str("GEOMETRY SinglePoint\nEND") @staticmethod def get_default_xc(): - """Returns: ADFKey using default XC.""" + """Get ADFKey using default XC.""" return AdfKey.from_str("XC\nGGA PBE\nEND") @staticmethod def get_default_units(): - """Returns: Default units.""" + """Get Default units.""" return AdfKey.from_str("Units\nlength angstrom\nangle degree\nEnd") def _setup_task(self, geo_subkeys): diff --git a/pymatgen/io/cif.py b/pymatgen/io/cif.py index d518c7eba4d..46286de6576 100644 --- a/pymatgen/io/cif.py +++ b/pymatgen/io/cif.py @@ -1608,8 +1608,8 @@ def __init__( self._cf = CifFile(dct) @property - def cif_file(self): - """Returns: CifFile associated with the CifWriter.""" + def cif_file(self) -> CifFile: + """Get CifFile associated with the CifWriter.""" return self._cf def __str__(self): diff --git a/pymatgen/io/common.py b/pymatgen/io/common.py index 2b4c56ca107..0321b7c9be2 100644 --- a/pymatgen/io/common.py +++ b/pymatgen/io/common.py @@ -112,8 +112,8 @@ def __add__(self, other): def __sub__(self, other): return self.linear_add(other, -1.0) - def copy(self): - """Copy of Volumetric object""" + def copy(self) -> Self: + """Make a copy of VolumetricData object""" return VolumetricData( self.structure, {k: v.copy() for k, v in self.data.items()}, diff --git a/pymatgen/io/feff/inputs.py b/pymatgen/io/feff/inputs.py index ea6d2c87495..7f28c6249cf 100644 --- a/pymatgen/io/feff/inputs.py +++ b/pymatgen/io/feff/inputs.py @@ -243,14 +243,14 @@ def header_string_from_file(filename: str = "feff.inp"): Returns: Reads header string. """ - with zopen(filename, mode="r") as fobject: - f = fobject.readlines() + with zopen(filename, mode="r") as file: + lines = file.readlines() feff_header_str = [] ln = 0 # Checks to see if generated by pymatgen try: - feff_pmg = f[0].find("pymatgen") + feff_pmg = lines[0].find("pymatgen") if feff_pmg == -1: feff_pmg = False except IndexError: @@ -258,8 +258,8 @@ def header_string_from_file(filename: str = "feff.inp"): # Reads pymatgen generated header or feff.inp file if feff_pmg: - n_sites = int(f[8].split()[2]) - for line in f: + n_sites = int(lines[8].split()[2]) + for line in lines: ln += 1 if ln <= n_sites + 9: feff_header_str.append(line) @@ -267,7 +267,7 @@ def header_string_from_file(filename: str = "feff.inp"): # Reads header from header from feff.inp file from unknown # source end = 0 - for line in f: + for line in lines: if line[0] in {"*", "T"} and end == 0: feff_header_str.append(line.replace("\r", "")) else: diff --git a/pymatgen/io/feff/outputs.py b/pymatgen/io/feff/outputs.py index 2d8bb9eeba4..2ca4957888f 100644 --- a/pymatgen/io/feff/outputs.py +++ b/pymatgen/io/feff/outputs.py @@ -400,13 +400,13 @@ def total_spectrum(self): return self.data[:, 1] @property - def atomic_background(self): - """Returns: atomic background.""" + def atomic_background(self) -> np.ndarray: + """The atomic background of EELS.""" return self.data[:, 2] @property - def fine_structure(self): - """Returns: Fine structure of EELS.""" + def fine_structure(self) -> np.ndarray: + """The fine structure of EELS.""" return self.data[:, 3] @classmethod diff --git a/pymatgen/io/icet.py b/pymatgen/io/icet.py index 9404ad02ce8..159b75cdcc9 100644 --- a/pymatgen/io/icet.py +++ b/pymatgen/io/icet.py @@ -288,7 +288,7 @@ def enumerate_sqs_structures(self, cluster_space: _ClusterSpace | None = None) - return list(working_list) - def _get_best_sqs_from_list(self, structures: list[Atoms], output_list: list[dict]) -> None: + def _get_best_sqs_from_list(self, structures: list[Atoms], output_list: list[dict]) -> dict[str, Any]: """Find best SQS structure from list of SQS structures. Args: @@ -304,6 +304,8 @@ def _get_best_sqs_from_list(self, structures: list[Atoms], output_list: list[dic best_sqs = {"structure": structure, "objective_function": objective} output_list.append(best_sqs) + return best_sqs + def _single_monte_carlo_sqs_run(self): """Run a single Monte Carlo SQS search with Icet.""" cluster_space = self._get_cluster_space() diff --git a/pymatgen/io/lammps/outputs.py b/pymatgen/io/lammps/outputs.py index 7a2999ffafd..30757f6614d 100644 --- a/pymatgen/io/lammps/outputs.py +++ b/pymatgen/io/lammps/outputs.py @@ -87,7 +87,7 @@ def from_dict(cls, dct: dict) -> Self: return cls(**items) def as_dict(self) -> dict[str, Any]: - """Returns: MSONable dict.""" + """Get MSONable dict.""" dct: dict[str, Any] = {} dct["@module"] = type(self).__module__ dct["@class"] = type(self).__name__ diff --git a/pymatgen/io/lobster/outputs.py b/pymatgen/io/lobster/outputs.py index acc6ccf1390..502b3e87ffe 100644 --- a/pymatgen/io/lobster/outputs.py +++ b/pymatgen/io/lobster/outputs.py @@ -506,7 +506,7 @@ def __init__( @property def icohplist(self) -> dict[Any, dict[str, Any]]: - """Returns: icohplist compatible with older version of this class.""" + """The ICOHP list compatible with older version of this class.""" icohp_dict = {} for key, value in self._icohpcollection._icohplist.items(): icohp_dict[key] = { @@ -520,7 +520,7 @@ def icohplist(self) -> dict[Any, dict[str, Any]]: @property def icohpcollection(self): - """Returns: IcohpCollection object.""" + """The IcohpCollection object.""" return self._icohpcollection @@ -1004,44 +1004,44 @@ def __init__(self, filename: str | None, **kwargs) -> None: else: raise ValueError("must provide either filename or kwargs to initialize Lobsterout") - def get_doc(self): - """Returns: LobsterDict with all the information stored in lobsterout.""" - LobsterDict = {} + def get_doc(self) -> dict[str, Any]: + """Get the LobsterDict with all the information stored in lobsterout.""" + lobster_dict: dict[str, Any] = {} # check if Lobster starts from a projection - LobsterDict["restart_from_projection"] = self.is_restart_from_projection - LobsterDict["lobster_version"] = self.lobster_version - LobsterDict["threads"] = self.number_of_threads - LobsterDict["dft_program"] = self.dft_program + lobster_dict["restart_from_projection"] = self.is_restart_from_projection + lobster_dict["lobster_version"] = self.lobster_version + lobster_dict["threads"] = self.number_of_threads + lobster_dict["dft_program"] = self.dft_program - LobsterDict["charge_spilling"] = self.charge_spilling - LobsterDict["total_spilling"] = self.total_spilling + lobster_dict["charge_spilling"] = self.charge_spilling + lobster_dict["total_spilling"] = self.total_spilling - LobsterDict["elements"] = self.elements - LobsterDict["basis_type"] = self.basis_type - LobsterDict["basis_functions"] = self.basis_functions + lobster_dict["elements"] = self.elements + lobster_dict["basis_type"] = self.basis_type + lobster_dict["basis_functions"] = self.basis_functions - LobsterDict["timing"] = self.timing + lobster_dict["timing"] = self.timing - LobsterDict["warning_lines"] = self.warning_lines + lobster_dict["warning_lines"] = self.warning_lines - LobsterDict["info_orthonormalization"] = self.info_orthonormalization + lobster_dict["info_orthonormalization"] = self.info_orthonormalization - LobsterDict["info_lines"] = self.info_lines + lobster_dict["info_lines"] = self.info_lines - LobsterDict["has_doscar"] = self.has_doscar - LobsterDict["has_doscar_lso"] = self.has_doscar_lso - LobsterDict["has_cohpcar"] = self.has_cohpcar - LobsterDict["has_coopcar"] = self.has_coopcar - LobsterDict["has_cobicar"] = self.has_cobicar - LobsterDict["has_charge"] = self.has_charge - LobsterDict["has_madelung"] = self.has_madelung - LobsterDict["has_projection"] = self.has_projection - LobsterDict["has_bandoverlaps"] = self.has_bandoverlaps - LobsterDict["has_fatbands"] = self.has_fatbands - LobsterDict["has_grosspopulation"] = self.has_grosspopulation - LobsterDict["has_density_of_energies"] = self.has_density_of_energies + lobster_dict["has_doscar"] = self.has_doscar + lobster_dict["has_doscar_lso"] = self.has_doscar_lso + lobster_dict["has_cohpcar"] = self.has_cohpcar + lobster_dict["has_coopcar"] = self.has_coopcar + lobster_dict["has_cobicar"] = self.has_cobicar + lobster_dict["has_charge"] = self.has_charge + lobster_dict["has_madelung"] = self.has_madelung + lobster_dict["has_projection"] = self.has_projection + lobster_dict["has_bandoverlaps"] = self.has_bandoverlaps + lobster_dict["has_fatbands"] = self.has_fatbands + lobster_dict["has_grosspopulation"] = self.has_grosspopulation + lobster_dict["has_density_of_energies"] = self.has_density_of_energies - return LobsterDict + return lobster_dict def as_dict(self): """MSONable dict""" diff --git a/pymatgen/io/nwchem.py b/pymatgen/io/nwchem.py index 02fa6c8053d..6049a5274d4 100644 --- a/pymatgen/io/nwchem.py +++ b/pymatgen/io/nwchem.py @@ -187,7 +187,7 @@ def __str__(self): return output def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "@module": type(self).__module__, "@class": type(self).__name__, @@ -394,7 +394,7 @@ def write_file(self, filename): file.write(str(self)) def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return { "mol": self._mol.as_dict(), "tasks": [task.as_dict() for task in self.tasks], diff --git a/pymatgen/io/openff.py b/pymatgen/io/openff.py index e8c8fdee50e..1f4ed67c6d3 100644 --- a/pymatgen/io/openff.py +++ b/pymatgen/io/openff.py @@ -86,10 +86,7 @@ def mol_graph_from_openff_mol(molecule: tk.Molecule) -> MoleculeGraph: Returns: MoleculeGraph: The converted MoleculeGraph. """ - mol_graph = MoleculeGraph.with_empty_graph( - Molecule([], []), - name="none", - ) + mol_graph = MoleculeGraph.with_empty_graph(Molecule([], []), name="none") p_table = {el.Z: str(el) for el in Element} total_charge = 0 cum_atoms = 0 diff --git a/pymatgen/io/phonopy.py b/pymatgen/io/phonopy.py index bbada65c39c..f3e9ead6e8b 100644 --- a/pymatgen/io/phonopy.py +++ b/pymatgen/io/phonopy.py @@ -57,7 +57,7 @@ def get_phonopy_structure(pmg_structure: Structure) -> PhonopyAtoms: ) -def get_structure_from_dict(dct): +def get_structure_from_dict(dct) -> Structure: """Extracts a structure from the dictionary extracted from the output files of phonopy like phonopy.yaml or band.yaml. Adds "phonopy_masses" in the site_properties of the structures. @@ -103,7 +103,7 @@ def eigvec_to_eigdispl(eig_vec, q, frac_coords, mass): return c * eig_vec -def get_ph_bs_symm_line_from_dict(bands_dict, has_nac=False, labels_dict=None): +def get_ph_bs_symm_line_from_dict(bands_dict, has_nac=False, labels_dict=None) -> PhononBandStructureSymmLine: r""" Creates a pymatgen PhononBandStructure object from the dictionary extracted by the band.yaml file produced by phonopy. The labels @@ -121,6 +121,9 @@ def get_ph_bs_symm_line_from_dict(bands_dict, has_nac=False, labels_dict=None): --nac option. Default False. labels_dict: dict that links a qpoint in frac coords to a label. Its value will replace the data contained in the band.yaml. + + Returns: + PhononBandStructure: the phonon band structure """ structure = get_structure_from_dict(bands_dict) diff --git a/pymatgen/io/pwscf.py b/pymatgen/io/pwscf.py index 9c2a2401c2f..9b99fc51913 100644 --- a/pymatgen/io/pwscf.py +++ b/pymatgen/io/pwscf.py @@ -4,7 +4,7 @@ import re from collections import defaultdict -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from monty.io import zopen from monty.re import regrep @@ -520,7 +520,7 @@ def __init__(self, filename): filename (str): Filename. """ self.filename = filename - self.data: dict[str, list[float] | float] = defaultdict(list) + self.data: dict[str, Any] = defaultdict(list) self.read_pattern(PWOutput.patterns) for k, v in self.data.items(): if k == "energies": @@ -574,11 +574,11 @@ def get_celldm(self, idx: int): return self.data[f"celldm{idx}"] @property - def final_energy(self): - """Returns: Final energy.""" + def final_energy(self) -> float: + """The final energy from the PW output.""" return self.data["energies"][-1] @property - def lattice_type(self): - """Returns: Lattice type.""" + def lattice_type(self) -> int: + """The lattice type.""" return self.data["lattice_type"] diff --git a/pymatgen/io/shengbte.py b/pymatgen/io/shengbte.py index 1a795de4ec0..745c5f04665 100644 --- a/pymatgen/io/shengbte.py +++ b/pymatgen/io/shengbte.py @@ -261,7 +261,7 @@ def get_structure(self) -> Structure: return Structure(cell, species, self["positions"]) def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return dict(self) diff --git a/pymatgen/io/vasp/help.py b/pymatgen/io/vasp/help.py index 92c54913caf..3f7351ee07b 100644 --- a/pymatgen/io/vasp/help.py +++ b/pymatgen/io/vasp/help.py @@ -66,7 +66,7 @@ def get_help(cls, tag: str, fmt: str = "text") -> str: @classmethod def get_incar_tags(cls) -> list[str]: - """Returns: All incar tags.""" + """Get a list of all INCAR tags from the VASP wiki.""" tags = [] for page in [ "https://www.vasp.at/wiki/index.php/Category:INCAR", diff --git a/pymatgen/io/vasp/inputs.py b/pymatgen/io/vasp/inputs.py index 02d56292800..e109ba71f99 100644 --- a/pymatgen/io/vasp/inputs.py +++ b/pymatgen/io/vasp/inputs.py @@ -1483,7 +1483,8 @@ def automatic_linemode(cls, divisions: int, ibz: HighSymmKpath) -> Self: num_kpts=divisions, ) - def copy(self): + def copy(self) -> Self: + """Make a copy of the Kpoints object.""" return self.from_dict(self.as_dict()) @classmethod diff --git a/pymatgen/phonon/bandstructure.py b/pymatgen/phonon/bandstructure.py index d3bd4a9bf87..87f97f4f5b1 100644 --- a/pymatgen/phonon/bandstructure.py +++ b/pymatgen/phonon/bandstructure.py @@ -622,7 +622,7 @@ def band_reorder(self) -> None: eig[:, nq] = eigq[order[nq]] def as_dict(self) -> dict: - """Returns: MSONable dict.""" + """Get MSONable dict.""" dct = super().as_dict() # remove nac_frequencies and nac_eigendisplacements as they are reconstructed # in the __init__ when the dict is deserialized diff --git a/pymatgen/phonon/gruneisen.py b/pymatgen/phonon/gruneisen.py index 119781d7136..46e1355fe11 100644 --- a/pymatgen/phonon/gruneisen.py +++ b/pymatgen/phonon/gruneisen.py @@ -135,11 +135,10 @@ def thermal_conductivity_slack( t: float | None = None, ) -> float: """Calculate the thermal conductivity at the acoustic Debye temperature with the Slack formula, - using the average Gruneisen. - Adapted from abipy. + using the average Gruneisen. Adapted from abipy. Args: - squared (bool): if True the average is performed on the squared values of the Gruenisen + squared (bool): if True the average is performed on the squared values of the Gruneisen limit_frequencies: if None (default) no limit on the frequencies will be applied. Possible values are "debye" (only modes with frequencies lower than the acoustic Debye temperature) and "acoustic" (only the acoustic modes, i.e. the first three modes). @@ -163,12 +162,12 @@ def thermal_conductivity_slack( f1 = 0.849 * 3 * (4 ** (1 / 3)) / (20 * np.pi**3 * (1 - 0.514 * mean_g**-1 + 0.228 * mean_g**-2)) f2 = (const.k * theta_d / const.hbar) ** 2 f3 = const.k * average_mass * self.structure.volume ** (1 / 3) * 1e-10 / (const.hbar * mean_g**2) - k = f1 * f2 * f3 + thermal_cond = f1 * f2 * f3 if t is not None: - k *= theta_d / t + thermal_cond *= theta_d / t - return k + return thermal_cond @property # type: ignore @requires(phonopy, "This method requires phonopy to be installed") @@ -179,18 +178,18 @@ def tdos(self): class TempMesh: """Temporary Class.""" - a = TempMesh() - a.frequencies = np.transpose(self.frequencies) - a.weights = self.multiplicities + tmp_mesh = TempMesh() + tmp_mesh.frequencies = np.transpose(self.frequencies) + tmp_mesh.weights = self.multiplicities - b = TotalDos(a) - b.run() + dos_tot = TotalDos(tmp_mesh) + dos_tot.run() - return b + return dos_tot @property def phdos(self) -> PhononDos: - """Returns: PhononDos object.""" + """The phonon DOS (re)constructed from the gruneisen.yaml file.""" return PhononDos(self.tdos.frequency_points, self.tdos.dos) @property diff --git a/pymatgen/symmetry/settings.py b/pymatgen/symmetry/settings.py index 88964fd9107..3abd7f547f3 100644 --- a/pymatgen/symmetry/settings.py +++ b/pymatgen/symmetry/settings.py @@ -140,10 +140,10 @@ def p(self) -> list[float]: return self._p @property - def inverse(self) -> JonesFaithfulTransformation: + def inverse(self) -> Self: """JonesFaithfulTransformation.""" P_inv = np.linalg.inv(self.P) - return JonesFaithfulTransformation(P_inv, -np.matmul(P_inv, self.p)) + return type(self)(P_inv, -np.matmul(P_inv, self.p)) @property def transformation_string(self) -> str: diff --git a/pymatgen/symmetry/structure.py b/pymatgen/symmetry/structure.py index e7679826604..22d975c9b53 100644 --- a/pymatgen/symmetry/structure.py +++ b/pymatgen/symmetry/structure.py @@ -67,9 +67,9 @@ def __init__( self.wyckoff_letters = wyckoff_letters self.wyckoff_symbols = [f"{len(symb)}{symb[0]}" for symb in wyckoff_symbols] - def copy(self): - """Copy of structure.""" - return SymmetrizedStructure( + def copy(self) -> Self: # type: ignore[override] + """Make a copy of the SymmetrizedStructure.""" + return type(self)( self, spacegroup=self.spacegroup, equivalent_positions=self.site_labels, diff --git a/pymatgen/transformations/advanced_transformations.py b/pymatgen/transformations/advanced_transformations.py index 720c0f166ba..fc709d6fb9e 100644 --- a/pymatgen/transformations/advanced_transformations.py +++ b/pymatgen/transformations/advanced_transformations.py @@ -90,16 +90,6 @@ def apply_transformation(self, structure: Structure): def __repr__(self): return f"Charge Balance Transformation : Species to remove = {self.charge_balance_sp}" - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class SuperTransformation(AbstractTransformation): """This is a transformation that is inherently one-to-many. It is constructed @@ -148,14 +138,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | def __repr__(self): return f"Super Transformation : Transformations = {' '.join(map(str, self._transformations))}" - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -248,14 +233,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | def __repr__(self): return f"Multiple Substitution Transformation : Substitution on {self.sp_to_replace}" - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -487,14 +467,9 @@ def sort_func(struct): def __repr__(self): return "EnumerateStructureTransformation" - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -552,14 +527,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | def __repr__(self): return "SubstitutionPredictorTransformation" - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -918,20 +888,9 @@ def key(struct: Structure) -> int: return self._all_structures[0:num_to_return] # type: ignore - def __str__(self) -> str: - return "MagOrderingTransformation" - - def __repr__(self) -> str: - return str(self) - - @property - def inverse(self) -> None: - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -1149,14 +1108,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | return all_structures[0]["structure"] - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -1231,16 +1185,6 @@ def apply_transformation(self, structure: Structure): ) return sg.get_slab(self.shift, self.tol) - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class DisorderOrderedTransformation(AbstractTransformation): """Not to be confused with OrderDisorderedTransformation, @@ -1292,14 +1236,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | disordered_structures = disordered_structures[0:return_ranked_list] return disordered_structures - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @staticmethod @@ -1480,16 +1419,6 @@ def apply_transformation(self, structure: Structure): quick_gen=self.quick_gen, ) - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class CubicSupercellTransformation(AbstractTransformation): """A transformation that aims to generate a nearly cubic supercell structure @@ -1621,16 +1550,6 @@ def apply_transformation(self, structure: Structure) -> Structure: ) raise AttributeError("Unable to find cubic supercell") - @property - def inverse(self): - """Returns None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns False.""" - return False - class AddAdsorbateTransformation(AbstractTransformation): """Create adsorbate structures.""" @@ -1709,14 +1628,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | return structures[0] return [{"structure": structure} for structure in structures[:return_ranked_list]] - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -1868,14 +1782,9 @@ def apply_transformation( return structures[0] return [{"structure": structure} for structure in structures[:return_ranked_list]] - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -2151,14 +2060,9 @@ def _get_unique_best_sqs_structs(sqs, best_only, return_ranked_list, remove_dupl return to_return[:return_ranked_list] return to_return - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @@ -2230,13 +2134,3 @@ def apply_transformation(self, structure: Structure) -> Structure: def __repr__(self): return f"{__name__} : rattle_std = {self.rattle_std}" - - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False diff --git a/pymatgen/transformations/site_transformations.py b/pymatgen/transformations/site_transformations.py index 8e0276a3cfa..32976547a72 100644 --- a/pymatgen/transformations/site_transformations.py +++ b/pymatgen/transformations/site_transformations.py @@ -70,16 +70,6 @@ def apply_transformation(self, structure: Structure): def __repr__(self): return f"InsertSiteTransformation : species {self.species}, coords {self.coords}" - @property - def inverse(self): - """Returns None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns False.""" - return False - class ReplaceSiteSpeciesTransformation(AbstractTransformation): """This transformation substitutes certain sites with certain species.""" @@ -116,16 +106,6 @@ def __repr__(self): [f"{key}->{val}" + val for key, val in self.indices_species_map.items()] ) - @property - def inverse(self): - """Returns None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns False.""" - return False - class RemoveSitesTransformation(AbstractTransformation): """Remove certain sites in a structure.""" @@ -154,16 +134,6 @@ def apply_transformation(self, structure: Structure): def __repr__(self): return "RemoveSitesTransformation :" + ", ".join(map(str, self.indices_to_remove)) - @property - def inverse(self): - """Returns None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns False.""" - return False - class TranslateSitesTransformation(AbstractTransformation): """This class translates a set of sites by a certain vector.""" @@ -214,11 +184,6 @@ def inverse(self) -> TranslateSitesTransformation: """TranslateSitesTransformation with the reverse translation.""" return TranslateSitesTransformation(self.indices_to_move, -self.translation_vector, self.vector_in_frac_coords) - @property - def is_one_to_many(self) -> bool: - """Returns False.""" - return False - def as_dict(self): """JSON-serializable dict representation.""" dct = MSONable.as_dict(self) @@ -518,16 +483,6 @@ def apply_transformation(self, structure: Structure): new_struct.add_site_property(prop, self.site_properties[prop]) return new_struct - @property - def inverse(self): - """Returns None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns False.""" - return False - class RadialSiteDistortionTransformation(AbstractTransformation): """Radially perturbs atoms around a site. Can be used to create spherical distortion due to a @@ -591,13 +546,6 @@ def displace_dist(x, r, r0): structure.translate_sites(**kwargs) return structure - @property - def inverse(self): - """Returns the inverse transformation if available. - Otherwise, should return None. - """ - return False - @property def is_one_to_many(self) -> bool: """Determine if a Transformation is a one-to-many transformation. If a diff --git a/pymatgen/transformations/standard_transformations.py b/pymatgen/transformations/standard_transformations.py index 37282fd9ffb..3e5a862029a 100644 --- a/pymatgen/transformations/standard_transformations.py +++ b/pymatgen/transformations/standard_transformations.py @@ -73,11 +73,6 @@ def inverse(self): """Returns inverse Transformation.""" return RotationTransformation(self.axis, -self.angle, self.angle_in_radians) - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class OxidationStateDecorationTransformation(AbstractTransformation): """This transformation decorates a structure with oxidation states.""" @@ -103,16 +98,6 @@ def apply_transformation(self, structure): struct.add_oxidation_state_by_element(self.oxidation_states) return struct - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class AutoOxiStateDecorationTransformation(AbstractTransformation): """This transformation automatically decorates a structure with oxidation @@ -157,16 +142,6 @@ def apply_transformation(self, structure): """ return self.analyzer.get_oxi_state_decorated_structure(structure) - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class OxidationStateRemovalTransformation(AbstractTransformation): """This transformation removes oxidation states from a structure.""" @@ -185,16 +160,6 @@ def apply_transformation(self, structure): """ return structure.copy().remove_oxidation_states() - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class SupercellTransformation(AbstractTransformation): """The SupercellTransformation replicates a unit cell to a supercell.""" @@ -295,11 +260,6 @@ def inverse(self): """Raises: NotImplementedError.""" raise NotImplementedError - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class SubstitutionTransformation(AbstractTransformation): """This transformation substitutes species for one another.""" @@ -349,11 +309,6 @@ def inverse(self): inverse_map = {v: k for k, v in self._species_map.items()} return SubstitutionTransformation(inverse_map) - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class RemoveSpeciesTransformation(AbstractTransformation): """Remove all occurrences of some species from a structure.""" @@ -382,16 +337,6 @@ def apply_transformation(self, structure): def __repr__(self): return "Remove Species Transformation :" + ", ".join(self.species_to_remove) - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class PartialRemoveSpecieTransformation(AbstractTransformation): """Remove fraction of specie from a structure. @@ -451,7 +396,7 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True def __repr__(self): @@ -460,11 +405,6 @@ def __repr__(self): algo = self.algo return f"PartialRemoveSpecieTransformation({species=}, {fraction_to_remove=}, {algo=})" - @property - def inverse(self): - """Returns: None.""" - return - class OrderDisorderedStructureTransformation(AbstractTransformation): """Order a disordered structure. The disordered structure must be oxidation @@ -639,14 +579,9 @@ def apply_transformation(self, structure: Structure, return_ranked_list: bool | def __repr__(self): return "Order disordered structure transformation" - @property - def inverse(self): - """Returns: None.""" - return - @property def is_one_to_many(self) -> bool: - """Returns: True.""" + """Transform one structure to many.""" return True @property @@ -686,16 +621,6 @@ def apply_transformation(self, structure): def __repr__(self): return "Primitive cell transformation" - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class ConventionalCellTransformation(AbstractTransformation): """This class finds the conventional cell of the input structure.""" @@ -727,16 +652,6 @@ def apply_transformation(self, structure): def __repr__(self): return "Conventional cell transformation" - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class PerturbStructureTransformation(AbstractTransformation): """This transformation perturbs a structure by a specified distance in random @@ -776,16 +691,6 @@ def apply_transformation(self, structure: Structure) -> Structure: def __repr__(self): return f"PerturbStructureTransformation : Min_distance = {self.min_distance}" - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class DeformStructureTransformation(AbstractTransformation): """This transformation deforms a structure by a deformation gradient matrix.""" @@ -817,11 +722,6 @@ def inverse(self): """Returns inverse Transformation.""" return DeformStructureTransformation(self._deform.inv) - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class DiscretizeOccupanciesTransformation(AbstractTransformation): """Discretizes the site occupancies in a disordered structure; useful for @@ -878,16 +778,6 @@ def apply_transformation(self, structure): def __repr__(self): return "DiscretizeOccupanciesTransformation" - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class ChargedCellTransformation(AbstractTransformation): """The ChargedCellTransformation applies a charge to a structure (or defect @@ -923,11 +813,6 @@ def inverse(self): """Raises: NotImplementedError.""" raise NotImplementedError - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False - class ScaleToRelaxedTransformation(AbstractTransformation): """Takes the unrelaxed and relaxed structure and applies its site and volume @@ -992,13 +877,3 @@ def apply_transformation(self, structure): def __repr__(self): return "ScaleToRelaxedTransformation" - - @property - def inverse(self): - """Returns: None.""" - return - - @property - def is_one_to_many(self) -> bool: - """Returns: False.""" - return False diff --git a/pymatgen/transformations/transformation_abc.py b/pymatgen/transformations/transformation_abc.py index f5c62800b2b..934c54e8eb2 100644 --- a/pymatgen/transformations/transformation_abc.py +++ b/pymatgen/transformations/transformation_abc.py @@ -49,20 +49,18 @@ def apply_transformation(self, structure: Structure): return @property - @abc.abstractmethod def inverse(self) -> AbstractTransformation | None: """Returns the inverse transformation if available. - Otherwise, should return None. + Otherwise, should return None. Defaults to None, so only need to + override if applicable. """ @property - @abc.abstractmethod def is_one_to_many(self) -> bool: - """Determine if a Transformation is a one-to-many transformation. If a - Transformation is a one-to-many transformation, the - apply_transformation method should have a keyword arg - "return_ranked_list" which allows for the transformed structures to be - returned as a ranked list. + """Determine if a Transformation is a one-to-many transformation. In that case, the + apply_transformation method should have a keyword arg "return_ranked_list" which + allows for the transformed structures to be returned as a ranked list. + Defaults to False, so only need to override if True. """ return False diff --git a/pymatgen/util/provenance.py b/pymatgen/util/provenance.py index cb2469fed00..2dd43ce8ab8 100644 --- a/pymatgen/util/provenance.py +++ b/pymatgen/util/provenance.py @@ -74,7 +74,7 @@ class HistoryNode(namedtuple("HistoryNode", ["name", "url", "description"])): __slots__ = () def as_dict(self) -> dict[str, str]: - """Returns: Dict.""" + """Get MSONable dict.""" return {"name": self.name, "url": self.url, "description": self.description} @classmethod @@ -118,7 +118,7 @@ def __str__(self): return f"{self.name} <{self.email}>" def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" return {"name": self.name, "email": self.email} @classmethod @@ -257,7 +257,7 @@ def __init__( self.created_at = created_at or datetime.datetime.utcnow() def as_dict(self): - """Returns: MSONable dict.""" + """Get MSONable dict.""" dct = self.structure.as_dict() dct["@module"] = type(self).__module__ dct["@class"] = type(self).__name__ diff --git a/tests/core/test_interface.py b/tests/core/test_interface.py index ca9cd34d5a0..3d24180cd1a 100644 --- a/tests/core/test_interface.py +++ b/tests/core/test_interface.py @@ -14,11 +14,10 @@ class TestGrainBoundary(PymatgenTest): - @classmethod - def setUpClass(cls): - cls.Cu_conv = Structure.from_file(f"{TEST_DIR}/Cu_mp-30_conventional_standard.cif") - GB_Cu_conv = GrainBoundaryGenerator(cls.Cu_conv) - cls.Cu_GB1 = GB_Cu_conv.gb_from_parameters( + def setUp(self): + self.Cu_conv = Structure.from_file(f"{TEST_DIR}/Cu_mp-30_conventional_standard.cif") + GB_Cu_conv = GrainBoundaryGenerator(self.Cu_conv) + self.Cu_GB1 = GB_Cu_conv.gb_from_parameters( [1, 2, 3], 123.74898859588858, expand_times=4, @@ -27,7 +26,7 @@ def setUpClass(cls): plane=[1, 3, 1], rm_ratio=0.0, ) - cls.Cu_GB2 = GB_Cu_conv.gb_from_parameters( + self.Cu_GB2 = GB_Cu_conv.gb_from_parameters( [1, 2, 3], 123.74898859588858, expand_times=4, @@ -48,6 +47,8 @@ def test_init(self): def test_copy(self): Cu_GB1_copy = self.Cu_GB1.copy() + assert Cu_GB1_copy is not self.Cu_GB1 + assert Cu_GB1_copy == self.Cu_GB1 assert Cu_GB1_copy.sigma == approx(self.Cu_GB1.sigma) assert Cu_GB1_copy.rotation_angle == approx(self.Cu_GB1.rotation_angle) assert Cu_GB1_copy.rotation_axis == self.Cu_GB1.rotation_axis diff --git a/tests/transformations/test_advanced_transformations.py b/tests/transformations/test_advanced_transformations.py index 13c2db75475..71ef890053d 100644 --- a/tests/transformations/test_advanced_transformations.py +++ b/tests/transformations/test_advanced_transformations.py @@ -54,8 +54,7 @@ def get_table(): - """ - Loads a lightweight lambda table for use in unit tests to reduce + """Loads a lightweight lambda table for use in unit tests to reduce initialization time, and make unit tests insensitive to changes in the default lambda table. """