From 9fbc658aa627aedd32bf334ee3079f5262fd1574 Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Tue, 24 Mar 2020 18:24:31 -0400 Subject: [PATCH] rtutil: Add RT.parse method. This method can parse the ticket and (optional) attachment IDs out of our short-hand link formats, both for Ledger and Beancount. --- conservancy_beancount/rtutil.py | 14 ++++++++++++++ tests/test_rtutil.py | 26 +++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/conservancy_beancount/rtutil.py b/conservancy_beancount/rtutil.py index 3bdc2f9..0d87b9d 100644 --- a/conservancy_beancount/rtutil.py +++ b/conservancy_beancount/rtutil.py @@ -16,6 +16,7 @@ import functools import mimetypes +import re import urllib.parse as urlparse import rt @@ -31,6 +32,11 @@ AttachmentTuple = Tuple[str, str, str, str] RTId = Union[int, str] class RT: + PARSE_REGEXPS = [ + re.compile(r'^rt:([0-9]+)(?:/([0-9]+))?/?$'), + re.compile(r'^rt://ticket/([0-9]+)(?:/attachments?/([0-9]+))?/?$'), + ] + def __init__(self, rt_client: rt.Rt) -> None: self.rt = rt_client urlparts = urlparse.urlparse(rt_client.url) @@ -94,6 +100,14 @@ class RT: def exists(self, ticket_id: RTId, attachment_id: Optional[RTId]=None) -> bool: return self.url(ticket_id, attachment_id) is not None + def parse(self, s: str) -> Optional[Tuple[str, Optional[str]]]: + for regexp in self.PARSE_REGEXPS: + match = regexp.match(s) + if match is not None: + ticket_id, attachment_id = match.groups() + return (ticket_id, attachment_id) + return None + @functools.lru_cache() def ticket_url(self, ticket_id: RTId) -> Optional[str]: if self.rt.get_ticket(ticket_id) is None: diff --git a/tests/test_rtutil.py b/tests/test_rtutil.py index accb7af..87333e7 100644 --- a/tests/test_rtutil.py +++ b/tests/test_rtutil.py @@ -35,7 +35,7 @@ EXPECTED_URLS = [ (9, None, None), ] -@pytest.fixture +@pytest.fixture(scope='module') def rt(): client = testutil.RTClient() return rtutil.RT(client) @@ -97,3 +97,27 @@ def test_exists_caches(new_client): assert rt.exists(2) assert not rt.exists(1, 9) assert not rt.exists(9) + +@pytest.mark.parametrize('link,expected', [ + ('rt:1/2', ('1', '2')), + ('rt:123/456', ('123', '456')), + ('rt:12345', ('12345', None)), + ('rt:12346/', ('12346', None)), + ('rt:12346/789', ('12346', '789')), + ('rt:12346/780/', ('12346', '780')), + ('rt://ticket/1', ('1', None)), + ('rt://ticket/1/', ('1', None)), + ('rt://ticket/1234/attachments/5678', ('1234', '5678')), + ('rt://ticket/1234/attachments/5678/', ('1234', '5678')), + ('rt://ticket/1234/attachment/5678', ('1234', '5678')), + ('rt://ticket/1234/attachment/5678/', ('1234', '5678')), + ('rt:', None), + ('rt://', None), + ('rt:example.org', None), + ('rt:example.org/1', None), + ('rt://example.org', None), + ('rt://example.org/1', None), + ('https://example.org/rt/Ticket/Display.html?id=123', None), +]) +def test_parse(rt, link, expected): + assert rt.parse(link) == expected