Source code for biweeklybudget.utils

"""
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)