Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support exclusion in tagmatcher #102

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/rpft/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ def create_parser():
help=(
"Tags to filter the content index sheet. A sequence of lists, with each "
"list starting with an integer (tag position) followed by tags to include "
"for this position. Example: 1 foo bar 2 baz means: only include rows if "
"tags:1 is empty, foo or bar, and tags:2 is empty or baz"
"or exclude for this position. To exclude, precede by '!'.\n"
"Example: 1 foo bar 2 baz means: only include rows if "
"tags:1 is empty, foo or bar, and tags:2 is empty or baz\n"
"Example: 1 foo bar ! 2 !baz means: only include rows if "
"tags:1 is foo or bar (but not empty), and tags:2 is not baz"
),
)
return parser
Expand Down
14 changes: 11 additions & 3 deletions src/rpft/parsers/creation/tagmatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

class TagMatcher:
def __init__(self, params=[]):
self.tag_patterns = collections.defaultdict(list)
self.include_patterns = collections.defaultdict(list)
self.exclude_patterns = collections.defaultdict(list)
if not params:
return
current_index = None
Expand All @@ -20,11 +21,18 @@ def __init__(self, params=[]):
"Tags parameter must start with a "
"number indicating the tag position."
)
self.tag_patterns[current_index].append(param)
if param[0] == "!":
self.exclude_patterns[current_index].append(param[1:])
else:
self.include_patterns[current_index].append(param)
# Empty string is accepted by default
self.include_patterns[current_index].append("")

def matches(self, tags):
matches = True
for i, tag in enumerate(tags):
if tag and i in self.tag_patterns and tag not in self.tag_patterns[i]:
if i in self.include_patterns and tag not in self.include_patterns[i]:
matches = False
if i in self.exclude_patterns and tag in self.exclude_patterns[i]:
matches = False
return matches
30 changes: 30 additions & 0 deletions tests/test_tagmatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,33 @@ def test_two_tags(self):
self.assertFalse(tm.matches(["something"]))
self.assertFalse(tm.matches(["something", "foo"]))
self.assertFalse(tm.matches(["something", "baz"]))

def test_exclude_tag(self):
tm = TagMatcher(["1", "!foo"])
self.assertTrue(tm.matches([]))
self.assertTrue(tm.matches([""]))
self.assertTrue(tm.matches(["bar"]))
self.assertFalse(tm.matches(["foo"]))

def test_excludetwo_tag(self):
tm = TagMatcher(["1", "!foo", "!bar"])
self.assertTrue(tm.matches([]))
self.assertTrue(tm.matches([""]))
self.assertTrue(tm.matches(["baz"]))
self.assertFalse(tm.matches(["bar"]))
self.assertFalse(tm.matches(["foo"]))

def test_excludeemptyonly_tag(self):
tm = TagMatcher(["1", "!"])
self.assertTrue(tm.matches([]))
self.assertTrue(tm.matches(["bar"]))
self.assertTrue(tm.matches(["foo"]))
self.assertFalse(tm.matches([""]))

def test_excludeempty_tag(self):
tm = TagMatcher(["1", "!", "foo", "bar"])
self.assertTrue(tm.matches([]))
self.assertTrue(tm.matches(["bar"]))
self.assertTrue(tm.matches(["foo"]))
self.assertFalse(tm.matches(["baz"]))
self.assertFalse(tm.matches([""]))