Example #1
0
def main():
    # Define Grains
    pale = Grain(u"Pale Malt (2 Row) US", color=1.8, ppg=37)
    pale_add = GrainAddition(pale, weight=13.96)
    crystal = Grain(u"Caramel/Crystal Malt - 20L", color=20.0, ppg=35)
    crystal_add = GrainAddition(crystal, weight=0.78)
    grain_additions = [pale_add, crystal_add]

    # Define Hops
    centennial = Hop(u"Centennial", percent_alpha_acids=0.14)
    centennial_add = HopAddition(centennial, weight=0.57, boil_time=60.0)
    cascade = Hop(u"Cascade (US)", percent_alpha_acids=0.07)
    cascade_add = HopAddition(cascade, weight=0.76, boil_time=5.0)
    hop_additions = [centennial_add, cascade_add]

    # Define Yeast
    yeast = Yeast(u"Wyeast 1056")

    # Define Recipe
    beer = Recipe(
        u"pale ale",
        grain_additions=grain_additions,
        hop_additions=hop_additions,
        yeast=yeast,
        brew_house_yield=0.70,  # %
        start_volume=7.0,  # G
        final_volume=5.0,  # G
    )
    print(beer.format())
Example #2
0
 def setUp(self):
     # A special recipe is needed since the loaders only return
     # pre-chosen additions
     self.recipe = Recipe(
         name=u"pale ale",
         grain_additions=[pale_add, pale_add],
         hop_additions=[cascade_add, cascade_add],
         yeast=yeast,
         brew_house_yield=0.70,  # %
         start_volume=7.0,  # G
         final_volume=5.0,  # G
     )
     self.recipe_data = self.recipe.to_dict()
     self.cereals_loader = CerealsLoader("./")
     self.hops_loader = HopsLoader("./")
     self.yeast_loader = YeastLoader("./")
Example #3
0
class TestRecipeParser(unittest.TestCase):

    def setUp(self):
        # A special recipe is needed since the loaders only return
        # pre-chosen additions
        self.recipe = Recipe(name=u'pale ale',
                             grain_additions=[pale_add, pale_add],
                             hop_additions=[cascade_add, cascade_add],
                             yeast=yeast,
                             percent_brew_house_yield=0.70,  # %
                             start_volume=7.0,  # G
                             final_volume=5.0,  # G
                             )
        self.recipe_data = self.recipe.to_dict()
        self.cereals_loader = CerealsLoader('./')
        self.hops_loader = HopsLoader('./')
        self.yeast_loader = YeastLoader('./')

    def test_parse_recipe(self):
        out = parse_recipe(self.recipe_data, None,
                           cereals_loader=self.cereals_loader,
                           hops_loader=self.hops_loader,
                           yeast_loader=self.yeast_loader)
        self.assertEquals(out, self.recipe)

    def test_parse_recipe_default_loader(self):
        out = parse_recipe(self.recipe_data, DataLoader('./'),
                           cereals_dir_suffix='/',
                           hops_dir_suffix='/',
                           yeast_dir_suffix='/')
        self.assertEquals(out, self.recipe)
Example #4
0
def main():
    # Define Grains
    pale = Grain(u"Pale Malt (2 Row) US", color=1.8, ppg=37)
    rye = Grain(u"Rye Malt", color=3.5, ppg=38)
    crystal = Grain(u"Caramel/Crystal - 60L", color=60, ppg=34)
    carapils = Grain(u"Carapils/Dextrine Malt", color=1.8, ppg=33)
    flaked_wheat = Grain(u"Flaked Wheat", color=2, ppg=34)

    pale_add = GrainAddition(pale, weight=13.96)
    rye_add = GrainAddition(rye, weight=3.0)
    crystal_add = GrainAddition(crystal, weight=1.25)
    carapils_add = GrainAddition(carapils, weight=0.5)
    flaked_wheat_add = GrainAddition(flaked_wheat, weight=0.5)

    grain_additions = [
        pale_add, rye_add, crystal_add, carapils_add, flaked_wheat_add
    ]

    # Define Hops
    mt_hood = Hop(u"Mount Hood", percent_alpha_acids=0.048)
    columbus = Hop(u"Columbus", percent_alpha_acids=0.15)

    mt_hood_add_01 = HopAddition(mt_hood, weight=1.0, boil_time=60.0)
    columbus_add_01 = HopAddition(columbus, weight=1.0, boil_time=60.0)
    mt_hood_add_02 = HopAddition(mt_hood, weight=0.5, boil_time=30.0)
    mt_hood_add_03 = HopAddition(mt_hood, weight=1.5, boil_time=1.0)
    columbus_add_02 = HopAddition(columbus, weight=1.0, boil_time=0.0)

    hop_additions = [
        mt_hood_add_01, columbus_add_01, mt_hood_add_02, mt_hood_add_03,
        columbus_add_02
    ]

    # Define Yeast
    yeast = Yeast(u"Wyeast 1450", percent_attenuation=0.75)

    # Define Recipe
    beer = Recipe(
        u"pale ale",
        grain_additions=grain_additions,
        hop_additions=hop_additions,
        yeast=yeast,
        brew_house_yield=0.70,  # %
        start_volume=7.5,  # G
        final_volume=5.5,  # G
    )
    print(beer.format())
Example #5
0
def main():
    # Define Grains
    pale = Grain(u'Pale Malt (2 Row) US',
                 color=1.8,
                 ppg=37)
    pale_add = GrainAddition(pale,
                             weight=13.96)
    crystal = Grain(u'Caramel/Crystal Malt - 20L',
                    color=20.0,
                    ppg=35)
    crystal_add = GrainAddition(crystal,
                                weight=0.78)
    grain_additions = [pale_add, crystal_add]

    # Define Hops
    centennial = Hop(u'Centennial',
                     percent_alpha_acids=0.14)
    centennial_add = HopAddition(centennial,
                                 weight=0.57,
                                 boil_time=60.0)
    cascade = Hop(u'Cascade (US)',
                  percent_alpha_acids=0.07)
    cascade_add = HopAddition(cascade,
                              weight=0.76,
                              boil_time=5.0)
    hop_additions = [centennial_add, cascade_add]

    # Define Yeast
    yeast = Yeast(u'Wyeast 1056')

    # Define Recipe
    beer = Recipe(u'pale ale',
                  grain_additions=grain_additions,
                  hop_additions=hop_additions,
                  yeast=yeast,
                  percent_brew_house_yield=0.70,  # %
                  start_volume=7.0,  # G
                  final_volume=5.0,  # G
                  )
    print(beer.format())
Example #6
0
 def test_hops_units_mismatch_raises(self):
     hop_additions = [h.change_units() for h in self.hop_additions]
     with self.assertRaises(RecipeException) as ctx:
         Recipe(
             name=u"pale ale",
             grain_additions=self.grain_additions,
             hop_additions=hop_additions,
             yeast=self.yeast,
         )
     self.assertEquals(
         str(ctx.exception),
         u"pale ale: Hop addition units must be in 'imperial' not 'metric'",
     )  # noqa
Example #7
0
 def test_recipe_matches(self):
     pale_add = GrainAddition(pale, weight=8.69)
     crystal_add = GrainAddition(crystal, weight=1.02)
     pale_ale = Recipe(
         name=u"pale ale",
         grain_additions=[pale_add, crystal_add],
         hop_additions=hop_additions,
         yeast=yeast,
         brew_house_yield=0.70,
         start_volume=7.0,
         final_volume=5.0,
     )
     out = self.style.recipe_matches(pale_ale)
     self.assertTrue(out)
Example #8
0
 def test_unicode(self):
     recipe = Recipe(
         name=u"Kölsch Ale",
         grain_additions=grain_additions,
         hop_additions=hop_additions,
         yeast=yeast,
         brew_house_yield=0.70,
         start_volume=7.0,
         final_volume=5.0,
     )
     out = str(recipe)
     if sys.version_info[0] >= 3:
         self.assertEquals(out, u"Kölsch Ale")
     else:
         self.assertEquals(out, u"Kölsch Ale".encode("utf8"))
Example #9
0
    def test_get_total_points_dme(self):
        pale_dme_add = GrainAddition(pale_dme,
                                     weight=11.74,
                                     grain_type=GRAIN_TYPE_DME,
                                     units=IMPERIAL_UNITS)
        recipe = Recipe(
            u"dme",
            grain_additions=[pale_dme_add],
            hop_additions=self.hop_additions,
            yeast=self.yeast,
            units=IMPERIAL_UNITS,
        )

        out = recipe.get_total_points()
        self.assertEquals(round(out, 1), 516.6)
Example #10
0
 def setUp(self):
     # A special recipe is needed since the loaders only return
     # pre-chosen additions
     self.recipe = Recipe(name=u'pale ale',
                          grain_additions=[pale_add, pale_add],
                          hop_additions=[cascade_add, cascade_add],
                          yeast=yeast,
                          percent_brew_house_yield=0.70,  # %
                          start_volume=7.0,  # G
                          final_volume=5.0,  # G
                          )
     self.recipe_data = self.recipe.to_dict()
     self.cereals_loader = CerealsLoader('./')
     self.hops_loader = HopsLoader('./')
     self.yeast_loader = YeastLoader('./')
Example #11
0
    def test_get_grain_add_dry_weight_lme(self):
        pale_lme_add = GrainAddition(pale_lme,
                                     weight=14.35,
                                     grain_type=GRAIN_TYPE_LME,
                                     units=IMPERIAL_UNITS)
        recipe = Recipe(
            u"lme",
            grain_additions=[pale_lme_add],
            hop_additions=self.hop_additions,
            yeast=self.yeast,
            units=IMPERIAL_UNITS,
        )

        out = recipe.get_grain_add_dry_weight(pale_lme_add)
        self.assertEquals(round(out, 2), 11.74)
Example #12
0
 def test_recipe_errors_none(self):
     pale_add = GrainAddition(pale, weight=8.69)
     crystal_add = GrainAddition(crystal, weight=1.02)
     pale_ale = Recipe(
         name=u"pale ale",
         grain_additions=[pale_add, crystal_add],
         hop_additions=hop_additions,
         yeast=yeast,
         brew_house_yield=0.70,
         start_volume=7.0,
         final_volume=5.0,
     )
     out = self.style.recipe_errors(pale_ale)
     expected = []
     self.assertEquals(out, expected)
Example #13
0
    def test_get_grain_add_cereal_weight_dme(self):
        pale_dme_add = GrainAddition(pale_dme,
                                     weight=11.74,
                                     grain_type=GRAIN_TYPE_DME,
                                     units=IMPERIAL_UNITS)
        recipe = Recipe(
            u"dme",
            grain_additions=[pale_dme_add],
            hop_additions=self.hop_additions,
            yeast=self.yeast,
            units=IMPERIAL_UNITS,
        )

        out = recipe.get_grain_add_cereal_weight(pale_dme_add, ppg=ppg_pale)
        self.assertEquals(round(out, 2), 13.96)
Example #14
0
class TestRecipeParser(unittest.TestCase):
    def setUp(self):
        # A special recipe is needed since the loaders only return
        # pre-chosen additions
        self.recipe = Recipe(
            name=u"pale ale",
            grain_additions=[pale_add, pale_add],
            hop_additions=[cascade_add, cascade_add],
            yeast=yeast,
            brew_house_yield=0.70,  # %
            start_volume=7.0,  # G
            final_volume=5.0,  # G
        )
        self.recipe_data = self.recipe.to_dict()
        self.cereals_loader = CerealsLoader("./")
        self.hops_loader = HopsLoader("./")
        self.yeast_loader = YeastLoader("./")

    def test_parse_recipe(self):
        out = parse_recipe(
            self.recipe_data,
            None,
            cereals_loader=self.cereals_loader,
            hops_loader=self.hops_loader,
            yeast_loader=self.yeast_loader,
        )
        self.assertEquals(out, self.recipe)

    def test_parse_recipe_default_loader(self):
        out = parse_recipe(
            self.recipe_data,
            DataLoader("./"),
            cereals_dir_suffix="/",
            hops_dir_suffix="/",
            yeast_dir_suffix="/",
        )
        self.assertEquals(out, self.recipe)
Example #15
0
 def test_ne_hop_additions(self):
     recipe1 = Recipe(u"pale ale", hop_additions=hop_additions)
     recipe2 = Recipe(u"pale ale", hop_additions=[hop_additions[0]])
     self.assertTrue(recipe1 != recipe2)
Example #16
0
 def test_validate(self):
     data = self.recipe.to_dict()
     Recipe.validate(data)
def main():

    # Constants
    name = u"Sagefight Imperial IPA"
    brew_house_yield = 0.70
    start_volume = 4.0
    final_volume = 5.0

    # Grains
    pale = Grain(u"pale 2-row", color=2.0, ppg=36.0)
    crystal = Grain(u"crystal 20", color=2.0, ppg=35.0)
    munich = Grain(u"munich", color=9.0, ppg=37.0)
    grain_list = [pale, crystal, munich]

    # Hops
    # Mild, herbaceous, elements of resin
    millennium = Hop(name=u"millennium", percent_alpha_acids=0.14)
    # Spicy, earthy, and lightly floral
    bravo = Hop(name=u"bravo", percent_alpha_acids=0.15)
    # Orange Citrus Flavor
    amarillo = Hop(name=u"amarillo", percent_alpha_acids=0.09)
    # Floral, with elements of citrus and notes of grapefruit  # noqa
    centennial = Hop(name=u"centennial", percent_alpha_acids=0.10)

    hop_list = [millennium, bravo, amarillo, centennial]
    hop_list = hop_list[:3]

    # Define Recipe Builder
    builder = RecipeBuilder(
        name=name,
        grain_list=grain_list,
        hop_list=hop_list,
        target_ibu=75.0,
        target_og=1.075,
        brew_house_yield=brew_house_yield,
        start_volume=start_volume,
        final_volume=final_volume,
    )

    # Get grain additions
    grain_percentages = [0.80, 0.10, 0.10]
    grain_additions = builder.get_grain_additions(grain_percentages)

    # Get hop additions
    hop_percentages = [0.50, 0.30, 0.20]
    hop_boil_times = [90, 15, 5]
    hop_additions = builder.get_hop_additions(hop_percentages, hop_boil_times)

    # Determine desired attenuation
    desired_attenuation = builder.get_yeast_attenuation(0.08)
    yeast = Yeast("English Ale", percent_attenuation=desired_attenuation)

    # Convert first grain addition to LME
    pale_lme = grain_additions[0].convert_to_lme(brew_house_yield=brew_house_yield)
    new_grain_additions = [pale_lme] + grain_additions[1:]

    # Create the recipe
    recipe = Recipe(
        name=name,
        grain_additions=new_grain_additions,
        hop_additions=hop_additions,
        yeast=yeast,
        brew_house_yield=brew_house_yield,
        start_volume=start_volume,
        final_volume=final_volume,
    )
    print(recipe.format())

    print("\nAdjuncts")
    print("===================================")
    print("- 0.66 oz Juniper Berries (crushed), 1/3 to boil at 10 min, 2/3 at knockout")
    print("- 0.25 oz Sage, 2/3 to boil at 10 min, 1/3 at knockout")
Example #18
0
cascade = Hop(name=u"cascade", percent_alpha_acids=0.07)
hop_list = [centennial, cascade]

centennial_add = HopAddition(centennial, boil_time=60.0, weight=0.57)
cascade_add = HopAddition(cascade, boil_time=5.0, weight=0.76)
hop_additions = [centennial_add, cascade_add]

# Define Yeast
yeast = Yeast(u"Wyeast 1056")

# Define Recipes
recipe = Recipe(
    name=u"pale ale",
    grain_additions=grain_additions,
    hop_additions=hop_additions,
    yeast=yeast,
    brew_house_yield=BHY,
    start_volume=7.0,
    final_volume=5.0,
)

recipe_lme = Recipe(
    name=u"pale ale lme",
    grain_additions=grain_additions_lme,
    hop_additions=hop_additions,
    yeast=yeast,
    brew_house_yield=0.70,
    start_volume=7.0,
    final_volume=5.0,
)
Example #19
0
def parse_recipe(recipe, loader,
                 cereals_loader=None,
                 hops_loader=None,
                 yeast_loader=None,
                 cereals_dir_suffix='cereals/',
                 hops_dir_suffix='hops/',
                 yeast_dir_suffix='yeast/'):
    """
    Parse a recipe from a python Dict

    :param dict recipe: A representation of a recipe
    :param DataLoader loader: A class to load additional information
    :param DataLoader cereal_loader: A class to load additional information specific to cereals
    :param DataLoader hops_loader: A class to load additional information specific to hops
    :param DataLoader yeast_loader: A class to load additional information specific to yeast

    A recipe must have the following top level attributes:

    * name         (str)
    * start_volume (float)
    * final_volume (float)
    * grains       (list(dict))
    * hops         (list(dict))
    * yeast        (dict)

    Additionally the recipe may contain override data in the 'data'
    attribute with the following keys:

    * percent_brew_house_yield (float)
    * units                    (str)

    All other fields will be ignored and may be used for other metadata.

    The dict objects in the grains, hops, and yeast values are required to have
    the key 'name' and the remaining attributes will be looked up in the data
    directory if they are not provided.
    """  # noqa
    if cereals_loader is None:
        cereals_loader = loader
    if hops_loader is None:
        hops_loader = loader
    if yeast_loader is None:
        yeast_loader = loader

    Recipe.validate(recipe)

    grain_additions = []
    for grain in recipe[u'grains']:
        grain_additions.append(parse_cereals(grain, cereals_loader,
                                             dir_suffix=cereals_dir_suffix))

    hop_additions = []
    for hop in recipe[u'hops']:
        hop_additions.append(parse_hops(hop, hops_loader,
                                        dir_suffix=hops_dir_suffix))

    yeast = parse_yeast(recipe[u'yeast'], yeast_loader,
                        dir_suffix=yeast_dir_suffix)

    recipe_kwargs = {
        u'grain_additions': grain_additions,
        u'hop_additions': hop_additions,
        u'yeast': yeast,
        u'start_volume': recipe[u'start_volume'],
        u'final_volume': recipe[u'final_volume'],
    }
    if u'data' in recipe:
        if u'percent_brew_house_yield' in recipe[u'data']:
            recipe_kwargs[u'percent_brew_house_yield'] = \
                recipe[u'data'][u'percent_brew_house_yield']
        if u'units' in recipe[u'data']:
            recipe_kwargs[u'units'] = recipe[u'data'][u'units']

    beer = Recipe(recipe[u'name'],
                  **recipe_kwargs)
    return beer
Example #20
0
 def test_ne_final_volume(self):
     recipe1 = Recipe(u"pale ale", final_volume=6.0)
     recipe2 = Recipe(u"pale ale", final_volume=5.5)
     self.assertTrue(recipe1 != recipe2)
Example #21
0
 def test_ne_units(self):
     recipe1 = Recipe(u"pale ale", units=IMPERIAL_UNITS)
     recipe2 = Recipe(u"pale ale", units=SI_UNITS)
     self.assertTrue(recipe1 != recipe2)
Example #22
0
 def test_ne_start_volume(self):
     recipe1 = Recipe(u"pale ale", start_volume=7.0)
     recipe2 = Recipe(u"pale ale", start_volume=6.5)
     self.assertTrue(recipe1 != recipe2)
Example #23
0
 def test_ne_brew_house_yield(self):
     recipe1 = Recipe(u"pale ale", brew_house_yield=0.70)
     recipe2 = Recipe(u"pale ale", brew_house_yield=0.65)
     self.assertTrue(recipe1 != recipe2)
Example #24
0
 def test_eq(self):
     recipe1 = Recipe(u"pale ale")
     recipe2 = Recipe(u"pale ale")
     self.assertEquals(recipe1, recipe2)
Example #25
0
 def test_ne_grain_additions(self):
     recipe1 = Recipe(u"pale ale", grain_additions=grain_additions)
     recipe2 = Recipe(u"pale ale", grain_additions=[grain_additions[0]])
     self.assertTrue(recipe1 != recipe2)
Example #26
0
 def test_ne_name(self):
     recipe1 = Recipe(u"pale ale")
     recipe2 = Recipe(u"ipa")
     self.assertTrue(recipe1 != recipe2)
 def test_validate(self):
     data = self.recipe.to_dict()
     Recipe.validate(data)
Example #28
0
 def test_ne_yeast(self):
     recipe1 = Recipe(u"pale ale", yeast=yeast)
     recipe2 = Recipe(u"pale ale", yeast=None)
     self.assertTrue(recipe1 != recipe2)