The main motivation for this change is to make sure that higher-level
code deals with the fact that self.units.number can be None, and has
an easy way to do so.
I'm not sure all our code is *currently* doing the right thing for this
case, because I'm not sure it will ever actually come up. It's possible
that earlier Beancount plugins fill in decimal amounts for postings
that are originally loaded with self.units.number=None. I'll have to see
later whether this case comes up in reality, and then deal with it if so.
For now the safest strategy seems to be that most code should operate
when self.units.number is None.
These were tightened up by running mypy with --disallow-any-generics
and cleaning up reported errors.
There are still a couple of cases I don't know how to deal with
right now that prevent me from setting that option permanently:
* plugin/__init__.py sets up a dict where the key is a Directive
and its value is a set of hooks that correspond to that type
of directive. The relationship between key and value is not
expressable through the type system, and any other solution would
make the code way more involved and less dynamic.
* The type variable used in _GenericRange still isn't quite right,
in the sense that specifying a value for CT creates more errors
I don't know how to deal with. Protocols seem like the right
solution for that but they apparently didn't land for Python 3.7
that I can see.
Mostly this meant giving annotations to low-value functions like
the error classes and __init_subclass__, but it's worth it for
the future strictness+documentation value.
This just returns a constant for now, but we know it may need to be
configurable in the future. Other code can start using this now
to be configurable in the future.
I wasn't too worried about this earlier because the cache mainly stores
a bunch of numbers, but there's a little more than that: the generated
URLs also include original attachment filenames, which might be sensitive
(referencing people's names, bank names, etc.). Tighten security
accordingly.
This returns a cached version of the new rtutil.RT class,
so that a single process can easily grab references to one
instance with one cache of ticket/attachment data, etc.
For now, this is basically the Python version of
ledger-tag-convert.plx. It knows how to create RT web links from
ticket and attachment IDs. It confirms that those objects actually
exist too. It may grow to encompass other functionality in the
future.
This loads settings from the same environment variables and ~/.rtrc
file as the rt CLI.
Note that it does *not* support RTCONFIG and the config file
searching, because right now that seems like more work for more
trouble to me.
Our version of Posting is interface-compatible with Beancount's,
but makes stronger guarantees about the data types for our
higher-level code to rely on.
As I'm pushing to reimplement payment-report/income-report, I see query and
reporting tools will want easy access to these kinds of views, so here it
starts.
* Rename _typing to beancount_types to better reflect what it is.
* LessComparable isn't a Beancount type, so move that to
plugin.core with its dependent helper classes.
* Errors are a core Beancount concept, so move that module to the
top level and have it include appropriate type definitions.
I feel like posting hooks a case of premature optimization in early
development. This approach reduces the number of special cases in
the code and allows us to more strongly reason about hooks in the
type system.
This is the layer that keeps track of the different groups of hooks and
can filter them before runtime. The idea here is that you'll be able
to do things like skip hooks that require network access when you don't
have it, or skip CPU-intensive hooks when you don't need them, etc.
Python's own enum works fine for the simple values that expenseAllocation
uses, but it won't work as well for metadata like taxImplication where
many of the values aren't legal Python identifiers. Introduce our own
MetadataEnum class with the necessary functionality, and switch to that.
This is the simplest version of a common validation we're going to do:
make sure that a particular piece of metadata has one of a set of
values.
This checker needs some bounds checking but I wanted to err on the
side of committing this early because it introduces so much base
infrastructure.