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

Officially support Python 3.12 and test in CI #3685

Merged
merged 10 commits into from
May 1, 2024
Merged

Officially support Python 3.12 and test in CI #3685

merged 10 commits into from
May 1, 2024

Conversation

janosh
Copy link
Member

@janosh janosh commented Mar 11, 2024

unknown if all upstream packages have 3.12 support by now. potential issues expected for pytorch and spglib materialsproject/atomate2#768 (comment).

@janosh janosh added compatability Concerning pymatgen compatibility with different OS, Python versions, numpy versions, etc. ci Continuous integration pkg Package health and distribution related stuff labels Mar 11, 2024
@janosh janosh requested review from shyuep and mkhorton as code owners March 11, 2024 14:27
@janosh
Copy link
Member Author

janosh commented Mar 11, 2024

chgnet cythonized graph converter doesn't compile on 3.12:

chgnet/graph/cygraph.c:1208:10: fatal error: fast_converter_libraries/create_graph.c: No such file or directory
 1208 | #include "fast_converter_libraries/create_graph.c"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
error: command '/usr/bin/gcc' failed with exit code 1

Copy link

coderabbitai bot commented Apr 26, 2024

Walkthrough

This update involves refinements across various modules in the pymatgen library, focusing on enhancing code clarity, type safety, and updating dependencies. Changes include variable renaming for better readability, type annotations for improved type checking, and adjustments in Python version compatibility in CI configurations and setup files.

Changes

Files Change Summary
alchemy/transmuters.py, analysis/structure_prediction/substitutor.py Replaced extend with += for list concatenation, updated return variable names, and renamed variables for clarity.
io/lobster/inputs.py Refactored keyword handling in from_file, optimized processing, and enhanced error handling.
io/vasp/outputs.py Modified _parse_dos method, added type annotations, and improved data processing.
.github/workflows/test.yml, setup.py Updated Python versions in CI configurations and dependencies.
tests/io/lobster/test_inputs.py Renamed instance variables within test classes for consistency.

Possibly related issues


Recent Review Details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits Files that changed from the base of the PR and between 2e05157 and 7779aeb.
Files selected for processing (3)
  • pymatgen/alchemy/transmuters.py (10 hunks)
  • pymatgen/io/lobster/inputs.py (3 hunks)
  • tests/io/lobster/test_inputs.py (5 hunks)
Files skipped from review as they are similar to previous changes (3)
  • pymatgen/alchemy/transmuters.py
  • pymatgen/io/lobster/inputs.py
  • tests/io/lobster/test_inputs.py

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: 0

Out of diff range and nitpick comments (6)
tests/io/vasp/test_outputs.py (1)

Line range hint 76-85: Consider removing the print statement unless it is essential for the test, to keep the test output clean.

pymatgen/io/vasp/outputs.py (5)

Line range hint 1483-1514: Optimize the parsing of complex coefficients in the Wavecar class.

- data = np.fromfile(file, dtype=np.complex64, count=nplane)
- np.fromfile(file, dtype=np.float64, count=recl8 - nplane)
+ data = np.fromfile(file, dtype=np.complex64, count=nplane)
+ file.seek((recl8 - nplane) * np.dtype(np.float64).itemsize, 1)

This change avoids reading unnecessary data into memory by directly seeking to the next relevant position in the file.


Line range hint 1483-1514: Consider using more descriptive variable names in _generate_nbmax.

- bmag = np.linalg.norm(self.b, axis=1)
- b = self.b
+ reciprocal_lattice_magnitudes = np.linalg.norm(self.b, axis=1)
+ reciprocal_lattice_vectors = self.b

Renaming bmag to reciprocal_lattice_magnitudes and b to reciprocal_lattice_vectors enhances readability by making the purpose of these variables clearer.


Line range hint 1483-1514: Refactor the loop in _generate_G_points to improve clarity and performance.

- for i in range(2 * self._nbmax[2] + 1):
-     i3 = i - 2 * self._nbmax[2] - 1 if i > self._nbmax[2] else i
-     for j in range(2 * self._nbmax[1] + 1):
-         j2 = j - 2 * self._nbmax[1] - 1 if j > self._nbmax[1] else j
-         for k in range(kmax):
-             k1 = k - 2 * self._nbmax[0] - 1 if k > self._nbmax[0] else k
+ for i3 in range(-self._nbmax[2], self._nbmax[2] + 1):
+     for j2 in range(-self._nbmax[1], self._nbmax[1] + 1):
+         for k1 in range(-self._nbmax[0], self._nbmax[0] + 1):

This change simplifies the loops by directly iterating over the range of indices, removing the need for conditional assignments inside the loop.


Line range hint 1483-1514: Clarify the usage of the shift parameter in the fft_mesh method.

- return np.fft.ifftshift(mesh) if shift else mesh
+ shifted_mesh = np.fft.ifftshift(mesh) if shift else mesh
+ return shifted_mesh

Refactoring this line to use a temporary variable shifted_mesh improves readability by making the conditional operation more explicit.


Line range hint 1483-1514: Refine the calculation of band properties in eigenvalue_band_properties.

- vbm = -float("inf")
- cbm = float("inf")
+ vbm = np.NINF  # Negative infinity using NumPy
+ cbm = np.inf   # Positive infinity using NumPy

Using NumPy's constants for infinity improves readability and ensures compatibility with NumPy operations.

@janosh janosh requested a review from JaGeo as a code owner April 27, 2024 14:28
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: 4

Out of diff range and nitpick comments (2)
tests/alchemy/test_materials.py (2)

43-45: Consider adding a comment explaining the purpose of the SupercellTransformation in this context.


116-131: The method to_snl and from_snl are used in a way that could be simplified or better documented to explain the transformations and expected outcomes, especially regarding the handling of other_parameters and history.

alt = ts.append_transformation(
t_struct = TransformedStructure(struct, [])
t_struct.append_transformation(SupercellTransformation.from_scaling_factors(2, 1, 1))
alt = t_struct.append_transformation(
Copy link

Choose a reason for hiding this comment

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

The transformation PartialRemoveSpecieTransformation is applied with a magic number 5. Consider defining this as a constant with a descriptive name to improve readability.

Comment on lines +69 to +73
t_struct = TransformedStructure.from_dict(dct)
t_struct.other_parameters["author"] = "Will"
t_struct.append_transformation(SubstitutionTransformation({"Fe": "Mn"}))
assert t_struct.final_structure.reduced_formula == "MnPO4"
assert t_struct.other_parameters == {"author": "Will", "tags": ["test"]}
Copy link

Choose a reason for hiding this comment

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

The method from_dict modifies other_parameters directly after instantiation. This could lead to side effects if other_parameters is expected to be immutable post-creation. Consider using a method to safely update this property.

Comment on lines +80 to +91
t_struct = TransformedStructure(self.structure, trafos)
assert t_struct.final_structure.reduced_formula == "NaMnPO4"
t_struct.undo_last_change()
assert t_struct.final_structure.reduced_formula == "NaFePO4"
t_struct.undo_last_change()
assert t_struct.final_structure.reduced_formula == "LiFePO4"
with pytest.raises(IndexError, match="No more changes to undo"):
ts.undo_last_change()
ts.redo_next_change()
assert ts.final_structure.reduced_formula == "NaFePO4"
ts.redo_next_change()
assert ts.final_structure.reduced_formula == "NaMnPO4"
t_struct.undo_last_change()
t_struct.redo_next_change()
assert t_struct.final_structure.reduced_formula == "NaFePO4"
t_struct.redo_next_change()
assert t_struct.final_structure.reduced_formula == "NaMnPO4"
Copy link

Choose a reason for hiding this comment

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

The methods undo_last_change and redo_next_change are tested sequentially. It's good practice to separate these into distinct test cases to isolate the effects and make the tests more modular.

Comment on lines 568 to 600
def is_float(element) -> bool:
try:
float(element)
return True
except ValueError:
return False

for datum in data:
# Remove all comments
if not datum.startswith(("!", "#", "//")):
pattern = r"\b[^!#//]+" # exclude comments after commands
if matched_pattern := re.findall(pattern, datum):
raw_datum = matched_pattern[0].replace("\t", " ") # handle tab in between and end of command
key_word = raw_datum.strip().split(" ") # extract keyword
key = key_word[0].lower()
if len(key_word) > 1:
# check which type of keyword this is, handle accordingly
if key_word[0].lower() not in [datum2.lower() for datum2 in Lobsterin.LISTKEYWORDS]:
if key_word[0].lower() not in [datum2.lower() for datum2 in Lobsterin.FLOAT_KEYWORDS]:
if key_word[0].lower() not in lobsterin_dict:
lobsterin_dict[key_word[0].lower()] = " ".join(key_word[1:])
if key not in [datum2.lower() for datum2 in Lobsterin.LISTKEYWORDS]:
if key not in [datum2.lower() for datum2 in Lobsterin.FLOAT_KEYWORDS]:
if key not in lobsterin_dict:
lobsterin_dict[key] = " ".join(key_word[1:])
else:
raise ValueError(f"Same keyword {key_word[0].lower()} twice!")
elif key_word[0].lower() not in lobsterin_dict:
lobsterin_dict[key_word[0].lower()] = float(key_word[1])
raise ValueError(f"Same keyword {key} twice!")
elif is_float(key_word[1]) and key not in lobsterin_dict:
lobsterin_dict[key] = float(key_word[1])
else:
raise ValueError(f"Same keyword {key_word[0].lower()} twice!")
elif key_word[0].lower() not in lobsterin_dict:
lobsterin_dict[key_word[0].lower()] = [" ".join(key_word[1:])]
raise ValueError(f"Same keyword {key} twice!")
elif key not in lobsterin_dict:
lobsterin_dict[key] = [" ".join(key_word[1:])]
else:
lobsterin_dict[key_word[0].lower()].append(" ".join(key_word[1:]))
lobsterin_dict[key].append(" ".join(key_word[1:]))
elif len(key_word) > 0:
lobsterin_dict[key_word[0].lower()] = True
lobsterin_dict[key] = True
Copy link

Choose a reason for hiding this comment

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

The method from_file uses a complex series of conditionals to parse the input file. Consider refactoring this to use a more structured approach or a parsing library to improve maintainability and readability.

@janosh
Copy link
Member Author

janosh commented Apr 28, 2024

@JaGeo some of the lobster tests started failing under Python 3.12. i fixed all but two. maybe you know what needs to change here?

____________________ TestLobsterin.test_dict_functionality _____________________

self = <lobster.test_inputs.TestLobsterin testMethod=test_dict_functionality>

    def test_dict_functionality(self):
        for key in ("COHPstartEnergy", "COHPstartEnergy", "COhPstartenergy"):
            start_energy = self.Lobsterin.get(key)
>           assert start_energy == -15.0, f"{start_energy=}"
E           AssertionError: start_energy=None

tests/io/lobster/test_inputs.py:1773: AssertionError
___________________ TestLobsterin.test_read_write_lobsterin ____________________

self = <lobster.test_inputs.TestLobsterin testMethod=test_read_write_lobsterin>

    def test_read_write_lobsterin(self):
        outfile_path = tempfile.mkstemp()[1]
        lobsterin1 = Lobsterin.from_file(f"{TEST_DIR}/lobsterin.1")
        lobsterin1.write_lobsterin(outfile_path)
        lobsterin2 = Lobsterin.from_file(outfile_path)
>       assert lobsterin1.diff(lobsterin2)["Different"] == {}
E       AssertionError

tests/io/lobster/test_inputs.py:1793: AssertionError

@JaGeo
Copy link
Member

JaGeo commented Apr 29, 2024

@janosh : see #3775

@JaGeo
Copy link
Member

JaGeo commented Apr 29, 2024

@janosh could you try this solution for now?
python/cpython#105524 (comment)

…nd modify __getitem__ to get the salient __getitem__ behavior from UserDict
@janosh
Copy link
Member Author

janosh commented Apr 30, 2024

@JaGeo oh right, i forgot about our UserDict discussion in #3757.

if possible, i'd prefer to drop UserDict altogether and make Lobsterin inherit directly from dict. do you remember what exactly the issues it solves are?

@JaGeo
Copy link
Member

JaGeo commented Apr 30, 2024

@janosh We had issues in #3439 that the Userdict solved.

@janosh
Copy link
Member Author

janosh commented Apr 30, 2024

@JaGeo the suggested fix you linked doesn't work (see da1f7c5). i'm still unclear what benefits UserDict offers after having looked at #3439

@JaGeo
Copy link
Member

JaGeo commented Apr 30, 2024

I can try again in the next days. Need to fix other stuff as well. Sorry that this functionality here is such a pain.

@janosh
Copy link
Member Author

janosh commented Apr 30, 2024

the thing making this hard to debug is that i can't repro the issue locally. even on 3.12, everything works for me on macOS. don't understand why this would be linux-specific (if it is)

@JaGeo
Copy link
Member

JaGeo commented Apr 30, 2024

the thing making this hard to debug is that i can't repro the issue locally. even on 3.12, everything works for me on macOS. don't understand why this would be linux-specific (if it is)

Fixes everything except for a temp_path problem. Not sure where this is coming from. will check and see if I can fix it as well. Overwrote the __contains__ with a similar method as __get_item__ before

@JaGeo
Copy link
Member

JaGeo commented Apr 30, 2024

@janosh tests are passing locally now for py 3.12. You might want to check the tmp_dir change. The rest should hopefully be fine now.

@JaGeo
Copy link
Member

JaGeo commented Apr 30, 2024

3.9 and 3.12 tests are passing. 3.11 does not run.

@janosh
Copy link
Member Author

janosh commented May 1, 2024

3.9 and 3.12 tests are passing

perfect! thanks! 👍

3.11 does not run.

that's intentional. no point in wasting Ci budget. usually enough to test the oldest and newest boundaries of supported versions. i'll update the required status checks before merging here to make 3.12 tests instead of 3.11 required

You might want to check the tmp_dir change

done. i refactored the test slightly and deleted the new test files. i assume they were added by accident?

@janosh janosh changed the title Add python 3.12 to officially supported versions and test it in CI Officially support Python 3.12 and test in CI May 1, 2024
@janosh janosh enabled auto-merge (squash) May 1, 2024 00:24
@janosh janosh merged commit c1a610c into master May 1, 2024
22 checks passed
@janosh janosh deleted the py312 branch May 1, 2024 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci Continuous integration compatability Concerning pymatgen compatibility with different OS, Python versions, numpy versions, etc. pkg Package health and distribution related stuff
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants