pawelad / pymonzo Goto Github PK
View Code? Open in Web Editor NEWModern Python API client for Monzo public API.
Home Page: https://pymonzo.pawelad.dev/
License: Mozilla Public License 2.0
Modern Python API client for Monzo public API.
Home Page: https://pymonzo.pawelad.dev/
License: Mozilla Public License 2.0
When MonzoAPI() is called with keyword arguments (i.e. not using env variables) I get the following response:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/pymonzo/monzo_api.py", line 76, in __init__
self._token = self._get_oauth_token()
File "/usr/local/lib/python2.7/dist-packages/pymonzo/monzo_api.py", line 155, in _get_oauth_token
client_secret=self._client_secret,
File "/usr/local/lib/python2.7/dist-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/usr/local/lib/python2.7/dist-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 411, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/usr/local/lib/python2.7/dist-packages/oauthlib/oauth2/rfc6749/parameters.py", line 379, in parse_token_response
validate_token_parameters(params)
File "/usr/local/lib/python2.7/dist-packages/oauthlib/oauth2/rfc6749/parameters.py", line 386, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/usr/local/lib/python2.7/dist-packages/oauthlib/oauth2/rfc6749/errors.py", line 415, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidClientIdError: (invalid_request) Invalid redirect URI
I'm assuming this is to do with how I have configured the client on the Monzo dev portal, but I can't see what's wrong with it?
Using transaction() is returning [<class 'pymonzo.api_objects.MonzoTransaction'>
instead of the expected output MonzoTransaction({data here})
(MonzoTransaction object).
Or is this expected output?
pymonzo version: v0.11.0
(latest)
This started happening for me since 15.03.2022:
Stacktrace:
...
File "/app/export.py", line 44, in <genexpr>
self.api.transaction(t['id'], expand_merchant=True)._raw_data
File "/usr/local/lib/python3.8/site-packages/pymonzo/monzo_api.py", line 398, in transaction
return MonzoTransaction(data=response.json()['transaction'])
File "/usr/local/lib/python3.8/site-packages/pymonzo/api_objects.py", line 42, in __init__
self._parse_special_fields(data_copy)
File "/usr/local/lib/python3.8/site-packages/pymonzo/api_objects.py", line 117, in _parse_special_fields
self.merchant = MonzoMerchant(data=data.pop('merchant'))
File "/usr/local/lib/python3.8/site-packages/pymonzo/api_objects.py", line 33, in __init__
raise ValueError(
ValueError: Passed data doesn't have all required keys (missing keys: created)
More debugging:
DEBUG:requests_oauthlib.oauth2_session:Passing through key word arguments {'params': {'expand[]': 'merchant'}, 'allow_redirects': True}.
DEBUG:urllib3.connectionpool:https://api.monzo.com:443 "GET /transactions/tx_XXXXXXXXXXXXXXX?expand%5B%5D=merchant HTTP/1.1" 200 None
(Pdb) self.api._get_response(method='get', endpoint=f"/transactions/{transactions[0]['id']}", params={'expand[]': 'merchant'}).json()['transaction']['merchant']
{'id': 'merch_0000A7F9qhxKe3RynPV14E', 'group_id': 'grp_000092JZy7UcN7FpKMkvh3', 'name': 'Deliveroo', 'logo': 'https://mondo-logo-cache.appspot.com/twitter/deliveroo/?size=large', 'emoji': '๐๐ฆ', 'category': 'eating_out', 'online': True, 'atm': False, 'address': {'short_formatted': 'Somewhere in the United Kingdom', 'city': '', 'latitude': 54.557817, 'longitude': -3.484688, 'zoom_level': 4, 'approximate': True, 'formatted': 'United Kingdom', 'address': '', 'region': '', 'country': 'GBR', 'postcode': ''}, 'disable_feedback': False, 'suggested_tags': '#groceries #food, #delivery #yum', 'metadata': {'suggested_tags': '#groceries #food, #delivery #yum', 'website': 'www.deliveroo.co.uk'}
So merchant creation date is missing from the payload. I couldn't find API docs for merchants, so not sure if it's just not passed by the API now
Possibly related: monzo/docs#71
I tried monkey patching it with the following snippet:
M_keys = MonzoMerchant._required_keys
if 'created' in M_keys:
M_keys.remove('created')
But sadly this fails with, so seems created
is hardcoded in pymonzo code
File "/usr/local/lib/python3.8/site-packages/pymonzo/api_objects.py", line 117, in _parse_special_fields
self.merchant = MonzoMerchant(data=data.pop('merchant'))
File "/usr/local/lib/python3.8/site-packages/pymonzo/api_objects.py", line 42, in __init__
self._parse_special_fields(data_copy)
File "/usr/local/lib/python3.8/site-packages/pymonzo/api_objects.py", line 136, in _parse_special_fields
self.created = parse_date(data.pop('created'))
KeyError: 'created`
So I think for now, for my monzoexport, I'll just use the raw __get_response
method. But let me know if you're interested in a proper fix, I might come up with some PR. Thanks!
I am getting errors when running the MonzoAPI() command after exporting the authorisation environment variables.
Also it is not clear from where I should get the auth code to input. Is the code the whole URL from the email or just the part after 'code='?
Thank you.
m.MonzoAPI()
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python3.6/site-packages/pymonzo/monzo_api.py", line 95, in init
self._token = self._get_oauth_token()
File "/usr/local/lib/python3.6/site-packages/pymonzo/monzo_api.py", line 144, in _get_oauth_token
client_secret=self._client_secret,
File "/usr/local/lib/python3.6/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/usr/local/lib/python3.6/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/usr/local/lib/python3.6/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
validate_token_parameters(params)
File "/usr/local/lib/python3.6/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/usr/local/lib/python3.6/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 404, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.ServerError: (server_error) Unknown error occurred
Allow custom redirect_uri
values, probably via an environment variable. Extracted from #12
Hello everyone,
I have managed to set up the API access following all the instructions in the readme, saving the client ID, client secret and auth code in the auth.py file. The codes work when I run them normally, i.e. python3 filename.py, and I can obtain my transaction data, balance, etc. with no problem.
However, I am also using the Adafruit Neopixel library to control some LED lights at the same time. The library can be found here: https://github.com/adafruit/Adafruit_NeoPixel
Using this library apparently has two constraints: it has to be run in Python 3, and it has to be run as root. The documentation explains that "For NeoPixels to work on Raspberry Pi, you must run the code as root! Root access is required to access the RPi peripherals." Further documentation can be found here: https://cdn-learn.adafruit.com/downloads/pdf/neopixels-on-raspberry-pi.pdf
The problem is, I can't seem to run the PyMonzo codes when I run as root (i.e. sudo python3 filename.py). The error I get is:
Traceback (most recent call last):
File "filename.py", line 34, in
monzo = MonzoAPI( )
File "/usr/local/lib/python3.5/dist-packages/pymonzo/monzo_api.py", line 106, in init
"To authenticate and use Monzo public API you need to pass "
ValueError: To authenticate and use Monzo public API you need to pass (or set as environment variables either the access token or all of client ID, client secret and authentication code. For more info see https://github.com/pawelad/pymonzo#authentication
If I run the code normally without using sudo, the error I get is:
Can't open /dev/mem: Operation not permitted
Traceback (most recent call last):
File "filename.py", line 66, in
neopix.show( )
.....
RuntimeError: ws2811_init failed with code -5 (mmap( ) failed)
swig/python detected a memory leak of type 'ws2811_t *', no destructor found
Does anyone know if there is a way to deconflict between these two operations, perhaps a way that pyMonzo can be run as root?
I have tried running sudo chmod 666 /dev/mem, and running it without sudo.
Thank you very much.
As per Monzo docs https://monzo.com/docs/#acquire-an-access-token
They now require a redirect URI,
pip installed version error code
oauthlib.oauth2.rfc6749.errors.InvalidClientIdError: (invalid_request) The supplied redirect_uri is different from the one used to issue this code
Various URLs in the readme still refer to getmondo.co.uk
and need to be changed to monzo.com
or they won't work.
Per comments in #2 , the token file (~/.pymonzo-token
) for some reason has a .db
extension on OS X which makes pymonzo
think it does not exist.
When creating MonzoAPI object using environmental variables, I get the following error:
"AttributeError: DbfilenameShelf instance has no attribute '__exit__' "
This occurs on any method that is used to interact with the access token on disk.
Hi there,
Thanks again for the help with the previous issue.
Is there a way for me to restart my machine and then use MonzoAPI() without getting another Auth_Code for my Client?
Thanks,
Jack
I have this code to export a CSV:
import csv
from pymonzo import MonzoAPI
if __name__ == '__main__':
monzo_api = MonzoAPI()
monzo_transactions = monzo_api.transactions()
with open('monzo_transactions.csv', 'w') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([
'transaction.amount', 'transaction.description', 'transaction.created',
])
for transaction in monzo_transactions:
writer.writerow([
transaction.amount, transaction.description, transaction.created,
])
print('MONZO DATA SAVED!')
I also want to get my balance at the date of the transaction. Really for the purposes of this project all I need are [DATE] and [BALANCE] columns.
I can see that balance is part of the transaction information under 'account_balance' but I can't seem to just add it like with the others in the code.
Any ideas?
I apologise if I should not be putting these questions in the issues section.
Thanks.
It would seem that tests that use 'vcr' are failing.
I don't know enough about this to even begin to understand what it is failing on, but it makes it harder to find genuine test failures when these tests are always failing.
FAILED tests/pymonzo/test_accounts.py::TestAccountsResource::test_list_vcr - vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('tests/pymonzo/cassettes/test_accounts/TestAccountsResource.test_list_vcr.yaml') in your current record mode ('none').
FAILED tests/pymonzo/test_balance.py::TestBalanceResource::test_list_vcr - vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('tests/pymonzo/cassettes/test_balance/TestBalanceResource.test_list_vcr.yaml') in your current record mode ('none').
FAILED tests/pymonzo/test_pots.py::TestPotsResource::test_list_vcr - vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('tests/pymonzo/cassettes/test_pots/TestPotsResource.test_list_vcr.yaml') in your current record mode ('none').
FAILED tests/pymonzo/test_whoami.py::TestWhoAmIResource::test_whoami_vcr - vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('tests/pymonzo/cassettes/test_whoami/TestWhoAmIResource.test_whoami_vcr.yaml') in your current record mode ('none').
Running monzo_api.transactions.list(account_id=account_id, expand_merchant=True)
produces pydantic errors:
pydantic_core._pydantic_core.ValidationError: 2 validation errors for MonzoTransaction
merchant.MonzoTransactionMerchant.suggested_tags
Field required [type=missing, input_value={'id': 'merch_0000ADdaX06...: False, 'metadata': {}}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.7/v/missing
merchant.str
Input should be a valid string [type=string_type, input_value={'id': 'merch_0000ADdaX06...: False, 'metadata': {}}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.7/v/string_type
These look like they could be tied together... I don't see a 'suggested_tags' option in any of the transactions I have.
As per #3, I will be changing token file format from shelve
to just using a JSON file. That means the file will need to be regenerated, which we should probably warn about.
I still very much like the idea of https://github.com/kevin1024/vcrpy, but I think it works best when the API is publicly accessible and doesn't contain any sensitive data.
Right now, I'm using it alongside https://github.com/CarloDePieri/vcrpy-encrypt, but that means the tests can't be run in PRs opened by other people.
Thus, I think I should just migrate the VCR.py tests to use https://github.com/lundberg/respx instead.
Hi, just noticed there is a dev branch, that seems more up to date with main. Just wondering if you're ever planning to merge it in main and release? :)
When using the python interpreter to set up OAuth as suggested in the README, it fails because:
MonzoAPI._token
is set in MonzoAPI.__init__
by calling self_get_oauth_token()
self._save_token_on_disk()
before returning_save _token_on_disk()
tries to do token = self._token.copy()
, but fails with AttributeError: 'MonzoAPI' object has no attribute '_token'
becasue _token
isn't set yet because _get_oauth_token()
has not yet returned.There was a use case where the reauth wasn't doing the required actions. I added my own checks in to see what was happening. The response code from the server was 401 which means you are unauthorised. Upon this error, it was also failing to re-authenticate. The error codes can be seen in the documentation here - https://monzo.com/docs/#errors.
If I run across the error again, I'll get some more debugging information added in to see what is actually happening in the long term.
Minimal code snippet below to see when it was happening:
from ConfigParser import ConfigParser
import pymonzo
conf = ConfigParser()
conf.read('api_info.conf')
data = dict(conf.items('monzo'))
api = pymonzo.MonzoAPI(client_id=data['client_id'], client_secret=data['client_secret'])
The token file is created without specifying a mask so it will usually be world readable on Unix systems.
At the moment getting transactions that have custom categories doesn't appear to be supported.
Monzo supports custom categories as part of the Plus plan (src).
When running monzo_api.transactions.list()
I get the following error:
self.__pydantic_validator__.validate_python(data, self_instance=self)
pydantic_core._pydantic_core.ValidationError: 1 validation error for MonzoTransaction
category
Input should be 'general', 'eating_out', 'expenses', 'transport', 'cash', 'bills', 'entertainment', 'shopping', 'holidays', 'groceries', 'income', 'savings' or 'transfers' [type=enum, input_value='family', input_type=str]
In this case it's because a new category - "family" - has been added. However, I can see via the API playground that custom categories are encoded like this - "category_0000AeR8A0F6XTLXKTDADB" and this won't be supported by an enum.
Would be great to be able to still get transactions even if the categories don't exist in the enum. Maybe warn instead?
Thanks for the project, this is great!
I was hoping to be able to do json.dumps(monzoTransaction)
but get TypeError(repr(o) + " is not JSON serializable")
- I'm working around this, but it would be really handy for the use case I'm working on (a tool to batch-import transactions into YNAB)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.