From 39a9d0d67ea5ce9f09b727edd48091fb9c7d64d6 Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Fri, 12 Mar 2021 17:16:46 -0500 Subject: [PATCH] query: rt_ticket() supports looking up custom fields. --- conservancy_beancount/reports/query.py | 12 ++++++++++++ setup.py | 2 +- tests/test_reports_query.py | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/conservancy_beancount/reports/query.py b/conservancy_beancount/reports/query.py index a5c2bdc..9ea5052 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 669dfde..d55c9be 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 f3ba594..f0b56a8 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))