From 39a9d0d67ea5ce9f09b727edd48091fb9c7d64d6 2021-03-12 22:16:46 From: Brett Smith Date: 2021-03-12 22:16:46 Subject: [PATCH] query: rt_ticket() supports looking up custom fields. --- diff --git a/conservancy_beancount/reports/query.py b/conservancy_beancount/reports/query.py index a5c2bdc7ed1bf09b6cf658d2d4cfbd84a7442810..9ea5052789f85e1022d7d3e2e0e87c14c10dbb7c 100644 --- a/conservancy_beancount/reports/query.py +++ b/conservancy_beancount/reports/query.py @@ -53,6 +53,7 @@ import functools import itertools import logging import os +import re import sqlite3 import sys @@ -254,6 +255,10 @@ class RTField(NamedTuple): class RTTicket(bc_query_compile.EvalFunction): """Look up a field from RT ticket(s) mentioned in metadata documentation""" __intypes__ = [str, str, int] + _CF_REGEXPS = [ + re.compile(r'^CF_([-\w]+)$', re.IGNORECASE), + re.compile(r'^CF\.\{([-\w]+)\}$', re.IGNORECASE), + ] FIELDS = {key: RTField(key, None) for key in [ 'AdminCc', 'Cc', @@ -320,6 +325,13 @@ class RTTicket(bc_query_compile.EvalFunction): try: return self.FIELDS[key] except KeyError: + for regexp in self._CF_REGEXPS: + match = regexp.fullmatch(key) + if match is not None: + cfield = RTField(f'CF.{{{match.group(1)}}}', None) + self.FIELDS[cfield.key] = cfield + self.FIELDS[key] = cfield + return cfield raise ValueError(f"unknown RT ticket field {key!r}") from None def _meta_key(self, key: str) -> str: diff --git a/setup.py b/setup.py index 669dfde5bfc1b1194af21f9a91246eef195c59bf..d55c9be2663faa8f1b749e6a00b5e8776e8d75df 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup setup( name='conservancy_beancount', description="Plugin, library, and reports for reading Conservancy's books", - version='1.19.2', + version='1.19.3', author='Software Freedom Conservancy', author_email='info@sfconservancy.org', license='GNU AGPLv3+', diff --git a/tests/test_reports_query.py b/tests/test_reports_query.py index f3ba5947de28d183f993e3317cc397da6091fdfd..f0b56a8aabea14a18b4eb0b67df7f165c64c9260 100644 --- a/tests/test_reports_query.py +++ b/tests/test_reports_query.py @@ -90,6 +90,7 @@ def test_rt_ticket_bad_metadata(ticket_query, meta_name): ('Queue', 'approval', {'general'}), ('Requestors', 'invoice', {'mx1@example.org', 'requestor2@example.org'}), ('Due', 'tax-reporting', {datetime.datetime(2017, 1, 14, 12, 1, 0, tzinfo=UTC)}), + ('cf.{payment-to}', 'statement', {'Hon. Mx. 1'}), ]) def test_rt_ticket_from_txn(ticket_query, field_name, meta_name, expected): func = ticket_query(const_operands(field_name, meta_name)) @@ -104,6 +105,7 @@ def test_rt_ticket_from_txn(ticket_query, field_name, meta_name, expected): ('Queue', 'approval', {'general'}), ('Requestors', 'invoice', {'mx2@example.org', 'requestor2@example.org'}), ('Due', 'tax-reporting', {datetime.datetime(2017, 1, 14, 12, 2, 0, tzinfo=UTC)}), + ('CF_payment-to', 'statement', {'Hon. Mx. 2'}), ]) def test_rt_ticket_from_post(ticket_query, field_name, meta_name, expected): func = ticket_query(const_operands(field_name, meta_name)) @@ -121,6 +123,7 @@ def test_rt_ticket_from_post(ticket_query, field_name, meta_name, expected): 'mx2@example.org', 'requestor2@example.org', }, False), + ('cf_payment-to', 'statement', {'Hon. Mx. 1', 'Hon. Mx. 2'}, True), ]) def test_rt_ticket_multi_results(ticket_query, field_name, meta_name, expected, on_txn): func = ticket_query(const_operands(field_name, meta_name))