"""
The latest version of this package is available at:
<http://github.com/jantman/biweeklybudget>
################################################################################
Copyright 2016 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
This file is part of biweeklybudget, also known as biweeklybudget.
biweeklybudget is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
biweeklybudget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with biweeklybudget. If not, see <http://www.gnu.org/licenses/>.
The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/biweeklybudget> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
################################################################################
AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
################################################################################
"""
import os
import logging
import plaid
from biweeklybudget import settings
from datetime import datetime
import pytz
from contextlib import contextmanager
from babel.numbers import format_currency
from plaid import Configuration, ApiClient, Environment
from plaid.api.plaid_api import PlaidApi
logger = logging.getLogger(__name__)
[docs]def plaid_client() -> PlaidApi:
"""
Return an initialized Plaid API client instance.
"""
logger.debug('Getting Plaid client instance')
assert settings.PLAID_CLIENT_ID is not None
assert settings.PLAID_SECRET is not None
assert settings.PLAID_ENV is not None
configuration = Configuration(
host=getattr(Environment, settings.PLAID_ENV),
api_key={
'clientId': settings.PLAID_CLIENT_ID,
'secret': settings.PLAID_SECRET,
}
)
api_client = ApiClient(configuration)
client = PlaidApi(api_client)
return client
[docs]def fix_werkzeug_logger():
"""
Remove the werkzeug logger StreamHandler (call from ``app.py``).
With Werkzeug at least as of 0.12.1, werkzeug._internal._log sets up its own
StreamHandler if logging isn't already configured. Because we're using
the ``flask`` command line wrapper, that will ALWAYS be imported (and
executed) before we can set up our own logger. As a result, to fix the
duplicate log messages, we have to go back and remove that StreamHandler.
"""
wlog = logging.getLogger('werkzeug')
logger.info('Removing handlers from "werkzeug" logger')
for h in wlog.handlers:
wlog.removeHandler(h)
[docs]def fmt_currency(amt):
"""
Using :py:attr:`~biweeklybudget.settings.LOCALE_NAME` and
:py:attr:`~biweeklybudget.settings.CURRENCY_CODE`, return ``amt`` formatted
as currency.
:param amt: The amount to format; any numeric type.
:return: ``amt`` formatted for the appropriate locale and currency
:rtype: str
"""
return format_currency(
amt, settings.CURRENCY_CODE, locale=settings.LOCALE_NAME
)
[docs]def dtnow():
"""
Return the current datetime as a timezone-aware DateTime object in UTC.
:return: current datetime
:rtype: datetime.datetime
"""
# This is for acceptance tests... :(
if settings.BIWEEKLYBUDGET_TEST_TIMESTAMP is not None:
return datetime.fromtimestamp(
int(settings.BIWEEKLYBUDGET_TEST_TIMESTAMP), pytz.utc
)
return datetime.utcnow().replace(tzinfo=pytz.utc)
[docs]def decode_json_datetime(d):
"""
Return a datetime.datetime for a datetime that was serialized with
:py:class:`~.MagicJSONEncoder`.
:param d: dict from deserialized JSON
:type d: dict
:return: datetime represented by dict
:rtype: datetime.datetime
"""
return datetime(
d['year'], d['month'], d['date'], d['hour'], d['minute'], d['second'],
tzinfo=pytz.timezone(d['tzname'])
)
[docs]def date_suffix(n):
"""
Given an integer day of month (1 <= n <= 31), return that number with the
appropriate suffix (st|nd|rd|th).
From: http://stackoverflow.com/a/5891598/211734
:param n: Integer day of month
:type n: int
:return: n with the appropriate suffix
:rtype: str
"""
return 'th' if 11 <= n <= 13 else {1: 'st', 2: 'nd', 3: 'rd'}.get(
n % 10, 'th'
)
[docs]@contextmanager
def in_directory(path):
pwd = os.getcwd()
os.chdir(path)
yield os.path.abspath(path)
os.chdir(pwd)