Python based Paymo API

So I think I’ve written before about the cloud based time tracking software I use; Paymo, well I’ve been working on a project to improve the invoicing side of it. Paymo does produce invoices but I find they’re a little bland, and they currently don’t meet the requirements set out by the ATO, so I have to produce my own manually.

This being a time consuming process I thought I’d automate it, and combining another side project I figured why not use it as a chance to improve my Python and Django skills. So it was a very nice relief to find that someone has already written a Python based library to the Paymo API – http://scardine.github.com/paymo/. Although it shouldn’t really come a surprise, part of my deciding what coding language would be a good choice was finding out what kind of community support and adoption each language had. So I guess it’s really confirmation of some research and means I chose wisely; young Jedi.

Everything isn’t all beer and skittles though trying to install it from pip failed, so I had to do some manual intervention to get it installed. Here’s what I did in case it helps someone else.

firewall # pip install paymo
Downloading/unpacking paymo
Downloading paymo-0.0.2.zip
Running setup.py egg_info for package paymo
Traceback (most recent call last):
File "", line 16, in 
File "/tmp/pip-build/paymo/setup.py", line 15, in
long_description=open("README.TXT").read(),
IOError: [Errno 2] No such file or directory: 'README.TXT'
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 16, in 
File "/tmp/pip-build/paymo/setup.py", line 15, in
long_description=open("README.TXT").read(),
IOError: [Errno 2] No such file or directory: 'README.TXT'
----------------------------------------
Command python setup.py egg_info failed with error code 1 in /tmp/pip-build/paymo
Storing complete log in /root/.pip/pip.log

Looks like the first problem was unpacking and installing the python package itself.

firewall # cd /tmp/pip-build/paymo/
firewall # ls -la
total 28
drwxr-xr-x 4 root root 4096 Jan 30 12:11 .
drwxr-xr-x 3 root root 4096 Jan 30 12:11 ..
-rw-r--r-- 1 root root  978 Jan 30 12:11 PKG-INFO
-rw-r--r-- 1 root root  269 Jan 30 12:11 README.txt
drwxr-xr-x 2 root root 4096 Jan 30 12:11 paymo
drwxr-xr-x 2 root root 4096 Jan 30 12:11 pip-egg-info
-rw-r--r-- 1 root root  953 Jan 30 12:11 setup.py
firewall # mv README.txt README.TXT

Fairly easily fixed, it was looking for README.TXT but the file is called README.txt, Linux being case sensitive sees those as 2 different files. I suspect it was probably tested under Windows which is not case sensitive. A quick rename and we’re back installing correctly with no errors.

firewall # python
Python 2.7.2 (default, Nov 15 2011, 13:17:26)
[GCC 4.5.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from paymoapi import PaymoAPI
Traceback (most recent call last):
File "", line 1, in 
ImportError: No module named paymoapi
>>> from paymo.api import PaymoAPI
Traceback (most recent call last):
File "", line 1, in 
File "/usr/lib64/python2.7/site-packages/paymo/api.py", line 1, in
import requests
ImportError: No module named requests
>>> quit()

Now that it’s installed a simple test to confirm it works. Note the first attempt to import the library is based upon the Example given at the developer’s site http://scardine.github.com/paymo/ and contains this typo. The correct import should be from paymo.api not from paymoapi. Any other examples I’ve seen on the web also contain this error.

Anyhow that’s a sideline the major problem here is the import requests failing. Seems it’s dependent on the requests library.

firewall # pip install requests
Downloading/unpacking requests
Downloading requests-1.1.0.tar.gz (337kB): 337kB downloaded
Running setup.py egg_info for package requests
Installing collected packages: requests
Running setup.py install for requests
Successfully installed requests
Cleaning up...

Simple install using pip, and take 2.

firewall # python
Python 2.7.2 (default, Nov 15 2011, 13:17:26)
[GCC 4.5.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from paymo.api import PaymoAPI
Traceback (most recent call last):
File "", line 1, in 
File "/usr/lib64/python2.7/site-packages/paymo/api.py", line 5, in
from pyquery import PyQuery as pq
ImportError: No module named pyquery
>>> quit()

Doh! Another module dependency, this time pyquery.

firewall # pip install pyquery
Downloading/unpacking pyquery
Downloading pyquery-1.2.4.zip
Running setup.py egg_info for package pyquery
Downloading/unpacking lxml>=2.1 (from pyquery)
.......
Successfully installed pyquery lxml cssselect
Cleaning up...

Again a quick pip and hopefully good to go.

firewall # python
Python 2.7.2 (default, Nov 15 2011, 13:17:26)
[GCC 4.5.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from paymo.api import PaymoAPI

Well it imports that’s a good sign.

>>> paymo = PaymoAPI('apikey’, 'username', 'password’)
>>> paymo.users.getList()
{u'status': u'error', u'error': {u'message': u'Invalid auth token / Login failed', u'code': u'104'}}
>>> quit()
firewall #

That’s not a good sign, I did use my real username passwords etc. in the correct spots here but it seems to be throwing login errors. If you put in wrong entries or garbage it won’t even assign the class to the paymo variable, so I know the username and password is working OK, but looks like there’s a/some bug(s) in the library, which will have to wait till another time to sort out.

You may note that it was all done under Python 2.7, I however am trying to code anything I do in Python 3.x wherever possible as eventually 2.x will be phased out. So I thought I’d give it a try and see how it installs under Python 3.2. Thankfully with Gentoo it’s easy to switch between versions.

firewall tmp # eselect python list
Available Python interpreters:
[1]   python2.7 *
[2]   python3.2
firewall tmp # eselect python set 2
firewall tmp # eselect python list
Available Python interpreters:
[1]   python2.7
[2]   python3.2 *
firewall tmp # python -V
Python 3.2.3

So at this point I installed it again and had to repeat the above dependencies and case sensitive renaming, but apart from that hassle free. So time to see how it runs.

firewall tmp # python
Python 3.2.3 (default, May 28 2012, 11:39:24)
[GCC 4.5.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from paymo.api import PaymoAPI
Traceback (most recent call last):
File "", line 1, in 
File "/usr/lib64/python3.2/site-packages/paymo/api.py", line 33
return u"{0}\n{1}\n{0}\n\n".format(c * len(s), s)
^
SyntaxError: invalid syntax
>>> exit()
firewall tmp #

Oops not so good, but a fairly common problem for 2.x to 3.x code, and mentioned in the “what’s new in 3.0” guide. A quick search and replace removing all the u”” to be just “” fixes that. For example;

return u"{0}\n{1}\n{0}\n\n".format(c * len(s), s)

becomes

return "{0}\n{1}\n{0}\n\n".format(c * len(s), s)

Trying again now throws syntax errors about print statements, again a common version 2 to 3 problem, as print is now a function instead of a statement. Once again a simple search and replace to add parentheses around any print statements. For example;

print self.parent.__class__

becomes

print(self.parent.__class__)

Final test and all is well, except for the whole Login failure issue, but at this point that’s expected behaviour. I know I could have also just run 2to3 on api.py which would perform all the necessary conversions for me, but I wanted to test my knowledge of Python 3. I did however run 2to3 to check my work and the only suggestion it made was to change import urllib for the more specific import urllib.request, urllib.parse, urllib.error. Not a bad effort for someone whose was new to python only 2 weeks ago.
Quick update: Seems there might be another api wrapper for Paymo although a little crude it might work better (well work at all), I might have to give it a go tomorrow.