Skip to content

Commit

Permalink
relocate duplicate check to setter so that both from str and dict wou…
Browse files Browse the repository at this point in the history
…ld be checked
  • Loading branch information
DanielYang59 committed Oct 19, 2024
1 parent 259124d commit 96ad945
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 12 deletions.
20 changes: 9 additions & 11 deletions src/pymatgen/io/vasp/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import re
import subprocess
import warnings
from collections import Counter, UserDict
from collections import UserDict
from enum import Enum, unique
from glob import glob
from hashlib import sha256
Expand Down Expand Up @@ -724,17 +724,9 @@ def __init__(self, params: dict[str, Any] | None = None) -> None:
Args:
params (dict): INCAR parameters as a dictionary.
Warnings:
BadIncarWarning: If there are duplicate in keys (case insensitive).
"""
params = params or {}

# Check for case-insensitive duplicate keys
key_counter = Counter(key.strip().upper() for key in params)
if duplicates := [key for key, count in key_counter.items() if count > 1]:
warnings.warn(f"Duplicate keys found (case-insensitive): {duplicates}", BadIncarWarning, stacklevel=2)

# If INCAR contains vector-like MAGMOMS given as a list
# of floats, convert to a list of lists
if (params.get("MAGMOM") and isinstance(params["MAGMOM"][0], int | float)) and (
Expand All @@ -753,9 +745,15 @@ def __setitem__(self, key: str, val: Any) -> None:
- Clean the parameter and val by stripping leading
and trailing white spaces.
- Cast keys to upper case.
Warnings:
BadIncarWarning: If there are duplicate in keys (case insensitive).
"""
key = key.strip().upper()
# Cast float/int to str and feed into proc_val to clean up their types
# Check for case-insensitive duplicate keys
if (key := key.strip().upper()) in self:
warnings.warn(f"Duplicate key found (case-insensitive): {key}", BadIncarWarning, stacklevel=2)

# Cast float/int to str such that proc_val would clean up their types
val = self.proc_val(key, str(val)) if isinstance(val, str | float | int) else val
super().__setitem__(key, val)

Expand Down
6 changes: 5 additions & 1 deletion tests/io/vasp/test_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,9 +552,13 @@ def test_check_for_duplicate(self):
ENCUT = 500
"""

with pytest.warns(BadIncarWarning, match=re.escape("Duplicate keys found (case-insensitive): ['ENCUT']")):
with pytest.warns(BadIncarWarning, match=re.escape("Duplicate key found (case-insensitive): ENCUT")):
Incar.from_str(incar_str)

incar_dict = {"ALGO": "Fast", "algo": "fast"}
with pytest.warns(BadIncarWarning, match=re.escape("Duplicate key found (case-insensitive): ALGO")):
Incar.from_dict(incar_dict)

def test_key_case_insensitive(self):
"""Verify that keys are case-insensitive by internally converting
all keys to upper case. This includes operations such as:
Expand Down

0 comments on commit 96ad945

Please sign in to comment.