Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More type annotations #3800

Merged
merged 6 commits into from
May 2, 2024
Merged

More type annotations #3800

merged 6 commits into from
May 2, 2024

Conversation

janosh
Copy link
Member

@janosh janosh commented May 2, 2024

No description provided.

janosh added 3 commits May 2, 2024 09:24
TestGrainBoundary setUpClass -> setUp, helps language server infer types of class attributes
@janosh janosh added linting Linting and quality assurance types Type all the things labels May 2, 2024
@janosh janosh requested review from shyuep and mkhorton as code owners May 2, 2024 14:11
Copy link

coderabbitai bot commented May 2, 2024

Walkthrough

The recent updates across various files in the Python library focus on refining method definitions and documentation for improved code clarity and type checking. Changes include adding return type hints, updating docstrings, and transitioning setup methods in the test suite from class-level to instance-level for enhanced flexibility and clarity during testing.

Changes

File Path Change Summary
.../vasp/inputs.py Updated copy method in SomeClass with a return type hint and a descriptive docstring.
.../symmetry/structure.py Modified copy method in SymmetrizedStructure to specify the return type as Self and update the docstring.
tests/core/test_interface.py Converted class-level setup methods to instance-level in TestGrainBoundary and adjusted variable references.
.../analysis/ewald.py Refined docstrings for properties eta, best_m_list, minimized_sum, and output_lists for clarity.
.../analysis/nmr.py Updated docstrings for properties related to chemical shielding tensors for improved descriptions.
.../io/lobster/outputs.py Enhanced docstrings for properties icohplist and icohpcollection, and specified return type for get_doc.
.../io/nwchem.py Clarified the docstring for the as_dict method to improve its purpose description.
.../io/pwscf.py Added Any to typing import, updated type annotations, specified return types, and refined docstrings.
.../io/shengbte.py Updated the docstring for the as_dict method to improve clarity.
.../io/vasp/help.py Changed documentation for get_incar_tags method to provide a clearer description of its functionality.
.../phonon/bandstructure.py Updated the as_dict method in BandStructureSymmLine for better clarity.
.../phonon/gruneisen.py Made adjustments to method names and docstrings for clarity in thermal conductivity calculations.
.../symmetry/settings.py Changed the return type of the inverse property to Self and updated the return statement accordingly.
.../transformations/advanced_transformations.py,
.../site_transformations.py,
.../standard_transformations.py
Removed redundant properties and methods for streamlining code across multiple classes.
.../transformations/transformation_abc.py Removed @abc.abstractmethod decorators and updated docstrings for inverse and is_one_to_many properties.
.../util/provenance.py Updated docstrings for as_dict methods in HistoryNode and History classes for clarity in purpose.
tests/transformations/test_advanced_transformations.py Updated the description for the get_table method for improved clarity.

Recent Review Details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits Files that changed from the base of the PR and between 68734ab and 6e46259.
Files selected for processing (33)
  • dev_scripts/update_pt_data.py (1 hunks)
  • pymatgen/alchemy/filters.py (3 hunks)
  • pymatgen/analysis/ewald.py (2 hunks)
  • pymatgen/analysis/molecule_structure_comparator.py (1 hunks)
  • pymatgen/analysis/nmr.py (3 hunks)
  • pymatgen/analysis/pourbaix_diagram.py (1 hunks)
  • pymatgen/analysis/structure_matcher.py (4 hunks)
  • pymatgen/analysis/structure_prediction/substitution_probability.py (1 hunks)
  • pymatgen/analysis/structure_prediction/substitutor.py (3 hunks)
  • pymatgen/analysis/thermochemistry.py (1 hunks)
  • pymatgen/apps/battery/battery_abc.py (1 hunks)
  • pymatgen/apps/battery/insertion_battery.py (1 hunks)
  • pymatgen/apps/borg/hive.py (3 hunks)
  • pymatgen/command_line/critic2_caller.py (1 hunks)
  • pymatgen/core/operations.py (1 hunks)
  • pymatgen/io/adf.py (1 hunks)
  • pymatgen/io/cif.py (1 hunks)
  • pymatgen/io/feff/outputs.py (1 hunks)
  • pymatgen/io/lammps/outputs.py (1 hunks)
  • pymatgen/io/lobster/outputs.py (3 hunks)
  • pymatgen/io/nwchem.py (2 hunks)
  • pymatgen/io/pwscf.py (3 hunks)
  • pymatgen/io/shengbte.py (1 hunks)
  • pymatgen/io/vasp/help.py (1 hunks)
  • pymatgen/phonon/bandstructure.py (1 hunks)
  • pymatgen/phonon/gruneisen.py (3 hunks)
  • pymatgen/symmetry/settings.py (1 hunks)
  • pymatgen/transformations/advanced_transformations.py (15 hunks)
  • pymatgen/transformations/site_transformations.py (6 hunks)
  • pymatgen/transformations/standard_transformations.py (17 hunks)
  • pymatgen/transformations/transformation_abc.py (1 hunks)
  • pymatgen/util/provenance.py (3 hunks)
  • tests/transformations/test_advanced_transformations.py (1 hunks)
Files skipped from review due to trivial changes (20)
  • dev_scripts/update_pt_data.py
  • pymatgen/alchemy/filters.py
  • pymatgen/analysis/ewald.py
  • pymatgen/analysis/molecule_structure_comparator.py
  • pymatgen/analysis/nmr.py
  • pymatgen/analysis/pourbaix_diagram.py
  • pymatgen/analysis/structure_matcher.py
  • pymatgen/analysis/structure_prediction/substitution_probability.py
  • pymatgen/analysis/thermochemistry.py
  • pymatgen/apps/battery/battery_abc.py
  • pymatgen/apps/battery/insertion_battery.py
  • pymatgen/apps/borg/hive.py
  • pymatgen/io/adf.py
  • pymatgen/io/lammps/outputs.py
  • pymatgen/io/nwchem.py
  • pymatgen/io/shengbte.py
  • pymatgen/phonon/bandstructure.py
  • pymatgen/transformations/site_transformations.py
  • pymatgen/transformations/transformation_abc.py
  • tests/transformations/test_advanced_transformations.py
Files skipped from review as they are similar to previous changes (1)
  • pymatgen/analysis/structure_prediction/substitutor.py
Additional comments not posted (4)
pymatgen/io/pwscf.py (2)

577-578: The method final_energy is well implemented with a clear return type annotation.


582-583: The method lattice_type is correctly implemented with a clear return type annotation.

pymatgen/core/operations.py (1)

236-239: The method inverse is correctly implemented with a clear return type annotation.

pymatgen/command_line/critic2_caller.py (1)

391-392: Ensure the type property correctly handles invalid types.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

Out of diff range and nitpick comments (20)
pymatgen/analysis/elasticity/elastic.py (6)

Line range hint 57-63: Ensure proper documentation for constructor parameters.

The constructor of NthOrderElasticTensor lacks detailed documentation for its parameters input_array and check_rank. It's crucial for maintainability and usability that all parameters are well-documented, especially in a complex domain like tensor mathematics.


Line range hint 80-86: Consider optimizing the strain shape conversion.

The method calculate_stress converts strain from Voigt to full tensor notation if needed. This conversion could be optimized or cached if strains are frequently in Voigt notation to avoid redundant calculations.


Line range hint 88-94: Clarify the unit conversion in energy_density.

The method energy_density includes a unit conversion step which might not be immediately clear to all users. Consider adding a comment explaining why this conversion is necessary and what units are being converted from and to.


Line range hint 108-114: Validate tensor shape in ElasticTensor constructor.

The constructor of ElasticTensor should explicitly check that the input_array is of shape 3x3x3x3. Currently, it relies on the superclass constructor, which does not enforce this specific shape.


Line range hint 116-120: Optimize the calculation of compliance_tensor.

The property compliance_tensor calculates the inverse of the Voigt matrix every time it is accessed. Consider caching this value or using a lazy evaluation pattern to improve performance, especially if this property is accessed frequently.


Line range hint 152-160: Improve error message clarity in directional_poisson_ratio.

The error message "n and m must be orthogonal" in the directional_poisson_ratio method could be more informative. Consider including the values of n and m in the error message to aid debugging.

pymatgen/analysis/chemenv/coordination_environments/coordination_geometries.py (4)

685-685: Ensure the mp_symbol property has a clear docstring.

Consider adding a more detailed docstring for the mp_symbol property to explain what an MP symbol is and its relevance.


690-691: Ensure consistency in property descriptions.

The docstring for the ce_symbol property could be improved for clarity. Consider specifying what "CE" stands for and how it relates to the MP symbol.


712-712: Clarify the purpose of the IUPAC_symbol_str property.

The IUPAC_symbol_str property seems redundant since it merely converts the IUPAC_symbol to a string, which is its inherent type. Consider removing this property if it does not serve a specific purpose.


Line range hint 972-997: Review the dictionary construction methods.

The methods get_symbol_name_mapping and get_symbol_cn_mapping contain duplicate logic. Consider creating a private helper method to reduce code duplication and improve maintainability.

+ def _get_mapping(self, key, coordination=None):
+     geom = {}
+     for coord_geom in self.cg_list:
+         if coordination is None or coord_geom.get_coordination_number() == coordination:
+             geom[getattr(coord_geom, key)] = getattr(coord_geom, key)
+     return geom

- # Replace calls to `get_symbol_name_mapping` and `get_symbol_cn_mapping` with `_get_mapping('mp_symbol')` and `_get_mapping('name')`
pymatgen/io/abinit/abiobjects.py (5)

917-917: Ensure the path_from_structure method has a clear docstring.

Adding a docstring to the path_from_structure method would improve code readability and maintainability by clearly explaining the purpose and usage of the method.


Line range hint 1-1: Consider adding type hints to the lattice_from_abivars function.

Adding type hints to the function parameters and return type would enhance code readability and maintainability, making it easier to understand the expected types of the inputs and output.


Line range hint 1-1: Refactor the lattice_from_abivars function to reduce complexity.

The function lattice_from_abivars is quite complex and handles multiple scenarios. Consider breaking it down into smaller, more focused functions to improve readability and maintainability.


Line range hint 1-1: Add error handling for missing required keys in structure_from_abivars.

The function structure_from_abivars assumes that certain keys like acell and typat are always present in the input dictionary. Consider adding checks and raising appropriate exceptions if these keys are missing to prevent runtime errors.


Line range hint 1-1: Optimize the handling of coordinate transformations in structure_from_abivars.

The coordinate transformation logic in structure_from_abivars could be optimized by extracting it into a separate function or method. This would make the main function cleaner and more focused on its primary responsibility.

pymatgen/io/abinit/pseudos.py (1)

Line range hint 590-625: The function _dict_from_lines is designed to parse formatted text into a dictionary. However, there are a few issues and improvements that can be made:

  1. The function assumes that key_nums is iterable, which might not always be the case. It's safer to ensure it's a list or tuple before proceeding.
  2. The error handling could be more descriptive, especially when the lengths of lines and key_nums do not match.
  3. The use of Namespace for kwargs is unconventional. A simple dictionary would suffice and be more understandable.
  4. The function modifies keys in-place, which can lead to unexpected behavior. It's better to create a new list for sanitized keys.
- if not isinstance(key_nums, collections.abc.Iterable):
-     key_nums = list(key_nums)
+ if not isinstance(key_nums, (list, tuple)):
+     raise TypeError("key_nums must be a list or tuple")

- kwargs = Namespace()
+ kwargs = {}

- keys = "".join(tokens[nk:]).replace("[", "").replace("]", "").split(",")
+ sanitized_keys = [key.replace("[", "").replace("]", "") for key in tokens[nk:].split(",")]
+ keys = sanitized_keys
pymatgen/analysis/surface_analysis.py (1)

Line range hint 1293-1307: Add type annotations to the function parameters and return type for entry_dict_from_list.

- def entry_dict_from_list(all_slab_entries) -> dict:
+ def entry_dict_from_list(all_slab_entries: List[SlabEntry]) -> Dict[Tuple, Dict]:

This change improves the readability and maintainability of the code by making the expected types of the function parameters and return value explicit.

pymatgen/core/structure.py (3)

Line range hint 318-327: Consider adding type hints for the __init__ method parameters to enhance code readability and maintainability.

- def __init__(
+ def __init__(self,

Line range hint 349-350: Consider adding type hints for the __init__ method parameters to enhance code readability and maintainability.

- def __init__(
+ def __init__(self,

Line range hint 372-373: Consider adding type hints for the __init__ method parameters to enhance code readability and maintainability.

- def __init__(
+ def __init__(self,

@@ -494,7 +494,7 @@ def wulff_from_chempot(
symprec=1e-5,
no_clean=False,
no_doped=False,
):
) -> WulffShape:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the wulff_from_chempot method handles exceptions or errors gracefully.

Consider adding error handling or logging to manage potential issues with input validation or during execution, such as when delu_dict keys do not match expected symbols or when calculations fail due to unexpected input values.

Comment on lines +623 to +625
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(",")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handling of the separator in _dict_from_lines function is potentially error-prone. The function checks if the first character of the first key matches the separator but does not handle cases where the separator might not be present, which could lead to incorrect parsing or errors.

- if sep is not None:
-     check = keys[0][0]
-     if check != sep:
-         raise ValueError(f"Expecting separator {sep}, got {check}")
-     keys[0] = keys[0][1:]
+ if sep is not None:
+     if not keys[0].startswith(sep):
+         raise ValueError(f"Expecting separator {sep} at the start of {keys[0]}")
+     keys = [key.lstrip(sep) for key in keys]

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
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(",")
values = tokens[:nk]
# Sanitize keys: In some case we might get strings in the form: foo[,bar]
keys = "".join(tokens[nk:]).replace("[", "").replace("]", "").split(",")
if sep is not None:
if not keys[0].startswith(sep):
raise ValueError(f"Expecting separator {sep} at the start of {keys[0]}")
keys = [key.lstrip(sep) for key in keys]

@@ -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]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for file operations.

The method _get_data_from_xyz opens a file without using a context manager, which could lead to resources not being freed if an exception occurs. Consider using a with statement to handle the file opening and reading.

- with open(xyz_path) as r:
+ with open(xyz_path, 'r') as r:

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def _get_data_from_xyz(xyz_path) -> list[float]:
def _get_data_from_xyz(xyz_path) -> list[float]:
with open(xyz_path, 'r') as r:

@@ -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]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure consistent error handling in file operations.

Similar to the previous method, _get_cm5_data_from_output opens a file directly. It's recommended to use a context manager here as well to ensure that the file is properly closed after its contents are processed.

- with open(ddec_analysis_path) as r:
+ with open(ddec_analysis_path, 'r') as r:

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def _get_cm5_data_from_output(ddec_analysis_path) -> list[float]:
def _get_cm5_data_from_output(ddec_analysis_path) -> list[float]:

@@ -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]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider refining the error handling for file operations.

The function bader_analysis_from_path uses the glob function to find files but does not handle the case where files are not found effectively. It raises a FileNotFoundError if the CHGCAR file is not found, but similar handling is not present for other critical files like AECCAR0 and AECCAR2. Consider adding explicit error handling for these cases to avoid runtime errors.

- if not aeccar0_path:
+ if aeccar0_path is None:
    raise FileNotFoundError("Could not find AECCAR0!")
- if not aeccar2_path:
+ if aeccar2_path is None:
    raise FileNotFoundError("Could not find AECCAR2!")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def bader_analysis_from_path(path: str, suffix: str = "") -> dict[str, Any]:
def bader_analysis_from_path(path: str, suffix: str = "") -> dict[str, Any]:

Comment on lines +103 to +107
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
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider refactoring compute_corrections to separate data validation from the core computation logic for better maintainability.

@@ -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] = []
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review the initialization of cg_list.

The initialization of cg_list directly within the constructor without checking if the file exists or handling potential JSON parsing errors could lead to runtime exceptions. Consider adding error handling mechanisms.

+ try:
+     with open(cg_file) as file:
+         dd = json.load(file)
+     self.cg_list.append(CoordinationGeometry.from_dict(dd))
+ except (IOError, json.JSONDecodeError) as e:
+     logging.error(f"Failed to load coordination geometry from {cg_file}: {str(e)}")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.cg_list: list[CoordinationGeometry] = []
try:
with open(cg_file) as file:
dd = json.load(file)
self.cg_list.append(CoordinationGeometry.from_dict(dd))
except (IOError, json.JSONDecodeError) as e:
logging.error(f"Failed to load coordination geometry from {cg_file}: {str(e)}")

Comment on lines +946 to +957
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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review the method get_geometries.

The method get_geometries can be optimized by removing redundant checks and simplifying the logic. Consider refactoring to improve readability and performance.

- if coordination is None:
-     for coord_geom in self.cg_list:
-         if returned == "cg":
-             geom.append(coord_geom)
-         elif returned == "mp_symbol":
-             geom.append(coord_geom.mp_symbol)
- else:
-     for coord_geom in self.cg_list:
-         if coord_geom.get_coordination_number() == coordination:
-             if returned == "cg":
-                 geom.append(coord_geom)
-             elif returned == "mp_symbol":
-                 geom.append(coord_geom.mp_symbol)
+ for coord_geom in self.cg_list:
+     if coordination is None or coord_geom.get_coordination_number() == coordination:
+         geom.append(coord_geom if returned == "cg" else coord_geom.mp_symbol)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
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)
for coord_geom in self.cg_list:
if coordination is None or coord_geom.get_coordination_number() == coordination:
geom.append(coord_geom if returned == "cg" else coord_geom.mp_symbol)

Comment on lines +222 to 223
def copy(self) -> Self:
"""Returns a copy of itself. Concrete subclasses should implement this
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding type hints for the __init__ method parameters to enhance code readability and maintainability.

- def __init__(
+ def __init__(self,

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def copy(self) -> Self:
"""Returns a copy of itself. Concrete subclasses should implement this
def copy(self) -> Self:
"""Returns a copy of itself. Concrete subclasses should implement this

Comment on lines +3188 to 3189
def copy(self) -> Self:
"""Convenience method to get a copy of the molecule.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding type hints for the __init__ method parameters to enhance code readability and maintainability.

- def __init__(
+ def __init__(self,

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def copy(self) -> Self:
"""Convenience method to get a copy of the molecule.
def copy(self) -> Self:
"""Convenience method to get a copy of the molecule.

@janosh janosh requested a review from JaGeo as a code owner May 2, 2024 15:01
@janosh janosh enabled auto-merge (squash) May 2, 2024 15:05
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Out of diff range and nitpick comments (13)
pymatgen/phonon/gruneisen.py (1)

Line range hint 138-170: Refactor the method thermal_conductivity_slack for better readability and efficiency.

The method thermal_conductivity_slack in the GruneisenParameter class can be refactored for better readability and to avoid redundant calculations. Consider extracting parts of the formula into separate methods or variables.

  def thermal_conductivity_slack(
      self,
      squared: bool = True,
      limit_frequencies: Literal["debye", "acoustic"] | None = None,
      theta_d: float | None = None,
      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.

      Args:
          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).
          theta_d: the temperature used to estimate the average of the Gruneisen used in the
              Slack formula. If None the acoustic Debye temperature is used (see
              acoustic_debye_temp). Will also be considered as the Debye temperature in the
              Slack formula.
          t: temperature at which the thermal conductivity is estimated. If None the value at
              the calculated acoustic Debye temperature is given. The value is obtained as a
              simple rescaling of the value at the Debye temperature.

      Returns:
          The value of the thermal conductivity in W/(m*K)
      """
      assert self.structure is not None, "Structure is not defined."
      average_mass = np.mean([s.specie.atomic_mass for s in self.structure]) * amu_to_kg
      if theta_d is None:
          theta_d = self.acoustic_debye_temp
      mean_g = self.average_gruneisen(t=theta_d, squared=squared, limit_frequencies=limit_frequencies)

      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)
      thermal_cond = f1 * f2 * f3

      if t is not None:
          thermal_cond *= theta_d / t

      return thermal_cond
pymatgen/transformations/standard_transformations.py (2)

399-399: Ensure consistency in method documentation.

The method is_one_to_many in PartialRemoveSpecieTransformation class lacks a docstring. Consider adding a brief description to maintain consistency with other methods in the class.


584-584: Ensure consistency in method documentation.

The method is_one_to_many in OrderDisorderedStructureTransformation class lacks a docstring. Consider adding a brief description to maintain consistency with other methods in the class.

pymatgen/io/cif.py (2)

1611-1612: Ensure the cif_file property in CifWriter is documented.

While the property is implemented correctly, adding a docstring would improve code maintainability and clarity, especially for new developers or external contributors who might use this class.


1611-1612: Consider adding a docstring to the cif_file property in CifWriter.

A docstring would help clarify the purpose and usage of this property, improving code readability and maintainability.

pymatgen/transformations/advanced_transformations.py (8)

Line range hint 53-53: Ensure proper documentation for the constructor parameters.

Consider adding parameter descriptions in the docstring for __init__ to enhance code readability and maintainability.


Line range hint 59-59: Handle potential division by zero.

- num_to_remove = (charge / specie.oxi_state) if specie.oxi_state else 0.0
+ if specie.oxi_state == 0:
+     raise ValueError("Oxidation state cannot be zero for charge balancing.")
+ num_to_remove = charge / specie.oxi_state

This change ensures that the code raises an informative error when attempting to divide by zero, which could occur if specie.oxi_state is zero.


93-93: Clarify the type of transformations parameter.

The transformations parameter in the constructor should specify the expected type more clearly, possibly using a type hint like List[AbstractTransformation].


Line range hint 99-99: Improve error message for clarity.

- raise ValueError("SuperTransformation has no single best structure output. Must use return_ranked_list")
+ raise ValueError("SuperTransformation requires 'return_ranked_list' to be set to an integer to specify the number of structures to return.")

This modification provides a clearer instruction on how to use the return_ranked_list parameter correctly.


Line range hint 183-183: Validate r_fraction to prevent logical errors.

+ if not (0 <= r_fraction <= 1):
+     raise ValueError("Replacement fraction must be between 0 and 1.")

Adding this validation ensures that the replacement fraction is within a logical range, preventing potential runtime errors or unexpected behavior.


Line range hint 199-199: Handle potential division by zero.

- dummy_sp = f"X{charge}{sign}"
+ if charge == 0:
+     raise ValueError("Charge cannot be zero when defining a dummy species.")
+ dummy_sp = f"X{charge}{sign}"

This change prevents a division by zero error that could occur later in the code when charge is used in calculations.


Line range hint 328-328: Validate max_cell_size and max_disordered_sites to prevent conflicting settings.

+ if max_cell_size is not None and max_disordered_sites is not None:
+     raise ValueError("Specify either 'max_cell_size' or 'max_disordered_sites', not both.")

This validation prevents the user from setting both parameters, which are mutually exclusive and could lead to ambiguous behavior.


Line range hint 502-502: Clarify the exception message for unsupported operations.

- raise ValueError("SubstitutionPredictorTransformation doesn't support returning 1 structure")
+ raise ValueError("SubstitutionPredictorTransformation requires 'return_ranked_list' to be set to an integer greater than 1.")

This change clarifies the requirements for using the return_ranked_list parameter, ensuring that users understand it must be an integer greater than 1.

@@ -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."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a more detailed docstring for the icohplist property.

The current docstring does not provide information about the structure and content of the returned dictionary. Enhancing the docstring would improve code readability and maintainability.

@@ -520,7 +520,7 @@ def icohplist(self) -> dict[Any, dict[str, Any]]:

@property
def icohpcollection(self):
"""Returns: IcohpCollection object."""
"""The IcohpCollection object."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the icohpcollection property has a complete docstring.

The docstring for the icohpcollection property is missing details about the return type and the structure of the returned object. Providing this information would aid developers in understanding the method's purpose and usage.

@@ -4,7 +4,7 @@

import re
from collections import defaultdict
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using more specific type hints for better type checking and clarity.

- from typing import TYPE_CHECKING, Any
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Dict, List, Optional

@@ -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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the type hint for data is specified for better code clarity and type checking.

- self.data: dict[str, Any] = defaultdict(list)
+ self.data: Dict[str, List[Any]] = defaultdict(list)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.data: dict[str, Any] = defaultdict(list)
self.data: Dict[str, List[Any]] = defaultdict(list)

return CriticalPointType(self._type)

def __str__(self):
return f"Critical Point: {self.type.name} ({self.frac_coords})"

@property
def laplacian(self) -> float:
"""Returns: The Laplacian of the field at the critical point."""
"""The Laplacian of the field at the critical point."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for cases where the Hessian matrix is not square.

- return np.trace(self.field_hessian)
+ if self.field_hessian.shape == (3, 3):
+     return np.trace(self.field_hessian)
+ else:
+     raise ValueError("Hessian matrix must be 3x3.")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""The Laplacian of the field at the critical point."""
"""The Laplacian of the field at the critical point."""
if self.field_hessian.shape == (3, 3):
return np.trace(self.field_hessian)
else:
raise ValueError("Hessian matrix must be 3x3.")

Add documentation for the ellipticity property to clarify its calculation and usage.

- """Most meaningful for bond critical points, can be physically interpreted as e.g.
- degree of pi-bonding in organic molecules. Consult literature for more info.
+ """
+ Ellipticity of the field at the critical point.
+ 
+ This property is most meaningful for bond critical points and can be physically interpreted, for example,
+ as the degree of pi-bonding in organic molecules. For more detailed information, consult the relevant literature.
+ 
+ Returns:
+     float: The ellipticity of the field at the critical point.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""The Laplacian of the field at the critical point."""
"""The Laplacian of the field at the critical point.
Ellipticity of the field at the critical point.
This property is most meaningful for bond critical points and can be physically interpreted, for example,
as the degree of pi-bonding in organic molecules. For more detailed information, consult the relevant literature.
Returns:
float: The ellipticity of the field at the critical point.
"""

Validate the dimensions of the Hessian matrix before computing its trace.

- return np.trace(self.field_hessian)
+ if self.field_hessian.shape == (3, 3):
+     return np.trace(self.field_hessian)
+ else:
+     raise ValueError("Hessian matrix must be 3x3.")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""The Laplacian of the field at the critical point."""
"""The Laplacian of the field at the critical point."""
if self.field_hessian.shape == (3, 3):
return np.trace(self.field_hessian)
else:
raise ValueError("Hessian matrix must be 3x3.")

@@ -74,7 +74,7 @@ class HistoryNode(namedtuple("HistoryNode", ["name", "url", "description"])):
__slots__ = ()

def as_dict(self) -> dict[str, str]:
"""Returns: Dict."""
"""Get MSONable dict."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure consistent return types in as_dict method.

The as_dict method in the HistoryNode class should consistently return a dictionary with string keys and values. The current implementation may not handle non-string descriptions properly.

  def as_dict(self) -> dict[str, str]:
      """Get MSONable dict."""
-     return {"name": self.name, "url": self.url, "description": self.description}
+     return {"name": self.name, "url": self.url, "description": str(self.description)}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""Get MSONable dict."""
def as_dict(self) -> dict[str, str]:
"""Get MSONable dict."""
return {"name": self.name, "url": self.url, "description": str(self.description)}

@@ -118,7 +118,7 @@ def __str__(self):
return f"{self.name} <{self.email}>"

def as_dict(self):
"""Returns: MSONable dict."""
"""Get MSONable dict."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify the expected dictionary structure in as_dict method.

In the as_dict method of the Author class, consider adding a docstring that clearly specifies the structure of the returned dictionary, especially the types of the values.

  def as_dict(self) -> dict:
+     """Return a dictionary representation of the Author.
+     Returns:
+         dict: A dictionary with 'name' and 'email' as keys and their corresponding values as strings.
+     """
      return {"name": self.name, "email": self.email}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""Get MSONable dict."""
def as_dict(self) -> dict:
"""Return a dictionary representation of the Author.
Returns:
dict: A dictionary with 'name' and 'email' as keys and their corresponding values as strings.
"""
return {"name": self.name, "email": self.email}

Comment on lines +403 to +404
def atomic_background(self) -> np.ndarray:
"""The atomic background of EELS."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add error handling for file operations in atomic_background.

The method atomic_background in the Eels class should include error handling for file operations to manage potential issues with file access or content.

  def atomic_background(self) -> np.ndarray:
      """The atomic background of EELS."""
+     try:
+         return self.data[:, 2]
+     except Exception as e:
+         raise RuntimeError("Failed to access atomic background data: " + str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def atomic_background(self) -> np.ndarray:
"""The atomic background of EELS."""
def atomic_background(self) -> np.ndarray:
"""The atomic background of EELS."""
try:
return self.data[:, 2]
except Exception as e:
raise RuntimeError("Failed to access atomic background data: " + str(e))

Comment on lines +408 to +409
def fine_structure(self) -> np.ndarray:
"""The fine structure of EELS."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate input parameters in fine_structure.

In the fine_structure method of the Eels class, consider validating the input parameters to ensure they meet expected conditions before processing.

  def fine_structure(self) -> np.ndarray:
+     if not isinstance(self.data, np.ndarray):
+         raise ValueError("Expected data to be a numpy array")
      """The fine structure of EELS."""
      return self.data[:, 3]

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def fine_structure(self) -> np.ndarray:
"""The fine structure of EELS."""
def fine_structure(self) -> np.ndarray:
"""The fine structure of EELS."""
if not isinstance(self.data, np.ndarray):
raise ValueError("Expected data to be a numpy array")
return self.data[:, 3]


@property
def phdos(self) -> PhononDos:
"""Returns: PhononDos object."""
"""The phonon DOS (re)constructed from the gruneisen.yaml file."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the phdos property correctly handles potential exceptions.

The phdos property in the GruneisenPhononBandStructure class should include error handling to manage cases where the DOS data might be incomplete or malformed.

  @property
  def phdos(self) -> PhononDos:
+     try:
          """The phonon DOS (re)constructed from the gruneisen.yaml file."""
          return PhononDos(self.tdos.frequency_points, self.tdos.dos)
+     except Exception as e:
+         raise RuntimeError("Failed to construct phonon DOS: " + str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""The phonon DOS (re)constructed from the gruneisen.yaml file."""
@property
def phdos(self) -> PhononDos:
try:
"""The phonon DOS (re)constructed from the gruneisen.yaml file."""
return PhononDos(self.tdos.frequency_points, self.tdos.dos)
except Exception as e:
raise RuntimeError("Failed to construct phonon DOS: " + str(e))

@janosh janosh disabled auto-merge May 2, 2024 15:20
@janosh janosh merged commit 87c92e6 into master May 2, 2024
21 of 22 checks passed
@janosh janosh deleted the types branch May 2, 2024 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
linting Linting and quality assurance types Type all the things
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant