diff options
-rw-r--r-- | gn3/api/search.py | 27 | ||||
-rw-r--r-- | tests/unit/test_search.py | 11 |
2 files changed, 26 insertions, 12 deletions
diff --git a/gn3/api/search.py b/gn3/api/search.py index 0d3f9ba..e497743 100644 --- a/gn3/api/search.py +++ b/gn3/api/search.py @@ -135,6 +135,19 @@ def apply_si_suffix(location: str) -> int: return int(location) +def parse_position(spec: str) -> tuple[Maybe[int], Maybe[int]]: + """Parse position specifiation converting point locations to ranges.""" + # Range + if ".." in spec: + return tuple(limit.map(apply_si_suffix) # type: ignore + for limit in parse_range(spec)) + # If point location, assume +/- 50 kbases on either side. + else: + width = 50*10**3 + point = apply_si_suffix(spec) + return Just(max(0, point - width)), Just(point + width) + + def parse_location_field(species_query: xapian.Query, chromosome_prefix: str, location_slot: int, liftover_function: IntervalLiftoverFunction, @@ -146,19 +159,11 @@ def parse_location_field(species_query: xapian.Query, """ def split_query(query: str) -> ChromosomalInterval: """Split query into chromosome and location tuple.""" - chromosome, location_str = query.lower().split(":") + chromosome, position_spec = query.lower().split(":") if not chromosome.startswith("chr"): raise ValueError - location: tuple[Maybe[int], Maybe[int]] - if ".." in location_str: - location = tuple(limit.map(apply_si_suffix) # type: ignore - for limit in parse_range(location_str)) - # If point location, assume +/- 50 kbases on either side. - else: - width = 50*10**3 - point = apply_si_suffix(location_str) - location = Just(max(0, point - width)), Just(point + width) - return ChromosomalInterval(chromosome.removeprefix("chr"), *location) + return ChromosomalInterval(chromosome.removeprefix("chr"), + *parse_position(position_spec)) def make_query(interval: ChromosomalInterval) -> xapian.Query: # TODO: Convert the xapian index to use bases instead of megabases. diff --git a/tests/unit/test_search.py b/tests/unit/test_search.py index ec89a61..c535c60 100644 --- a/tests/unit/test_search.py +++ b/tests/unit/test_search.py @@ -3,7 +3,7 @@ from hypothesis import given, strategies as st from pymonad.maybe import Just, Nothing import pytest -from gn3.api.search import apply_si_suffix, parse_range +from gn3.api.search import apply_si_suffix, parse_range, parse_position @pytest.mark.unit_test @given(st.decimals(places=3, allow_nan=False, allow_infinity=False), @@ -74,3 +74,12 @@ def test_parse_range_right_open_interval(): and no value (Nothing) for the ending of the range """ assert parse_range("foo..") == (Just("foo"), Nothing) + +@pytest.mark.unit_test +def test_parse_position_close_to_zero_location(): + """ + GIVEN: A point location close to zero + WHEN: we parse the range + THEN: set the lower limit to zero, not a negative number + """ + assert parse_position("25K")[0] == Just(0) |