mirror of
https://github.com/shouptech/humulus.git
synced 2026-02-03 17:19:42 +00:00
Add filters for og & fg
This commit is contained in:
parent
705f84d3cb
commit
1ff3d6e3a7
5 changed files with 165 additions and 0 deletions
|
|
@ -46,4 +46,8 @@ def create_app(test_config=None):
|
||||||
from . import auth
|
from . import auth
|
||||||
app.register_blueprint(auth.bp)
|
app.register_blueprint(auth.bp)
|
||||||
|
|
||||||
|
# Register custom filters
|
||||||
|
from . import filters
|
||||||
|
filters.create_filters(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
||||||
68
src/humulus/filters.py
Normal file
68
src/humulus/filters.py
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
"""This module contains filters used in rendering of Jinja templates."""
|
||||||
|
|
||||||
|
# Copyright 2019 Mike Shoup
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
def recipe_og(recipe):
|
||||||
|
"""Returns a recipe's Original Gravity"""
|
||||||
|
points = 0
|
||||||
|
grain_points = 0
|
||||||
|
# Loop through fermentables, adding up points
|
||||||
|
for fermentable in recipe['fermentables']:
|
||||||
|
if fermentable['type'] == 'Grain':
|
||||||
|
grain_points += (
|
||||||
|
float(fermentable['amount']) * float(fermentable['ppg'])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
points += (
|
||||||
|
float(fermentable['amount']) * float(fermentable['ppg'])
|
||||||
|
)
|
||||||
|
points += grain_points * float(recipe['efficiency']) / 100
|
||||||
|
return '{:.3f}'.format(
|
||||||
|
round(1 + points / (1000 * float(recipe['volume'])), 3)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def recipe_fg(recipe):
|
||||||
|
"""Returns a recipe's final gravity"""
|
||||||
|
if 'yeast' not in recipe:
|
||||||
|
return 0.0
|
||||||
|
og = float(recipe_og(recipe))
|
||||||
|
og_delta = 0.0
|
||||||
|
# Adjust original gravity by removing nonfermentables (i.e., Lactose)
|
||||||
|
for fermentable in recipe['fermentables']:
|
||||||
|
if fermentable['type'] == 'Non-fermentable':
|
||||||
|
og_delta += (
|
||||||
|
float(fermentable['amount']) * float(fermentable['ppg']) /
|
||||||
|
(1000 * float(recipe['volume']))
|
||||||
|
)
|
||||||
|
attenuation = (
|
||||||
|
(
|
||||||
|
float(recipe['yeast']['low_attenuation']) +
|
||||||
|
float(recipe['yeast']['high_attenuation'])
|
||||||
|
) / 200
|
||||||
|
)
|
||||||
|
print(og - 1 - og_delta)
|
||||||
|
print(attenuation)
|
||||||
|
print(og_delta)
|
||||||
|
return '{:.3f}'.format(
|
||||||
|
round(1 + (og - 1 - og_delta)*(1 - attenuation) + og_delta, 3)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_filters(app):
|
||||||
|
app.add_template_filter(recipe_og)
|
||||||
|
app.add_template_filter(recipe_fg)
|
||||||
|
|
@ -32,6 +32,10 @@
|
||||||
<dd>{{ recipe.efficiency|int }}%</dd>
|
<dd>{{ recipe.efficiency|int }}%</dd>
|
||||||
<dt>Batch Volume</dt>
|
<dt>Batch Volume</dt>
|
||||||
<dd>{{ recipe.volume|float|round(1) }} gal.</dd>
|
<dd>{{ recipe.volume|float|round(1) }} gal.</dd>
|
||||||
|
<dt>OG</dt>
|
||||||
|
<dd>{{ recipe|recipe_og }}</dd>
|
||||||
|
<dt>FG</dt>
|
||||||
|
<dd>{{ recipe|recipe_fg }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
|
|
||||||
|
|
@ -152,3 +152,68 @@ class AuthActions(object):
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def auth(client):
|
def auth(client):
|
||||||
return AuthActions(client)
|
return AuthActions(client)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sample_recipes():
|
||||||
|
"""These sample recipes are useful for testing filters."""
|
||||||
|
return {
|
||||||
|
'blonde-ale': {
|
||||||
|
'efficiency': '68.00',
|
||||||
|
'fermentables': [
|
||||||
|
{
|
||||||
|
'amount': '8.50',
|
||||||
|
'color': '1.80',
|
||||||
|
'name': 'Pale Malt, 2-row (Rahr) (US)',
|
||||||
|
'ppg': '37.00',
|
||||||
|
'type': 'Grain'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'amount': '0.50',
|
||||||
|
'color': '10.00',
|
||||||
|
'name': 'Munich Malt 10L (Briess) (US)',
|
||||||
|
'ppg': '35.00',
|
||||||
|
'type': 'Grain'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'hops': [
|
||||||
|
{
|
||||||
|
'alpha': '9.30',
|
||||||
|
'amount': '0.50',
|
||||||
|
'duration': '30.00',
|
||||||
|
'name': 'Cascade (US)',
|
||||||
|
'use': 'Boil'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'alpha': '9.30',
|
||||||
|
'amount': '0.50',
|
||||||
|
'duration': '15.00',
|
||||||
|
'name': 'Cascade (US)',
|
||||||
|
'use': 'Boil'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'alpha': '9.30',
|
||||||
|
'amount': '1.00',
|
||||||
|
'duration': '5.00',
|
||||||
|
'name': 'Cascade (US)',
|
||||||
|
'use': 'Boil'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'name': 'Blonde Ale Base',
|
||||||
|
'notes': "This is a base recipe. It's okay on its own, but"
|
||||||
|
'better with other things, like fruits.',
|
||||||
|
'volume': '5.50',
|
||||||
|
'yeast': {
|
||||||
|
'abv_tolerance': '15.00',
|
||||||
|
'code': 'WLP090',
|
||||||
|
'flocculation': 'High',
|
||||||
|
'high_attenuation': '83.00',
|
||||||
|
'lab': 'White Labs',
|
||||||
|
'low_attenuation': '76.00',
|
||||||
|
'max_temperature': '68.00',
|
||||||
|
'min_temperature': '65.00',
|
||||||
|
'name': 'San Diego Super Yeast',
|
||||||
|
'type': 'Liquid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
24
tests/test_filters.py
Normal file
24
tests/test_filters.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright 2019 Mike Shoup
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
from humulus.filters import *
|
||||||
|
|
||||||
|
|
||||||
|
def test_recipe_og(sample_recipes):
|
||||||
|
assert recipe_og(sample_recipes['blonde-ale']) == '1.041'
|
||||||
|
|
||||||
|
|
||||||
|
def test_recipe_fg(sample_recipes):
|
||||||
|
assert recipe_fg(sample_recipes['blonde-ale']) == '1.008'
|
||||||
Loading…
Add table
Reference in a new issue