# Path: budgettracker/data.py
# class Account(namedtuple('Account', ['id', 'title', 'amount'])):
#     @classmethod
#     def from_dict(cls, dct):
#         return cls(**dct)
# 
#     def update(self, **kwargs):
#         return Account(**dict(self._asdict(), **kwargs))
# 
#     def to_dict(self):
#         return {
#             'id': self.id,
#             'title': self.title,
#             'amount': self.amount
#         }
# 
# class Transaction(namedtuple('Transaction', ['id', 'label', 'date', 'amount', 'account', 'categories', 'goal'])):
#     @classmethod
#     def from_dict(cls, dct):
#         return cls(
#             id=dct['id'],
#             label=dct['label'],
#             date=datetime.datetime.strptime(dct['date'], "%Y-%m-%d").date(),
#             amount=float(dct['amount']),
#             account=dct['account'],
#             categories=dct.get('categories') or [],
#             goal=dct.get('goal')
#         )
# 
#     def update(self, **kwargs):
#         return Transaction(**dict(self._asdict(), **kwargs))
# 
#     def to_dict(self):
#         return {
#             'id': self.id,
#             'label': self.label,
#             'date': self.date.isoformat(),
#             'amount': self.amount,
#             'account': self.account,
#             'categories': self.categories,
#             'goal': self.goal
#         }
# 
#     def to_str(self, famount):
#         return u"%s - %s = %s%s%s" % (self.date.isoformat(), self.label, famount(self.amount),
#             ' #%s' % ', #'.join(self.categories) if self.categories else '',
#             ' [%s%s]' % (famount(self.goal)) if self.goal else '')
# 
#     def __unicode__(self):
#         return self.to_str()
# 
# Path: budgettracker/categories.py
# class Category(namedtuple('Category', ['name', 'color', 'keywords', 'warning_threshold'])):
#     @classmethod
#     def from_dict(cls, dct):
#         return cls(name=dct['name'], color=dct.get('color'), keywords=dct.get('keywords', []),
#             warning_threshold=dct.get('warning_threshold'))
# 
#     def to_dict(self):
#         return {
#             'name': self.name,
#             'color': self.color,
#             'keywords': self.keywords,
#             'warning_threshold': self.warning_threshold
#         }
# 
# def match_categories(categories, label):
#     matches = []
#     for category in categories:
#         for keyword in (category.keywords or []):
#             if re.search(r"\b%s\b" % keyword, label, re.I):
#                 matches.append(category.name)
#                 continue
#     return matches


import json, requests, os, time, uuid, re, inspect
from importlib import import_module
from ..data import Account, Transaction
from ..categories import Category, match_categories
    def fetch_transactions_from_all_accounts(self, start_date=None, end_date=None):
        transactions = []
        for account in self.fetch_accounts():
            transactions.extend(self.fetch_transactions(account, start_date, end_date))
        return sorted(transactions, key=lambda i: i.date, reverse=True)

    def create_request_session(self, reuse=True, filename='session.json'):
        if reuse and getattr(self, 'request_session_cache', None):
            return self.request_session_cache

        session = requests.Session()
        exp = time.time() - 1800 # cookie jar expires after 30min
        if reuse and os.path.exists(filename) and os.path.getmtime(filename) > exp:
            with open(filename) as f:
                cookies = json.load(f)
            session.cookies.update(cookies)
        else:
            self.login(session)
            with open(filename, 'w') as f:
                json.dump(session.cookies.get_dict(), f)

        self.request_session_cache = session
        return session

    def make_transaction(self, **kwargs):
        if not kwargs.get('id'):
            kwargs['id'] = str(uuid.uuid4())
        kwargs['label'] = re.sub("\s+", " ", kwargs['label'].replace("\n", " ").strip())
        kwargs.setdefault('categories', match_categories(self.categories, kwargs['label']))
        kwargs.setdefault('goal', None)

# Path: budgettracker/data.py
# class Account(namedtuple('Account', ['id', 'title', 'amount'])):
#     @classmethod
#     def from_dict(cls, dct):
#         return cls(**dct)
# 
#     def update(self, **kwargs):
#         return Account(**dict(self._asdict(), **kwargs))
# 
#     def to_dict(self):
#         return {
#             'id': self.id,
#             'title': self.title,
#             'amount': self.amount
#         }
# 
# class Transaction(namedtuple('Transaction', ['id', 'label', 'date', 'amount', 'account', 'categories', 'goal'])):
#     @classmethod
#     def from_dict(cls, dct):
#         return cls(
#             id=dct['id'],
#             label=dct['label'],
#             date=datetime.datetime.strptime(dct['date'], "%Y-%m-%d").date(),
#             amount=float(dct['amount']),
#             account=dct['account'],
#             categories=dct.get('categories') or [],
#             goal=dct.get('goal')
#         )
# 
#     def update(self, **kwargs):
#         return Transaction(**dict(self._asdict(), **kwargs))
# 
#     def to_dict(self):
#         return {
#             'id': self.id,
#             'label': self.label,
#             'date': self.date.isoformat(),
#             'amount': self.amount,
#             'account': self.account,
#             'categories': self.categories,
#             'goal': self.goal
#         }
# 
#     def to_str(self, famount):
#         return u"%s - %s = %s%s%s" % (self.date.isoformat(), self.label, famount(self.amount),
#             ' #%s' % ', #'.join(self.categories) if self.categories else '',
#             ' [%s%s]' % (famount(self.goal)) if self.goal else '')
# 
#     def __unicode__(self):
#         return self.to_str()
# 
# Path: budgettracker/categories.py
# class Category(namedtuple('Category', ['name', 'color', 'keywords', 'warning_threshold'])):
#     @classmethod
#     def from_dict(cls, dct):
#         return cls(name=dct['name'], color=dct.get('color'), keywords=dct.get('keywords', []),
#             warning_threshold=dct.get('warning_threshold'))
# 
#     def to_dict(self):
#         return {
#             'name': self.name,
#             'color': self.color,
#             'keywords': self.keywords,
#             'warning_threshold': self.warning_threshold
#         }
# 
# def match_categories(categories, label):
#     matches = []
#     for category in categories:
#         for keyword in (category.keywords or []):
#             if re.search(r"\b%s\b" % keyword, label, re.I):
#                 matches.append(category.name)
#                 continue
#     return matches


# Path: budgettracker/bank_adapters/base.py
import json, requests, os, time, uuid, re, inspect
from importlib import import_module
from ..data import Account, Transaction
from ..categories import Category, match_categories

    def fetch_transactions_from_all_accounts(self, start_date=None, end_date=None):
        transactions = []
        for account in self.fetch_accounts():
            transactions.extend(self.fetch_transactions(account, start_date, end_date))
        return sorted(transactions, key=lambda i: i.date, reverse=True)

    def create_request_session(self, reuse=True, filename='session.json'):
        if reuse and getattr(self, 'request_session_cache', None):
            return self.request_session_cache

        session = requests.Session()
        exp = time.time() - 1800 # cookie jar expires after 30min
        if reuse and os.path.exists(filename) and os.path.getmtime(filename) > exp:
            with open(filename) as f:
                cookies = json.load(f)
            session.cookies.update(cookies)
        else:
            self.login(session)
            with open(filename, 'w') as f:
                json.dump(session.cookies.get_dict(), f)

        self.request_session_cache = session
        return session

    def make_transaction(self, **kwargs):
        if not kwargs.get('id'):
            kwargs['id'] = str(uuid.uuid4())
        kwargs['label'] = re.sub("\s+", " ", kwargs['label'].replace("\n", " ").strip())
        kwargs.setdefault('categories', match_categories(self.categories, kwargs['label']))
        kwargs.setdefault('goal', None)

        return Transaction(**kwargs)