def get_todays_transactions(monzo: MonzoAPI, account: MonzoAccount) -> List[MonzoTransaction]: log.debug(f"Getting transactions from {account}...") transactions = monzo.transactions(account.id, limit=50) return list( filter(lambda x: x.created.date() == (datetime.today().date()), transactions))
def test_init_oauth(monkeypatch, mocker, client_id, client_secret, auth_code): """ Test initialization with `client_id`, `client_secret` and `auth_code` """ # Mock request that gets the OAuth token mocked_get_oauth_token = mocker.patch.object(MonzoAPI, '_get_oauth_token') mocked_get_oauth_token.return_value = { 'access_token': os.environ.get(MONZO_ACCESS_TOKEN_ENV), 'token_type': 'Bearer', } # Make sure that other auth options are invalid monkeypatch.delenv(MONZO_ACCESS_TOKEN_ENV, raising=False) is_file = mocker.patch('os.path.isfile') is_file.return_value = False # Set the environment variables monkeypatch.setenv(MONZO_CLIENT_ID_ENV, str(uuid4)) monkeypatch.setenv(MONZO_CLIENT_SECRET_ENV, str(uuid4)) monkeypatch.setenv(MONZO_AUTH_CODE_ENV, str(uuid4)) monzo = MonzoAPI( client_id=client_id, client_secret=client_secret, auth_code=auth_code, ) assert monzo assert mocked_get_oauth_token.called assert mocked_get_oauth_token.call_count == 1
def init_monzo(merchants=True): client = MonzoAPI() # Get the ID of the first account linked to the access token account_id = client.accounts()[1].id print("[Monzo] Retrieving transactions...") transactions = client.transactions(account_id) # Get client.transaction( print("[Monzo] Retrieving merchants...") for item in transactions: if merchants: item.merchant = client.transaction(item.id, expand_merchant=True).merchant identifier = item.merchant.name if hasattr(item.merchant, 'name') else item.merchant print("[Monzo] Retrieved merchant {}.".format(identifier)) print("Done.") return transactions
def get_current_account(monzo: MonzoAPI) -> MonzoAccount: log.debug("Getting current account...") current_account = list( filter(lambda x: x.type == "uk_retail", monzo.accounts())) if len(current_account) == 1: log.debug(f"Got {current_account}...") return current_account[0] else: return None
def cli(ctx, access_token): """ Simple command line interface for quickly accessing your Monzo account info, current balance, latest transactions, etc. See https://github.com/pawelad/monz for more info. """ try: ctx.obj = MonzoAPI(access_token=access_token) except (ValueError, PyMonzoException) as e: raise click.ClickException(str(e))
def test_init_no_data(monkeypatch, mocker): """Test initialization with no auth data provided""" # Make sure that all auth options are invalid monkeypatch.delenv(MONZO_ACCESS_TOKEN_ENV, raising=False) monkeypatch.delenv(MONZO_AUTH_CODE_ENV, raising=False) monkeypatch.delenv(MONZO_CLIENT_ID_ENV, raising=False) monkeypatch.delenv(MONZO_CLIENT_SECRET_ENV, raising=False) is_file = mocker.patch('os.path.isfile') is_file.return_value = False with pytest.raises(ValueError): MonzoAPI()
def test_init_access_token(monkeypatch, mocker, access_token): """Test initialization with only `access_token` provided""" # Make sure that other auth options are invalid monkeypatch.delenv(MONZO_AUTH_CODE_ENV, raising=False) monkeypatch.delenv(MONZO_CLIENT_ID_ENV, raising=False) monkeypatch.delenv(MONZO_CLIENT_SECRET_ENV, raising=False) is_file = mocker.patch('os.path.isfile') is_file.return_value = False monzo = MonzoAPI(access_token=access_token) assert monzo assert monzo._token['access_token'] == os.environ.get( MONZO_ACCESS_TOKEN_ENV) assert monzo._token['token_type'] == 'Bearer'
def mocked_monzo(self, mocker): """Helper fixture that returns a mocked `MonzoAPI` instance""" mocker.patch('pymonzo.monzo_api.OAuth2Session') mocker.patch('pymonzo.monzo_api.MonzoAPI._save_token_on_disk') client_id = 'explicit_client_id' client_secret = 'explicit_client_secret' auth_code = 'explicit_auth_code' monzo = MonzoAPI( client_id=client_id, client_secret=client_secret, auth_code=auth_code, ) return monzo
def test_class_initialization(self, monkeypatch, mocker): """ Test class `__init__` method. Quite long and complicated because of the number of possible scenarios. Possibly to revisit in the future. """ access_token = 'explicit_access_token' client_id = 'explicit_client_id' client_secret = 'explicit_client_secret' auth_code = 'explicit_auth_code' redirect_url = 'explicit_redirect_url' monkeypatch.setenv(config.MONZO_ACCESS_TOKEN_ENV, 'env_access_token') monkeypatch.setenv(config.MONZO_CLIENT_ID_ENV, 'env_client_id') monkeypatch.setenv(config.MONZO_CLIENT_SECRET_ENV, 'env_client_secret') monkeypatch.setenv(config.MONZO_AUTH_CODE_ENV, 'env_auth_code') # When we provide all variables both explicitly and via environment # variables, the explicit 'access token' should take precedence mocker.patch('os.path.isfile', return_value=True) mocked_oauth2_session = mocker.patch('pymonzo.monzo_api.OAuth2Session') expected_token = { 'access_token': 'explicit_access_token', 'token_type': 'Bearer', } monzo = MonzoAPI( access_token=access_token, client_id=client_id, client_secret=client_secret, auth_code=auth_code, redirect_url=redirect_url ) assert monzo._access_token == 'explicit_access_token' assert monzo._redirect_url == redirect_url assert monzo._client_id is None assert monzo._client_secret is None assert monzo._auth_code is None assert monzo._token == expected_token mocked_oauth2_session.assert_called_once_with( client_id=None, token=expected_token, ) # Don't pass 'access_token' explicitly mocked_oauth2_session = mocker.patch('pymonzo.monzo_api.OAuth2Session') mocked_get_oauth_token = mocker.patch( 'pymonzo.monzo_api.MonzoAPI._get_oauth_token' ) mocked_save_token_on_disk = mocker.patch( 'pymonzo.monzo_api.MonzoAPI._save_token_on_disk' ) expected_token = mocked_get_oauth_token.return_value monzo = MonzoAPI( client_id=client_id, client_secret=client_secret, auth_code=auth_code, ) assert monzo._access_token is None assert monzo._client_id == 'explicit_client_id' assert monzo._client_secret == 'explicit_client_secret' assert monzo._auth_code == 'explicit_auth_code' assert monzo._token == expected_token mocked_get_oauth_token.assert_called_once_with() mocked_save_token_on_disk.assert_called_once_with() mocked_oauth2_session.assert_called_once_with( client_id='explicit_client_id', token=expected_token, ) # Don't pass anything explicitly and the token file exists mocked_oauth2_session = mocker.patch('pymonzo.monzo_api.OAuth2Session') mocker.patch('os.path.isfile', return_value=True) mocked_open = mocker.patch('codecs.open', mocker.mock_open()) mocked_json_load = mocker.patch('json.load') expected_token = mocked_json_load.return_value monzo = MonzoAPI() assert monzo._access_token is None assert monzo._client_id is expected_token['client_id'] assert monzo._client_secret is expected_token['client_secret'] assert monzo._auth_code is None assert monzo._token == expected_token mocked_open.assert_called_once_with( config.TOKEN_FILE_PATH, 'r', 'utf-8', ) mocked_json_load.assert_called_once_with(mocked_open.return_value) mocked_get_oauth_token.assert_called_once_with() mocked_oauth2_session.assert_called_once_with( client_id=expected_token['client_id'], token=expected_token, ) # Don't pass anything explicitly, the token file doesn't exist # and 'access_token' environment variable exists mocked_oauth2_session = mocker.patch('pymonzo.monzo_api.OAuth2Session') mocker.patch('os.path.isfile', return_value=False) expected_token = { 'access_token': 'env_access_token', 'token_type': 'Bearer', } monzo = MonzoAPI() assert monzo._access_token == 'env_access_token' assert monzo._client_id is None assert monzo._client_secret is None assert monzo._auth_code is None assert monzo._token == expected_token mocked_oauth2_session.assert_called_once_with( client_id=None, token=expected_token, ) # Don't pass anything explicitly, the token file doesn't exist # and 'access_token' environment variable doesn't exist monkeypatch.delenv(config.MONZO_ACCESS_TOKEN_ENV) mocked_oauth2_session = mocker.patch('pymonzo.monzo_api.OAuth2Session') mocked_get_oauth_token = mocker.patch( 'pymonzo.monzo_api.MonzoAPI._get_oauth_token' ) mocked_save_token_on_disk = mocker.patch( 'pymonzo.monzo_api.MonzoAPI._save_token_on_disk' ) expected_token = mocked_get_oauth_token.return_value monzo = MonzoAPI() assert monzo._access_token is None assert monzo._client_id == 'env_client_id' assert monzo._client_secret == 'env_client_secret' assert monzo._auth_code == 'env_auth_code' assert monzo._token == expected_token mocked_get_oauth_token.assert_called_once_with() mocked_save_token_on_disk.assert_called_once_with() mocked_oauth2_session.assert_called_once_with( client_id='env_client_id', token=expected_token, ) # None of the above monkeypatch.delenv(config.MONZO_CLIENT_ID_ENV) with pytest.raises(ValueError): MonzoAPI( auth_code=auth_code, client_id=client_id, )
def monzo(self): """Helper fixture that returns a `MonzoAPI` instance""" return MonzoAPI(access_token='explicit_access_token')
# Get this by authorizing your new client app using this URL: # https://auth.monzo.com/?response_type=code&redirect_uri=https://github.com/pawelad/pymonzo&client_id={{monzoClientID}} # Then check the URL you're redirected to for the "code" parameter monzoClientAuthCode = '' # Only needed when running on a new machine - this generates ~/.pymonzo-token which is then used when instantiating # monzo = MonzoAPI( # client_id=monzoClientID, # client_secret=monzoClientSecret, # auth_code=monzoClientAuthCode, # ) # exit(0) # Instantiate Monzo API client normally, using tokens from ~/.pymonzo-token generated previously monzo = MonzoAPI() # Create method to handle non-serializable data types in transaction object def json_default(value): if isinstance(value, datetime.date): return value.isoformat() else: return value.__dict__ # Loop through all transactions and post them all to YNAB via fintech-to-ynab app deployed on Heroku for monzoTransactionSimple in monzo.transactions(): # Fetch full transaction details including merchant, as otherwise merchant name etc. is missing monzoTransactionFull = monzo.transaction(monzoTransactionSimple.id, True)
import json import requests from operator import attrgetter import codecs import os from pymonzo import MonzoAPI monzo = MonzoAPI() template = 'screen-output-weather.svg' MONZO_ACCOUNT_NAME=os.getenv("MONZO_ACCOUNT_NAME","") MONZO_POT_1_NAME=os.getenv("MONZO_POT_1_NAME","") MONZO_POT_2_NAME=os.getenv("MONZO_POT_2_NAME","") MONZO_POT_3_NAME=os.getenv("MONZO_POT_3_NAME","") monzoBalance = 'Undefined' pot1 = 'Undefined' pot2 = 'Undefined' pot3 = 'Undefined' monzoBalance = MONZO_ACCOUNT_NAME + ': £' + "{:.2f}".format(monzo.balance().balance/100) pots = monzo.pots() for pot in pots: if pot.name == MONZO_POT_1_NAME: pot1 = str(pot.name) + ': £' + "{:.2f}".format(float(pot.balance)/100) if pot.name == MONZO_POT_2_NAME: pot2 = str(pot.name) + ': £' + "{:.2f}".format(float(pot.balance)/100) if pot.name == MONZO_POT_3_NAME: pot3 = str(pot.name) + ': £' + "{:.2f}".format(float(pot.balance)/100)
def monzo(): """Create a `MonzoAPI` instance""" return MonzoAPI(access_token=os.environ.get(MONZO_ACCESS_TOKEN_ENV))
def test_raising_exception(): """Test API error caching and exception raising""" with pytest.raises(MonzoAPIException): MonzoAPI(access_token=str(uuid4))
def get_api() -> MonzoAPI: # TODO - Check connectivity - see https://github.com/pawelad/pymonzo/blob/master/src/pymonzo/exceptions.py log.debug("Connecting to api...") return MonzoAPI()