Skip to content

Commit

Permalink
TextPositionSetFactory will accept Sequence of mixed types
Browse files Browse the repository at this point in the history
  • Loading branch information
mscarey committed Jan 25, 2021
1 parent 597cb57 commit f8c5337
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 18 deletions.
45 changes: 29 additions & 16 deletions anchorpoint/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,22 @@ class TextPositionSetFactory:
def __init__(self, passage: str) -> None:
self.passage = passage

def from_bool(self, selection: bool) -> TextPositionSet:
if selection is True:
return TextPositionSet(TextPositionSelector(0, len(self.passage)))
return TextPositionSet()

def from_selection(
self,
selection: Union[
bool,
str,
TextPositionSelector,
TextQuoteSelector,
Sequence[TextQuoteSelector],
Sequence[str],
Sequence[Union[str, TextQuoteSelector, TextPositionSelector]],
],
) -> TextPositionSet:
"""Construct TextPositionSet for a provided text passage, from any type of selector."""
if selection is True:
return TextPositionSet(TextPositionSelector(0, len(self.passage)))
elif selection is False:
return TextPositionSet()
if isinstance(selection, str):
schema = SelectorSchema()
data = schema.expand_anchor_shorthand(selection)
Expand All @@ -136,26 +136,39 @@ def from_selection(
selection = [selection]
elif isinstance(selection, TextPositionSelector):
return TextPositionSet(selection)
if isinstance(selection, Sequence):
return self.from_exact_strings(selection)
return TextPositionSet(selection)
if isinstance(selection, bool):
return self.from_bool(selection)
return self.from_selection_sequence(selection)

def from_exact_strings(
self, selection: Sequence[Union[str, TextQuoteSelector]]
def from_selection_sequence(
self, selections: Sequence[Union[str, TextQuoteSelector, TextPositionSelector]]
) -> TextPositionSet:
"""
Construct TextPositionSet from a list of strings representing exact quotations.
Construct TextPositionSet from one or more of: strings, Quote Selectors, and Position Selectors.
First converts strings to TextQuoteSelectors, and then to TextPositionSelectors.
"""
positions = []
for selection in selections:
if isinstance(selection, str):
selection = TextQuoteSelector(exact=selection)
if isinstance(selection, TextQuoteSelector):
selection = selection.as_position(self.passage)
positions.append(selection)
return TextPositionSet(positions)

def from_exact_strings(self, selection: Sequence[str]) -> TextPositionSet:
"""
Construct TextPositionSet from a sequence of strings representing exact quotations.
First converts the sequence to TextQuoteSelectors, and then to TextPositionSelectors.
"""
selectors = [
TextQuoteSelector(exact=item) if isinstance(item, str) else item
for item in selection
]
selectors = [TextQuoteSelector(exact=item) for item in selection]
return self.from_quote_selectors(quotes=selectors)

def from_quote_selectors(
self, quotes: Sequence[TextQuoteSelector]
) -> TextPositionSet:
"""Construct TextPositionSet from a sequence of TextQuoteSelectors."""
position_selectors = [quote.as_position(self.passage) for quote in quotes]
return TextPositionSet(position_selectors)
4 changes: 3 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
dev
------------------
- provide "missing" instead of "optional" argument for SelectorSchema.end
- provide "missing" instead of "optional" argument for marshmallow schema
- add TextPositionSetFactory.from_exact_strings
- SelectorSchema.expand_anchor_shorthand takes only a string argument
- TextPositionSetFactory.from_selection will accept a Sequence of mixed types

0.4.3 (2020-12-11)
------------------
Expand Down
6 changes: 6 additions & 0 deletions tests/test_selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ def test_add_selector_without_endpoint(self):
assert new.start == 5
assert new.end > 22

def test_add_infinite_selector(self):
left = TextPositionSelector("(5, inf]")
new = left + 5
assert new.start == 10
assert new.end > 22

def test_adding_nonoverlapping_selectors(self):
"""
When the selectors aren't near enough to be added,
Expand Down
34 changes: 33 additions & 1 deletion tests/test_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,31 @@


class TestMakeSelectorSet:
def test_make_selector_set(self):
def test_make_selector_set_from_different_selectors(self):
quotes = [
TextPositionSelector(start=0, end=7),
TextQuoteSelector(exact="great"),
]
factory = TextPositionSetFactory(passage="Here is some great text.")
selector_set = factory.from_selection(quotes)
assert selector_set.ranges()[0].end == 7
assert selector_set.ranges()[1].start == 13

def test_make_selector_set_from_exact_strings(self):
quotes = ["some", "text"]
factory = TextPositionSetFactory(passage="Here is some great text.")
selector_set = factory.from_exact_strings(quotes)
assert selector_set.ranges()[0].start == 8
assert selector_set.ranges()[1].start == 19

def test_make_selector_set_from_one_string(self):
quote = "Here is some"
factory = TextPositionSetFactory(passage="Here is some great text.")
selector_set = factory.from_selection(quote)
assert selector_set.ranges()[0].start == 0
assert selector_set.ranges()[0].end == 12

def test_make_selector_set_from_factory(self):
quotes = [
TextPositionSelector(start=5, end=10),
TextPositionSelector(start=20, end=30),
Expand Down Expand Up @@ -187,6 +211,14 @@ def test_add_blank_margin(self):
result = selector_set.add_margin(text=passage, margin_width=1)
assert result.as_string(text=passage) == "Some text."

def test_cannot_add_negative_margin(self):
passage = "Some text."
selector_set = TextPositionSet(
[TextPositionSelector(0, 4), TextPositionSelector(5, 10)]
)
with pytest.raises(ValueError):
selector_set.add_margin(text=passage, margin_width=-1)

def test_add_margin_with_characters(self):
selector_set = TextPositionSet(
[TextPositionSelector(0, 7), TextPositionSelector(11, 21)]
Expand Down

0 comments on commit f8c5337

Please sign in to comment.