Files @ 8dede9d1398c
Branch filter:

Location: NPO-Accounting/oxrlib/oxrlib/rate.py

Brett Smith
historical: Swap Ledger and Beancount formatters in the class hierarchy.

This makes sense for a couple of reasons:

* The Beancount formatter has "less features" than the Ledger formatter, so
this is a more "logical" organization of the hierarchy anyway. Note how
this eliminates the need for the BeancountFormatter.__init__ override to
turn off Ledger features.

* Any future work will probably be focused on the Beancount formatter, so
this reduces the amount of code you have to understand and hold in your
head to do that.
import datetime
import decimal
import functools
import json

class Rate:
    FIELDS = [
        'base',
        'disclaimer',
        'license',
        'rates',
        'timestamp',
    ]

    @classmethod
    def walk_fields(cls, get_field, transform_prefix):
        for fieldname in cls.FIELDS:
            value = get_field(fieldname)
            if value is not None:
                try:
                    transformer = getattr(cls, '{}_{}'.format(transform_prefix, fieldname))
                except AttributeError:
                    pass
                else:
                    value = transformer(value)
            yield (fieldname, value)

    def __init__(self, base, rates, **kwargs):
        for key, value in self.walk_fields(kwargs.get, 'deserialize'):
            setattr(self, key, value)
        self.base = base
        self.rates = rates

    @classmethod
    def deserialize_timestamp(cls, value):
        return datetime.datetime.fromtimestamp(value)

    @classmethod
    def serialize_rates(cls, rates):
        return {code: float(rates[code]) for code in rates}

    @classmethod
    def serialize_timestamp(cls, value):
        return int(value.timestamp())

    @classmethod
    def from_json_file(cls, json_file):
        response = json.load(json_file, parse_int=decimal.Decimal, parse_float=decimal.Decimal)
        return cls(**response)

    def convert(self, amount, from_currency, to_currency):
        return amount * self.rates[to_currency] / self.rates[from_currency]

    def serialize(self):
        return dict(self.walk_fields(functools.partial(getattr, self), 'serialize'))