<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import shelve

from requests_oauthlib import OAuth2Session
from six.moves.urllib.parse import urljoin


API_URL = 'https://api.monzo.com/'
PYMONZO_REDIRECT_URI = 'https://github.com/pawelad/pymonzo'

MONZO_ACCESS_CODE_ENV = 'MONZO_ACCESS_CODE'
MONZO_AUTH_CODE_ENV = 'MONZO_AUTH_CODE'
MONZO_CLIENT_ID_ENV = 'MONZO_CLIENT_ID'
MONZO_CLIENT_SECRET_ENV = 'MONZO_CLIENT_SECRET'

TOKEN_FILE_NAME = '.pymonzo-token'
TOKEN_FILE_PATH = os.path.join(os.path.expanduser('~'), TOKEN_FILE_NAME)


class MonzoAPI(object):
    """
    Wrapper for Monzo API.

    Official docs:
        https://monzo.com/docs/
    """
    default_account_id = None

    def __init__(self, access_token=None, client_id=None, client_secret=None,
                 auth_code=None):
        # If no values are passed, try to get them from environment variables
        self._access_token = (
            access_token or os.environ.get(MONZO_ACCESS_CODE_ENV)
        )
        self._client_id = (
            client_id or os.environ.get(MONZO_CLIENT_ID_ENV)
        )
        self._client_secret = (
            client_secret or os.environ.get(MONZO_CLIENT_SECRET_ENV)
        )
        self._auth_code = (
            auth_code or os.environ.get(MONZO_AUTH_CODE_ENV)
        )

        # We try to get the access token from:
        # a) explicitly passed 'access_token'
        if access_token:
            self._token = {
                'access_token': self._access_token,
                'token_type': 'Bearer',
            }
        # b) explicitly passed 'client_id', 'client_secret' and 'auth_code'
        elif all([client_id, client_secret, auth_code]):
            self._token = self._get_oauth_token()
        # c) token file saved on the disk
        elif os.path.isfile(TOKEN_FILE_PATH):
            with shelve.open(TOKEN_FILE_PATH) as f:
                self._token = f['token']
        # d) 'access_token' saved as a environment variable
        elif self._access_token:
            self._token = {
                'access_token': self._access_token,
                'token_type': 'Bearer',
            }
        # e) 'client_id', 'client_secret' and 'auth_code' saved as
        # environment variables
        elif all([self._client_id, self._client_secret, self._auth_code]):
            self._token = self._get_oauth_token()
        else:
            raise ValueError(
                "You need to pass (or set as environment variables) either "
                "explicit 'access_token' or all of 'client_id', "
                "'client_secret' and 'auth_code'"
            )

        # Create a session with newly acquired token
        self.session = OAuth2Session(
            client_id=client_id, token=self._token,
        )

        # Set the default account ID if there is only one available
        if len(self.accounts()) == 1:
            self.default_account_id = self.accounts()[0]['id']

    @staticmethod
    def _save_token_on_disk(token):
        """Helper function that saves passed token on disk"""
        with shelve.open(TOKEN_FILE_PATH) as f:
            f['token'] = token

    def _get_oauth_token(self):
        """
        Get Monzo access token via OAuth2 `authorization_code` grant type.

        Official docs:
            https://monzo.com/docs/#acquire-an-access-token
        """
        endpoint = '/oauth2/token'
        url = urljoin(API_URL, endpoint)

        oauth = OAuth2Session(
            client_id=self._client_id,
            redirect_uri=PYMONZO_REDIRECT_URI,
        )

        token = oauth.fetch_token(
            token_url=url,
            code=self._auth_code,
            client_secret=self._client_secret,
        )

        self._save_token_on_disk(token)

        return token

    def whoami(self):
        """
        Get information about an access token

        Official docs:
            https://monzo.com/docs/#authenticating-requests
        """
        endpoint = '/ping/whoami'
        url = urljoin(API_URL, endpoint)
        response = self.session.get(url)

        return response.json()

    def accounts(self):
        """
        Returns a list of accounts owned by the currently authorised user.

        Official docs:
            https://monzo.com/docs/#list-accounts
        """<commit_msg>Added token auto refreshing<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import shelve

from requests_oauthlib import OAuth2Session
from six.moves.urllib.parse import urljoin


API_URL = 'https://api.monzo.com/'
PYMONZO_REDIRECT_URI = 'https://github.com/pawelad/pymonzo'

MONZO_ACCESS_CODE_ENV = 'MONZO_ACCESS_CODE'
MONZO_AUTH_CODE_ENV = 'MONZO_AUTH_CODE'
MONZO_CLIENT_ID_ENV = 'MONZO_CLIENT_ID'
MONZO_CLIENT_SECRET_ENV = 'MONZO_CLIENT_SECRET'

TOKEN_FILE_NAME = '.pymonzo-token'
TOKEN_FILE_PATH = os.path.join(os.path.expanduser('~'), TOKEN_FILE_NAME)


class MonzoAPI(object):
    """
    Wrapper for Monzo API.

    Official docs:
        https://monzo.com/docs/
    """
    default_account_id = None

    def __init__(self, access_token=None, client_id=None, client_secret=None,
                 auth_code=None):
        # If no values are passed, try to get them from environment variables
        self._access_token = (
            access_token or os.environ.get(MONZO_ACCESS_CODE_ENV)
        )
        self._client_id = (
            client_id or os.environ.get(MONZO_CLIENT_ID_ENV)
        )
        self._client_secret = (
            client_secret or os.environ.get(MONZO_CLIENT_SECRET_ENV)
        )
        self._auth_code = (
            auth_code or os.environ.get(MONZO_AUTH_CODE_ENV)
        )

        # We try to get the access token from:
        # a) explicitly passed 'access_token'
        if access_token:
            self._token = {
                'access_token': self._access_token,
                'token_type': 'Bearer',
            }
        # b) explicitly passed 'client_id', 'client_secret' and 'auth_code'
        elif all([client_id, client_secret, auth_code]):
            self._token = self._get_oauth_token()
        # c) token file saved on the disk
        elif os.path.isfile(TOKEN_FILE_PATH):
            with shelve.open(TOKEN_FILE_PATH) as f:
                self._token = f['token']
        # d) 'access_token' saved as a environment variable
        elif self._access_token:
            self._token = {
                'access_token': self._access_token,
                'token_type': 'Bearer',
            }
        # e) 'client_id', 'client_secret' and 'auth_code' saved as
        # environment variables
        elif all([self._client_id, self._client_secret, self._auth_code]):
            self._token = self._get_oauth_token()
        else:
            raise ValueError(
                "You need to pass (or set as environment variables) either "
                "explicit 'access_token' or all of 'client_id', "
                "'client_secret' and 'auth_code'"
            )

        # Create a session with newly acquired token
        self.session = OAuth2Session(
            client_id=client_id, token=self._token,
        )

        # Set the default account ID if there is only one available
        if len(self.accounts()) == 1:
            self.default_account_id = self.accounts()[0]['id']

    @staticmethod
    def _save_token_on_disk(token):
        """Helper function that saves passed token on disk"""
        with shelve.open(TOKEN_FILE_PATH) as f:
            f['token'] = token

    def _get_oauth_token(self):
        """
        Get Monzo access token via OAuth2 `authorization_code` grant type.

        Official docs:
            https://monzo.com/docs/#acquire-an-access-token
        """
        endpoint = '/oauth2/token'
        url = urljoin(API_URL, endpoint)

        oauth = OAuth2Session(
            client_id=self._client_id,
            redirect_uri=PYMONZO_REDIRECT_URI,
        )

        token = oauth.fetch_token(
            token_url=url,
            code=self._auth_code,
            client_secret=self._client_secret,
            auto_refresh_url=url,
            auto_refresh_kwargs={
                'grant_type': 'refresh_token',
                'client_id': self._client_id,
                'client_secret': self._client_secret,
            },
            token_updater=self._save_token_on_disk,
        )

        self._save_token_on_disk(token)

        return token

    def whoami(self):
        """
        Get information about an access token

        Official docs:
            https://monzo.com/docs/#authenticating-requests
        """
        endpoint = '/ping/whoami'
        url = urljoin(API_URL, endpoint)
        response = self.session.get(url)

        return response.json()

    def accounts(self):
        """
        Returns a list of accounts owned by the currently authorised user.

        Official docs:
            https://monzo.com/docs/#list-accounts
        """
{'fraction_non_alphanumeric': 0.0941609092935146, 'fraction_numerical': 0.0017829284599955428, 'mean_word_length': 2.1066112841813776, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6677899', 'n_tokens_mistral': 2753, 'n_tokens_neox': 2676, 'n_words': 592}