refactor never_unit automation to AutomationEngine

create tests for never_unit
This commit is contained in:
smilerz
2023-08-30 17:03:29 -05:00
parent 7c0b8b151c
commit 39253cfd02
3 changed files with 113 additions and 51 deletions

View File

@ -93,6 +93,48 @@ class AutomationEngine:
return automation.param_2 return automation.param_2
return food return food
def apply_never_unit_automation(self, tokens):
"""
Moves a string that should never be treated as a unit to next token and optionally replaced with default unit
e.g. NEVER_UNIT: param1: egg, param2: None would modify ['1', 'egg', 'white'] to ['1', '', 'egg', 'white']
or NEVER_UNIT: param1: egg, param2: pcs would modify ['1', 'egg', 'yolk'] to ['1', 'pcs', 'egg', 'yolk']
:param1 string: string that should never be considered a unit, will be moved to token[2]
:param2 (optional) unit as string: will insert unit string into token[1]
:return: unit as string (possibly changed by automation)
"""
if self.use_cache and self.never_unit is None:
self.never_unit = {}
NEVER_UNIT_CACHE_KEY = f'automation_never_unit_{self.request.space.pk}'
if c := caches['default'].get(NEVER_UNIT_CACHE_KEY, None):
self.never_unit = c
caches['default'].touch(NEVER_UNIT_CACHE_KEY, 30)
else:
for a in Automation.objects.filter(space=self.request.space, disabled=False, type=Automation.NEVER_UNIT).only('param_1', 'param_2').order_by('order').all():
self.never_unit[a.param_1.lower()] = a.param_2
caches['default'].set(NEVER_UNIT_CACHE_KEY, self.never_unit, 30)
else:
self.never_unit = {}
new_unit = None
alt_unit = self.apply_unit_automation(tokens[1])
never_unit = False
if self.never_unit:
try:
new_unit = self.never_unit[tokens[1].lower()]
never_unit = True
except KeyError:
return tokens
else:
if a := Automation.objects.annotate(param_1_lower=Lower('param_1')).filter(space=self.request.space, type=Automation.NEVER_UNIT, param_1_lower__in=[
tokens[1].lower(), alt_unit.lower()], disabled=False).order_by('order').first():
new_unit = a.param_2
never_unit = True
if never_unit:
tokens.insert(1, new_unit)
return tokens
def apply_transpose_automation(self, string): def apply_transpose_automation(self, string):
return string return string

View File

@ -14,12 +14,12 @@ class IngredientParser:
request = None request = None
ignore_rules = False ignore_rules = False
# food_aliases = {} # food_aliases = {}
unit_aliases = {} # unit_aliases = {}
never_unit = {} # never_unit = {}
transpose_words = {} transpose_words = {}
automation = None automation = None
def __init__(self, request, cache_mode, ignore_automations=False): def __init__(self, request, cache_mode=True, ignore_automations=False):
""" """
Initialize ingredient parser Initialize ingredient parser
:param request: request context (to control caching, rule ownership, etc.) :param request: request context (to control caching, rule ownership, etc.)
@ -49,14 +49,14 @@ class IngredientParser:
# caches['default'].set(UNIT_CACHE_KEY, self.unit_aliases, 30) # caches['default'].set(UNIT_CACHE_KEY, self.unit_aliases, 30)
# TODO migrated to automation engine # TODO migrated to automation engine
NEVER_UNIT_CACHE_KEY = f'automation_never_unit_{self.request.space.pk}' # NEVER_UNIT_CACHE_KEY = f'automation_never_unit_{self.request.space.pk}'
if c := caches['default'].get(NEVER_UNIT_CACHE_KEY, None): # if c := caches['default'].get(NEVER_UNIT_CACHE_KEY, None):
self.never_unit = c # self.never_unit = c
caches['default'].touch(NEVER_UNIT_CACHE_KEY, 30) # caches['default'].touch(NEVER_UNIT_CACHE_KEY, 30)
else: # else:
for a in Automation.objects.filter(space=self.request.space, disabled=False, type=Automation.NEVER_UNIT).only('param_1', 'param_2').order_by('order').all(): # for a in Automation.objects.filter(space=self.request.space, disabled=False, type=Automation.NEVER_UNIT).only('param_1', 'param_2').order_by('order').all():
self.never_unit[a.param_1.lower()] = a.param_2 # self.never_unit[a.param_1.lower()] = a.param_2
caches['default'].set(NEVER_UNIT_CACHE_KEY, self.never_unit, 30) # caches['default'].set(NEVER_UNIT_CACHE_KEY, self.never_unit, 30)
# TODO migrated to automation engine # TODO migrated to automation engine
TRANSPOSE_WORDS_CACHE_KEY = f'automation_transpose_words_{self.request.space.pk}' TRANSPOSE_WORDS_CACHE_KEY = f'automation_transpose_words_{self.request.space.pk}'
@ -71,8 +71,8 @@ class IngredientParser:
caches['default'].set(TRANSPOSE_WORDS_CACHE_KEY, self.transpose_words, 30) caches['default'].set(TRANSPOSE_WORDS_CACHE_KEY, self.transpose_words, 30)
else: else:
# self.food_aliases = {} # self.food_aliases = {}
self.unit_aliases = {} # self.unit_aliases = {}
self.never_unit = {} # self.never_unit = {}
self.transpose_words = {} self.transpose_words = {}
# def apply_food_automation(self, food): # def apply_food_automation(self, food):
@ -122,6 +122,9 @@ class IngredientParser:
if not unit: if not unit:
return None return None
if len(unit) > 0: if len(unit) > 0:
if self.ignore_rules:
u, created = Unit.objects.get_or_create(name=unit.strip(), space=self.request.space)
else:
u, created = Unit.objects.get_or_create(name=self.automation.apply_unit_automation(unit), space=self.request.space) u, created = Unit.objects.get_or_create(name=self.automation.apply_unit_automation(unit), space=self.request.space)
return u return u
return None return None
@ -135,6 +138,9 @@ class IngredientParser:
if not food: if not food:
return None return None
if len(food) > 0: if len(food) > 0:
if self.ignore_rules:
f, created = Food.objects.get_or_create(name=food.strip(), space=self.request.space)
else:
f, created = Food.objects.get_or_create(name=self.automation.apply_food_automation(food), space=self.request.space) f, created = Food.objects.get_or_create(name=self.automation.apply_food_automation(food), space=self.request.space)
return f return f
return None return None
@ -237,40 +243,39 @@ class IngredientParser:
food, note = self.parse_food_with_comma(tokens) food, note = self.parse_food_with_comma(tokens)
return food, note return food, note
# TODO migrated to automation engine # def apply_never_unit_automations(self, tokens):
def apply_never_unit_automations(self, tokens): # """
""" # Moves a string that should never be treated as a unit to next token and optionally replaced with default unit
Moves a string that should never be treated as a unit to next token and optionally replaced with default unit # e.g. NEVER_UNIT: param1: egg, param2: None would modify ['1', 'egg', 'white'] to ['1', '', 'egg', 'white']
e.g. NEVER_UNIT: param1: egg, param2: None would modify ['1', 'egg', 'white'] to ['1', '', 'egg', 'white'] # or NEVER_UNIT: param1: egg, param2: pcs would modify ['1', 'egg', 'yolk'] to ['1', 'pcs', 'egg', 'yolk']
or NEVER_UNIT: param1: egg, param2: pcs would modify ['1', 'egg', 'yolk'] to ['1', 'pcs', 'egg', 'yolk'] # :param1 string: string that should never be considered a unit, will be moved to token[2]
:param1 string: string that should never be considered a unit, will be moved to token[2] # :param2 (optional) unit as string: will insert unit string into token[1]
:param2 (optional) unit as string: will insert unit string into token[1] # :return: unit as string (possibly changed by automation)
:return: unit as string (possibly changed by automation) # """
"""
if self.ignore_rules: # if self.ignore_rules:
return tokens # return tokens
new_unit = None # new_unit = None
alt_unit = self.apply_unit_automation(tokens[1]) # alt_unit = self.apply_unit_automation(tokens[1])
never_unit = False # never_unit = False
if self.never_unit: # if self.never_unit:
try: # try:
new_unit = self.never_unit[tokens[1].lower()] # new_unit = self.never_unit[tokens[1].lower()]
never_unit = True # never_unit = True
except KeyError: # except KeyError:
return tokens # return tokens
else: # else:
if automation := Automation.objects.annotate(param_1_lower=Lower('param_1')).filter(space=self.request.space, type=Automation.NEVER_UNIT, param_1_lower__in=[ # if automation := Automation.objects.annotate(param_1_lower=Lower('param_1')).filter(space=self.request.space, type=Automation.NEVER_UNIT, param_1_lower__in=[
tokens[1].lower(), alt_unit.lower()], disabled=False).order_by('order').first(): # tokens[1].lower(), alt_unit.lower()], disabled=False).order_by('order').first():
new_unit = automation.param_2 # new_unit = automation.param_2
never_unit = True # never_unit = True
if never_unit: # if never_unit:
tokens.insert(1, new_unit) # tokens.insert(1, new_unit)
return tokens # return tokens
# TODO migrated to automation engine # TODO migrated to automation engine
def apply_transpose_words_automations(self, ingredient): def apply_transpose_words_automations(self, ingredient):
@ -356,7 +361,7 @@ class IngredientParser:
# a fraction for the amount # a fraction for the amount
if len(tokens) > 2: if len(tokens) > 2:
# TODO migrated to automation engine # TODO migrated to automation engine
tokens = self.apply_never_unit_automations(tokens) tokens = self.automation.apply_never_unit_automation(tokens)
try: try:
if unit is not None: if unit is not None:
# a unit is already found, no need to try the second argument for a fraction # a unit is already found, no need to try the second argument for a fraction
@ -403,9 +408,10 @@ class IngredientParser:
if unit_note not in note: if unit_note not in note:
note += ' ' + unit_note note += ' ' + unit_note
if unit: if unit and not self.ignore_rules:
unit = self.automation.apply_unit_automation(unit) unit = self.automation.apply_unit_automation(unit)
if food and not self.ignore_rules:
food = self.automation.apply_food_automation(food) food = self.automation.apply_food_automation(food)
if len(food) > Food._meta.get_field('name').max_length: # test if food name is to long if len(food) > Food._meta.get_field('name').max_length: # test if food name is to long
# try splitting it at a space and taking only the first arg # try splitting it at a space and taking only the first arg

View File

@ -53,7 +53,7 @@ def test_keyword_automation(u1_s1, arg):
automation = AutomationEngine(request, False) automation = AutomationEngine(request, False)
with scope(space=space): with scope(space=space):
Automation.objects.get_or_create(name='food test', type=Automation.KEYWORD_ALIAS, param_1=arg[0], param_2=target_name, created_by=user, space=space) Automation.objects.get_or_create(name='keyword test', type=Automation.KEYWORD_ALIAS, param_1=arg[0], param_2=arg[1], created_by=user, space=space)
assert (automation.apply_keyword_automation(arg[0]) == target_name) is True assert (automation.apply_keyword_automation(arg[0]) == target_name) is True
@ -73,7 +73,7 @@ def test_unit_automation(u1_s1, arg):
automation = AutomationEngine(request, False) automation = AutomationEngine(request, False)
with scope(space=space): with scope(space=space):
Automation.objects.get_or_create(name='food test', type=Automation.UNIT_ALIAS, param_1=arg[0], param_2=target_name, created_by=user, space=space) Automation.objects.get_or_create(name='unit test', type=Automation.UNIT_ALIAS, param_1=arg[0], param_2=target_name, created_by=user, space=space)
assert (automation.apply_unit_automation(arg[0]) == target_name) is True assert (automation.apply_unit_automation(arg[0]) == target_name) is True
@ -84,9 +84,23 @@ def test_unit_automation(u1_s1, arg):
# def test_instruction_replace_automation(): # def test_instruction_replace_automation():
# assert True == True # assert True == True
@pytest.mark.parametrize("arg", [
[[1, 'egg', 'white'], '', [1, '', 'egg', 'white']],
[[1, 'Egg', 'white'], '', [1, '', 'Egg', 'white']],
[[1, 'êgg', 'white'], '', [1, 'êgg', 'white']],
[[1, 'egg', 'white'], 'whole', [1, 'whole', 'egg', 'white']],
])
def test_never_unit_automation(u1_s1, arg):
user = auth.get_user(u1_s1)
space = user.userspace_set.first().space
request = RequestFactory()
request.user = user
request.space = space
automation = AutomationEngine(request, False)
# def test_never_unit_automation(): with scope(space=space):
# assert True == True Automation.objects.get_or_create(name='never unit test', type=Automation.NEVER_UNIT, param_1='egg', param_2=arg[1], created_by=user, space=space)
assert automation.apply_never_unit_automation(arg[0]) == arg[2]
# def test_transpose_automation(): # def test_transpose_automation():