Skip to content

Commit f345f2f

Browse files
committed
test nested square bracket in formula strings
add ref to GH issue in _parse_formula()
1 parent 9604d75 commit f345f2f

File tree

8 files changed

+51
-45
lines changed

8 files changed

+51
-45
lines changed

pymatgen/analysis/chempot_diagram.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,11 @@ def _get_min_entries_and_el_refs(
548548
el_refs = {}
549549
min_entries = []
550550

551-
for c, g in groupby(entries, key=lambda e: e.composition.reduced_formula):
552-
c = Composition(c)
553-
group = list(g)
551+
for formula, group in groupby(entries, key=lambda e: e.composition.reduced_formula):
552+
comp = Composition(formula)
554553
min_entry = min(group, key=lambda e: e.energy_per_atom)
555-
if c.is_element:
556-
el_refs[c.elements[0]] = min_entry
554+
if comp.is_element:
555+
el_refs[comp.elements[0]] = min_entry
557556
min_entries.append(min_entry)
558557

559558
return min_entries, el_refs

pymatgen/core/composition.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ def _parse_formula(self, formula: str, strict: bool = True) -> dict[str, float]:
544544
raise ValueError(f"Invalid {formula=}")
545545
# for Metallofullerene like "Y3N@C80"
546546
formula = formula.replace("@", "")
547+
# square brackets are used in formulas to denote coordination complexes (gh-3583)
547548
formula = formula.replace("[", "(")
548549
formula = formula.replace("]", ")")
549550

pymatgen/ext/matproj_legacy.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,12 +1633,12 @@ def parse_tok(t):
16331633
parts = re.split(r"(\*|\{.*\})", t)
16341634
parts = [parse_sym(s) for s in parts if s != ""]
16351635
for f in itertools.product(*parts):
1636-
c = Composition("".join(f))
1637-
if len(c) == n_elements:
1636+
comp = Composition("".join(f))
1637+
if len(comp) == n_elements:
16381638
# Check for valid Elements in keys.
1639-
for e in c:
1640-
Element(e.symbol)
1641-
all_formulas.add(c.reduced_formula)
1639+
for elem in comp:
1640+
Element(elem.symbol)
1641+
all_formulas.add(comp.reduced_formula)
16421642
return {"pretty_formula": {"$in": list(all_formulas)}}
16431643

16441644
if len(tokens) == 1:

tests/analysis/structure_prediction/test_substitution_probability.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ def test_prediction(self):
6969
assert result["probability"] == approx(cond_prob)
7070
assert set(result["substitutions"].values()) != {"Na+", "Cl-"}
7171

72-
c = Composition({"Ag2+": 1, "Cl-": 2})
73-
result = sp.composition_prediction(c, to_this_composition=True)[2]
74-
assert set(result["substitutions"].values()) == set(c.elements)
75-
result = sp.composition_prediction(c, to_this_composition=False)[2]
76-
assert set(result["substitutions"]) == set(c.elements)
72+
comp = Composition({"Ag2+": 1, "Cl-": 2})
73+
result = sp.composition_prediction(comp, to_this_composition=True)[2]
74+
assert set(result["substitutions"].values()) == set(comp.elements)
75+
result = sp.composition_prediction(comp, to_this_composition=False)[2]
76+
assert set(result["substitutions"]) == set(comp.elements)

tests/analysis/structure_prediction/test_substitutor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ def test_substitutor(self):
2626
s_list = [Species("O", -2), Species("Li", 1)]
2727
subs = self.s.pred_from_list(s_list)
2828
assert len(subs) == 4, "incorrect number of substitutions"
29-
c = Composition({"O2-": 1, "Li1+": 2})
30-
subs = self.s.pred_from_comp(c)
29+
comp = Composition({"O2-": 1, "Li1+": 2})
30+
subs = self.s.pred_from_comp(comp)
3131
assert len(subs) == 4, "incorrect number of substitutions"
3232

3333
structures = [{"structure": PymatgenTest.get_structure("Li2O"), "id": "pmgtest"}]

tests/core/test_composition.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,16 @@ def test_getitem(self):
115115
assert comp["O"] == 4
116116

117117
def test_hill_formula(self):
118-
c = Composition("CaCO3")
119-
assert c.hill_formula == "C Ca O3"
120-
c = Composition("C2H5OH")
121-
assert c.hill_formula == "C2 H6 O"
118+
comp = Composition("CaCO3")
119+
assert comp.hill_formula == "C Ca O3"
120+
comp = Composition("C2H5OH")
121+
assert comp.hill_formula == "C2 H6 O"
122122
# A test case with both C and H, but not one after another (mp-1228185)
123-
c = Composition("Ga8 As16 H102 C32 S36 O3")
124-
assert c.hill_formula == "C32 H102 As16 Ga8 O3 S36"
123+
comp = Composition("Ga8 As16 H102 C32 S36 O3")
124+
assert comp.hill_formula == "C32 H102 As16 Ga8 O3 S36"
125125
# A test case with H but no C
126-
c = Composition("Ga8 As16 H102 S36 O3")
127-
assert c.hill_formula == "As16 Ga8 H102 O3 S36"
126+
comp = Composition("Ga8 As16 H102 S36 O3")
127+
assert comp.hill_formula == "As16 Ga8 H102 O3 S36"
128128

129129
def test_init(self):
130130
with pytest.raises(ValueError, match="Amounts in Composition cannot be negative"):
@@ -138,8 +138,8 @@ def test_init(self):
138138
assert Composition({1: 2, 8: 1}).formula == "H2 O1"
139139
assert Composition(Na=2, O=1).formula == "Na2 O1"
140140

141-
c = Composition({"S": Composition.amount_tolerance / 2})
142-
assert len(c.elements) == 0
141+
comp = Composition({"S": Composition.amount_tolerance / 2})
142+
assert len(comp.elements) == 0
143143

144144
def test_str_and_repr(self):
145145
test_cases = [
@@ -838,5 +838,11 @@ def test_math(self):
838838
assert fe_pot - o_pot == pots - o_pot - o_pot
839839

840840
def test_square_brackets(self):
841-
c = Composition("(NH4)2[FeCl5(H2O)]")
842-
assert str(c) == "N2 H10 Fe1 Cl5 O1"
841+
comp = Composition("(NH4)2[FeCl5(H2O)]")
842+
assert str(comp) == "N2 H10 Fe1 Cl5 O1"
843+
# test nested brackets
844+
comp = Composition("[[[[Fe]]]]")
845+
assert str(comp) == "Fe1"
846+
# test nested brackets with charge
847+
comp = Composition("[N[Fe]2]2")
848+
assert str(comp) == "N2 Fe4"

tests/core/test_ion.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ def setUp(self):
2323
self.comp.append(Ion.from_formula("NaOH(aq)"))
2424

2525
def test_init(self):
26-
c = Composition({"Fe": 4, "O": 16, "P": 4})
26+
comp = Composition({"Fe": 4, "O": 16, "P": 4})
2727
charge = 4
28-
assert Ion(c, charge).formula == "Fe4 P4 O16 +4"
29-
f = {1: 1, 8: 1}
28+
assert Ion(comp, charge).formula == "Fe4 P4 O16 +4"
29+
formula_dict = {1: 1, 8: 1}
3030
charge = -1
31-
assert Ion(Composition(f), charge).formula == "H1 O1 -1"
31+
assert Ion(Composition(formula_dict), charge).formula == "H1 O1 -1"
3232
assert Ion(Composition(S=2, O=3), -2).formula == "S2 O3 -2"
3333

3434
def test_charge_from_formula(self):

tests/entries/test_compatibility.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -461,14 +461,14 @@ def test_get_corrections_dict(self):
461461
],
462462
},
463463
)
464-
c = compat.get_corrections_dict(entry)[0]
465-
assert c["MP Anion Correction"] == approx(-2.10687)
466-
assert c["MP Advanced Correction"] == approx(-5.466)
464+
comp = compat.get_corrections_dict(entry)[0]
465+
assert comp["MP Anion Correction"] == approx(-2.10687)
466+
assert comp["MP Advanced Correction"] == approx(-5.466)
467467

468468
entry.parameters["is_hubbard"] = False
469469
del entry.parameters["hubbards"]
470-
c = gga_compat.get_corrections_dict(entry)[0]
471-
assert "MP Advanced Correction" not in c
470+
comp = gga_compat.get_corrections_dict(entry)[0]
471+
assert "MP Advanced Correction" not in comp
472472

473473
def test_process_entries(self):
474474
entries = self.compat.process_entries([self.entry1, self.entry2, self.entry3, self.entry4])
@@ -936,12 +936,12 @@ def test_energy_adjustments(self):
936936
}
937937
entry = ComputedEntry.from_dict(entry)
938938

939-
c = compat.process_entry(entry)
940-
assert "MP2020 anion correction (oxide)" in [ea.name for ea in c.energy_adjustments]
941-
assert "MP2020 GGA/GGA+U mixing correction (Fe)" in [ea.name for ea in c.energy_adjustments]
942-
assert "MP2020 GGA/GGA+U mixing correction (Co)" in [ea.name for ea in c.energy_adjustments]
939+
processed = compat.process_entry(entry)
940+
assert "MP2020 anion correction (oxide)" in [ea.name for ea in processed.energy_adjustments]
941+
assert "MP2020 GGA/GGA+U mixing correction (Fe)" in [ea.name for ea in processed.energy_adjustments]
942+
assert "MP2020 GGA/GGA+U mixing correction (Co)" in [ea.name for ea in processed.energy_adjustments]
943943

944-
for ea in c.energy_adjustments:
944+
for ea in processed.energy_adjustments:
945945
if ea.name == "MP2020 GGA/GGA+U mixing correction (Fe)":
946946
assert ea.value == approx(-2.256 * 4)
947947
assert ea.uncertainty == approx(0.0101 * 4)
@@ -954,8 +954,8 @@ def test_energy_adjustments(self):
954954

955955
entry.parameters["is_hubbard"] = False
956956
del entry.parameters["hubbards"]
957-
c = gga_compat.process_entry(entry)
958-
assert "MP2020 GGA/GGA+U mixing correction" not in [ea.name for ea in c.energy_adjustments]
957+
processed = gga_compat.process_entry(entry)
958+
assert "MP2020 GGA/GGA+U mixing correction" not in [ea.name for ea in processed.energy_adjustments]
959959

960960
def test_process_entries(self):
961961
entries = self.compat.process_entries([self.entry1, self.entry2, self.entry3])

0 commit comments

Comments
 (0)