Skip to content

Commit 96fe48f

Browse files
committed
Fix flatten name bug
1 parent 7a14138 commit 96fe48f

File tree

10 files changed

+151
-46
lines changed

10 files changed

+151
-46
lines changed

pybeeryaml/__init__.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,22 @@
2828
from pybeeryaml.mash import MashProfile, MashStep
2929

3030

31-
__all__ = ["Recipe", "Hop", "Yeast", "Misc", "Water", "Style", "Fermentable",
32-
"MashProfile", "MashStep", "__version__", "__author__", "__url__",
33-
"__email__"]
34-
__version__ = "1.0"
31+
__all__ = [
32+
"Recipe",
33+
"Hop",
34+
"Yeast",
35+
"Misc",
36+
"Water",
37+
"Style",
38+
"Fermentable",
39+
"MashProfile",
40+
"MashStep",
41+
"__version__",
42+
"__author__",
43+
"__url__",
44+
"__email__",
45+
]
46+
__version__ = "1.1"
3547
__author__ = "TROUVERIE Joachim"
3648
__email__ = "joachim.trouverie@linoame.fr"
3749
__url__ = "https://github.com/j0ack/pybeeryaml"

pybeeryaml/fermentable.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
class Fermentable(BeerComponent):
25+
"""Fermentable class"""
2526

2627
def __init__(self, name, type, amount, color, beeryaml_yield, **kwargs):
2728
super().__init__()

pybeeryaml/hop.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
class Hop(BeerComponent):
25+
"""Hop class"""
2526

2627
def __init__(self, name, alpha, amount, use, time, **kwargs):
2728
super().__init__()

pybeeryaml/mash.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
class MashProfile(BeerComponent):
25+
"""Mash profile class"""
2526

2627
def __init__(self, name, grain_temp, **kwargs):
2728
super().__init__("mash")
@@ -34,8 +35,7 @@ def __init__(self, name, grain_temp, **kwargs):
3435
def to_yaml(self) -> dict:
3536
"""Convert object to YAML dict"""
3637
output = {
37-
k: v for k, v in self.__dict__.items()
38-
if not k.startswith("_")
38+
k: v for k, v in self.__dict__.items() if not k.startswith("_")
3939
}
4040
output["mash_steps"] = {}
4141
for step in getattr(self, "mash_steps", []):
@@ -45,6 +45,7 @@ def to_yaml(self) -> dict:
4545

4646

4747
class MashStep(BeerComponent):
48+
"""Mash step class"""
4849

4950
def __init__(self, name, type, step_time, step_temp, **kwargs):
5051
super().__init__("mash_step")

pybeeryaml/misc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
class Misc(BeerComponent):
25+
"""Misc class"""
2526

2627
def __init__(self, name, type, use, time, amount, **kwargs):
2728
super().__init__()

pybeeryaml/recipe.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,34 @@
1818
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1919

2020

21-
from yaml import safe_load
2221
from keyword import iskeyword
22+
23+
from yaml import safe_load
24+
25+
from pybeeryaml.fermentable import Fermentable
2326
from pybeeryaml.hop import Hop
24-
from pybeeryaml.yeast import Yeast
27+
from pybeeryaml.mash import MashProfile, MashStep
2528
from pybeeryaml.meta import BeerComponent
2629
from pybeeryaml.misc import Misc
27-
from pybeeryaml.water import Water
2830
from pybeeryaml.style import Style
29-
from pybeeryaml.fermentable import Fermentable
30-
from pybeeryaml.mash import MashProfile, MashStep
31+
from pybeeryaml.water import Water
32+
from pybeeryaml.yeast import Yeast
3133

3234

3335
class Recipe(BeerComponent):
34-
"""Recipe model
35-
36-
:param data: dict recipe data
37-
"""
38-
39-
def __init__(self, name, type, style, brewer, batch_size, boil_size,
40-
boil_time, **data: dict):
36+
"""Recipe model"""
37+
38+
def __init__(
39+
self,
40+
name,
41+
type,
42+
style,
43+
brewer,
44+
batch_size,
45+
boil_size,
46+
boil_time,
47+
**data: dict
48+
):
4149
super().__init__()
4250
self.name = name
4351
self.type = type
@@ -52,41 +60,40 @@ def __init__(self, name, type, style, brewer, batch_size, boil_size,
5260
if isinstance(self.style, dict):
5361
self.style = Style(**data["style"])
5462

55-
hops = self.flatten(data.get("hops", {}))
63+
hops = Recipe.flatten(data.get("hops", {}))
5664
self.hops = [Hop(**hdata) for hdata in hops]
5765

58-
yeasts = self.flatten(data.get("yeasts", {}))
66+
yeasts = Recipe.flatten(data.get("yeasts", {}))
5967
self.yeasts = [Yeast(**ydata) for ydata in yeasts]
6068

61-
ferments = self.flatten(data.get("fermentables", {}))
69+
ferments = Recipe.flatten(data.get("fermentables", {}))
6270
self.fermentables = [Fermentable(**fdata) for fdata in ferments]
6371

64-
miscs = self.flatten(data.get("miscs", {}))
72+
miscs = Recipe.flatten(data.get("miscs", {}))
6573
self.miscs = [Misc(**mdata) for mdata in miscs]
6674

6775
profile = data.get("mash", {"name": "mash", "grain_temp": 25})
6876
self.mash = MashProfile(**profile)
6977

7078
steps = []
7179
if hasattr(self.mash, "mash_steps"):
72-
msdata = self.flatten(self.mash.mash_steps)
80+
msdata = Recipe.flatten(self.mash.mash_steps)
7381
for mash_step in msdata:
7482
steps.append(MashStep(**mash_step))
7583

7684
self.mash.mash_steps = steps
7785

78-
waters = self.flatten(data.get("waters", {}))
86+
waters = Recipe.flatten(data.get("waters", {}))
7987
self.waters = [Water(wdata) for wdata in waters]
8088

81-
def flatten(self, data: dict) -> list:
82-
"""Flatten yaml dict
83-
84-
:param data: YAML dict
85-
"""
89+
@classmethod
90+
def flatten(cls, data: dict) -> list:
91+
"""Flatten yaml dict"""
8692
output = []
8793
for key, value in data.items():
8894
if isinstance(value, dict):
89-
value["name"] = key
95+
if "name" not in value:
96+
value["name"] = key
9097

9198
for vkey, vvalue in value.items():
9299
if iskeyword(vkey):
@@ -124,10 +131,7 @@ def to_yaml(self) -> dict:
124131

125132
@classmethod
126133
def from_file(cls, filepath: str):
127-
"""Create recipe from YAML file
128-
129-
:param filepath: YAML file containing recipe data
130-
"""
134+
"""Create recipe from YAML file"""
131135
with open(filepath, "r") as fi:
132136
data = safe_load(fi.read())
133137
return cls(**data)

pybeeryaml/style.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,26 @@
2222

2323

2424
class Style(BeerComponent):
25-
26-
def __init__(self, name, category, category_number, style_letter,
27-
style_guide, type, og_min, og_max, fg_min, fg_max, ibu_min,
28-
ibu_max, color_min, color_max, **kwargs):
25+
"""Style class"""
26+
27+
def __init__(
28+
self,
29+
name,
30+
category,
31+
category_number,
32+
style_letter,
33+
style_guide,
34+
type,
35+
og_min,
36+
og_max,
37+
fg_min,
38+
fg_max,
39+
ibu_min,
40+
ibu_max,
41+
color_min,
42+
color_max,
43+
**kwargs
44+
):
2945
super().__init__()
3046

3147
self.name = name

pybeeryaml/water.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,21 @@
2222

2323

2424
class Water(BeerComponent):
25-
26-
def __init__(self, name, amount, calcium, bicarbonate, sulfate, chloride,
27-
sodium, magnesium, ph, **kwargs):
25+
"""Water class"""
26+
27+
def __init__(
28+
self,
29+
name,
30+
amount,
31+
calcium,
32+
bicarbonate,
33+
sulfate,
34+
chloride,
35+
sodium,
36+
magnesium,
37+
ph,
38+
**kwargs
39+
):
2840
super().__init__()
2941

3042
self.name = name

pybeeryaml/yeast.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
class Yeast(BeerComponent):
25+
"""Yeast class"""
2526

2627
def __init__(self, name, type, form, amount, **kwargs):
2728
super().__init__()

tests/test_recipe.py

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020

2121
import os.path
2222
import xml.etree.ElementTree as ET
23-
from yaml import safe_load
2423
from copy import copy
24+
25+
from yaml import safe_load
26+
2527
from pybeeryaml import Recipe
2628

2729

@@ -33,10 +35,9 @@ def xmltodict(data: ET.Element, root=True) -> dict:
3335
tagname = child.tag
3436
if tagname in output:
3537
tagname = "{}{}".format(
36-
child.tag, len([
37-
k for k in output.keys()
38-
if k.startswith(child.tag)
39-
]))
38+
child.tag,
39+
len([k for k in output.keys() if k.startswith(child.tag)]),
40+
)
4041
output[tagname] = xmltodict(child, False)
4142
else:
4243
output[child.tag] = child.text
@@ -175,3 +176,58 @@ def remove_keys(data):
175176
data = safe_load(fi.read())
176177

177178
assert data == remove_keys(recipe.to_yaml())
179+
180+
181+
def test_flatten():
182+
data = {
183+
"pale ale": {
184+
"type": "Grain",
185+
"amount": "4500g",
186+
"color": "5.9EBC",
187+
"yield": "78.0",
188+
},
189+
"caramel/crystal": {
190+
"type": "Grain",
191+
"amount": "350g",
192+
"color": "120EBC",
193+
"yield": "74.0",
194+
},
195+
}
196+
expected = [
197+
{
198+
"name": "pale ale",
199+
"type": "Grain",
200+
"amount": "4500g",
201+
"color": "5.9EBC",
202+
"beeryaml_yield": "78.0",
203+
},
204+
{
205+
"name": "caramel/crystal",
206+
"type": "Grain",
207+
"amount": "350g",
208+
"color": "120EBC",
209+
"beeryaml_yield": "74.0",
210+
},
211+
]
212+
assert Recipe.flatten(data) == expected
213+
214+
215+
def test_flatten_with_same_names():
216+
data = {
217+
"first hop": {
218+
"name": "cascade",
219+
"amount": "20g",
220+
"use": "boil",
221+
"time": "10min",
222+
"alpha": "7.5%",
223+
},
224+
"second hop": {
225+
"name": "cascade",
226+
"amount": "20g",
227+
"use": "boil",
228+
"time": "20min",
229+
"alpha": "7.5%",
230+
},
231+
}
232+
assert len(Recipe.flatten(data)) == len(data)
233+
assert Recipe.flatten(data) == list(data.values())

0 commit comments

Comments
 (0)