diff --git a/etiquette/photodb.py b/etiquette/photodb.py index 8731806..705409c 100644 --- a/etiquette/photodb.py +++ b/etiquette/photodb.py @@ -768,24 +768,17 @@ class PDBPhotoMixin: self._cached_frozen_children = frozen_children if tag_expression: - expression_tree = expressionmatch.ExpressionTree.parse(tag_expression) - expression_tree.map(self.normalize_tagname) - expression_matcher = searchhelpers.tag_expression_matcher_builder( - frozen_children, + tag_expression_tree = searchhelpers.tag_expression_tree_builder( + tag_expression=tag_expression, + photodb=self, + frozen_children=frozen_children, warning_bag=warning_bag, ) - for node in expression_tree.walk_leaves(): - if node.token in frozen_children: - continue - - exc = exceptions.NoSuchTag(node.token) - if warning_bag is not None: - warning_bag.add(exc.error_message) - node.token = None - else: - raise exc - - expression_tree.prune() + if tag_expression_tree is None: + tag_expression = None + else: + print(tag_expression_tree) + tag_match_function = searchhelpers.tag_expression_matcher_builder(frozen_children) if filename: filename_tree = expressionmatch.ExpressionTree.parse(filename) @@ -859,9 +852,9 @@ class PDBPhotoMixin: continue if tag_expression: - success = expression_tree.evaluate( + success = tag_expression_tree.evaluate( photo_tags, - match_function=expression_matcher, + match_function=tag_match_function, ) if not success: #print('Failed tag expression') diff --git a/etiquette/searchhelpers.py b/etiquette/searchhelpers.py index eb6b299..2eaed38 100644 --- a/etiquette/searchhelpers.py +++ b/etiquette/searchhelpers.py @@ -3,6 +3,8 @@ from . import exceptions from . import helpers from . import objects +from voussoirkit import expressionmatch + def build_query(orderby, notnulls): query = 'SELECT * FROM photos' @@ -330,8 +332,48 @@ def normalize_tag_mmf(tags, photodb, warning_bag=None): return tagset -def tag_expression_matcher_builder(frozen_children, warning_bag=None): - def matcher(photo_tags, tagname): +def tag_expression_tree_builder( + tag_expression, + photodb, + frozen_children, + warning_bag=None + ): + try: + expression_tree = expressionmatch.ExpressionTree.parse(tag_expression) + except expressionmatch.NoTokens: + return None + except Exception as exc: + warning_bag.add('Bad expression "%s"' % tag_expression) + return None + + for node in expression_tree.walk_leaves(): + try: + node.token = photodb.normalize_tagname(node.token) + except (exceptions.TagTooShort, exceptions.TagTooLong) as exc: + if warning_bag is not None: + warning_bag.add(exc.error_message) + node.token = None + else: + raise + + if node.token is None: + continue + + if node.token not in frozen_children: + exc = exceptions.NoSuchTag(node.token) + if warning_bag is not None: + warning_bag.add(exc.error_message) + node.token = None + else: + raise exc + + expression_tree.prune() + if expression_tree.token is None: + return None + return expression_tree + +def tag_expression_matcher_builder(frozen_children): + def match_function(photo_tags, tagname): ''' Used as the `match_function` for the ExpressionTree evaluation. @@ -346,4 +388,4 @@ def tag_expression_matcher_builder(frozen_children, warning_bag=None): options = frozen_children[tagname] return any(option in photo_tags for option in options) - return matcher + return match_function