{ "info": { "author": "Alexander Brown", "author_email": "alexrybrown@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Intended Audience :: Financial and Insurance Industry", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Office/Business :: Financial :: Accounting" ], "description": "PyXero\n======\n\n[![Build Status](https://travis-ci.org/freakboy3742/pyxero.svg?branch=master)](https://travis-ci.org/freakboy3742/pyxero)\n\nPyXero is a Python API for accessing the REST API provided by the [Xero](http://developer.xero.com)\naccounting tool. It allows access to both Public, Private and Partner applications.\n\nThis code is based off the [sample code provided by Xero](http://developer.xero.com/getting-started/code/python/), which was\ncontributed by [IRESS Wealth Management](http://www.iress.com.au), and the [XeroPy](https://github.com/fatbox/XeroPy) packaged version of\nthat code.\n\nThis packages differs in three significant was from `XeroPy`:\n\n* It uses the popular [requests](http://python-requests.org) library (and the [requests-oauthlib](https://github.com/requests/requests-oauthlib)\n extension) instead of httplib2.\n* It uses the pure-python [PyCrypto](https://www.dlitz.net/software/pycrypto/) library instead of the hard-to-compile\n native M2Crypto wrapper for RSA signing.\n* It has been tested on Public, Private and Partner Xero Applications.\n\n\n## Quickstart:\n\nIn addition to the instructions shown here, you'll need to follow the [Xero\nDeveloper documentation](http://developer.xero.com/api-overview/) to register your application.\n\n### Public Applications\n\nPublic applications use a 3-step OAuth process.\n\nWhen you [register your public application with Xero](http://developer.xero.com/api-overview/public-applications/), you'll be given a\n**Consumer Key** and a **Consumer secret**. These are both strings.\n\nTo access the Xero API you must first create some credentials:\n\n```python\n>>> from xero.auth import PublicCredentials\n>>> credentials = PublicCredentials(, )\n>>> print credentials.url\n'http://my.xero.com/.....'\n```\n\nYou now direct the user to visit the URL described by `credentials.url`. They\nwill be asked to log into their Xero account, and then shown a request to\nauthenticate your request to access the user's account. When the allow access,\nthey will be directed to a page that gives them a 6-digit verification number.\nPut this verifier number into a string, and call `verify()` on the credentials\nobject::\n\n```python\n>>> credentials.verify()\n```\n\nThis will verify your credentials, and retrieve an access token. You can\nthen use your credentials to instantiate an instance of the Xero API::\n\n```python\n>>> from xero import Xero\n>>> xero = Xero(credentials)\n```\n\n### Public Applications with verification by callback\n\nPublic applications can also be validated using a callback URI. If this\napproach is used, the user won't be given a verification number. Instead,\nwhen they authorize the OAuth request, their browser will be redirected to\na pre-configured callback URI, which will deliver the validation token\ndirectly to your application.\n\nTo use a callback, you must provide a domain as part of your Xero application\nregistration; then, you provide a URL under that domain as the third argument\nwhen creating the credentials::\n\n```python\n>>> credentials = PublicCredentials(, , )\n>>> print credentials.url\n'http://my.xero.com/.....'\n```\n\nWhen the user authorizes access to their Xero account, the `callback_url`\nwill be called with three GET arguments:\n\n* `oauth_token`: The oauth_token that this request belongs to\n* `verifier`: The verifier string\n* `org`: An identifier for the organization that is allowing access.\n\nThe verifier can then be used to verify the credentials, as with the manual\nprocess.\n\n### Reconstructing Public credentials\n\nPublic Applications use a 3-step OAuth process, and if you're doing this in a\nweb application, you will usually lose the credentials object over the\nverification step. This means you need to be able to restore the credentials\nobject when verification has been provided.\n\nThe `state` attribute of a credentials object contains all the details needed\nto reconstruct an instance of the credentials::\n\n```python\n>>> saved_state = credentials.state\n>>> print saved_state\n{'consumer_key': '...', 'consumer_secret': '...', ...}\n\n>>> new_credentials = PublicCredentials(**saved_state)\n```\n\n### Private Applications\n\nIf using a Private application, you will need to install `PyCrypto`, a pure\nPython cryptographic module. You'll also need to generate an signed RSA\ncertificate, and submit that certificate as part of registering your\napplication with Xero. See the [Xero Developer documentation](http://developer.xero.com/api-overview/) for more\ndetails.\n\nWhen you [register your private application with Xero](http://developer.xero.com/api-overview/private-applications/), you'll be given a\n**Consumer Key**. You'll also be given a **Consumer secret** - this can be\nignored.\n\nUsing the Private credentials is much simpler than the Public credentials,\nbecause there's no verification step -- verification is managed using RSA\nsigned API requests::\n\n```python\n>>> from xero import Xero\n>>> from xero.auth import PrivateCredentials\n>>> with open() as keyfile:\n... rsa_key = keyfile.read()\n>>> credentials = PrivateCredentials(, rsa_key)\n>>> xero = Xero(credentials)\n```\n\nThe RSA key is a multi-line string that will look something like::\n\n -----BEGIN RSA PRIVATE KEY-----\n MIICXgIBAAKBgQDWJbmxJjQLGM76sZkk2EhsdpV0Gxtrhzh/wiNBGffa5JHV/Ex4\n ....\n mtXGQjKqsOpuCw7HwgnRQUWKYbaJ3a+yTCFjVwa9keQhDQ==\n -----END RSA PRIVATE KEY-----\n\nYou can get this string by either reading the contents of your private key\nfile into a variable, or storing the key value as a constant. If you choose to\nstore the key value as a constant, remember two things:\n\n* **DO NOT UNDER ANY CIRCUMSTANCES** check this file into a public\n repository. It is your identity, and anyone with access to this file\n could masquerade as you.\n\n* Make sure there is no leading space before\n the ``-----BEGIN PRIVATE KEY-----`` portion of the string.\n\n\n### Partner Applications\n\nPartner Application authentication works similarly to the 3-step OAuth used by\nPublic Applications, but with RSA signed requests and a client-side SSL\ncertificate which is issued by Xero. Partner OAuth tokens still have a 30 minute\nexpiry, but can be swapped for a new token at any time.\n\nWhen you [register your partner application with Xero](http://developer.xero.com/api-overview/partner-applications/), you'll have a\n**Consumer Key**, **Consumer Secret**, **RSA Key**, and **Client Certificate**.\nAll four elements are required.\n\nThe client certificate is represented by a tuple of file paths to the certificate\nand key.\n\n```python\n>>> from xero import Xero\n>>> from xero.auth import PartnerCredentials\n>>> client_cert = ('/path/to/entrust-cert.pem',\n... '/path/to/entrust-private-nopass.pem')\n>>> credentials = PartnerCredentials(, ,\n... , client_cert)\n>>> xero = Xero(credentials)\n```\n\nWhen using the API over an extended period, you will need to exchange tokens\nwhen they expire.\n\n```python\n>>> if credentials.expired():\n... credentials.refresh()\n```\n\n**Important**: ``credentials.state`` changes after a token swap. Be sure to persist\nthe new state.\n\n\n## Using the Xero API\n\n*This API is a work in progress. At present, there is no wrapper layer\nto help create real objects, it just returns dictionaries in the exact\nformat provided by the Xero API. This will change into a more useful API\nbefore 1.0*\n\nThe Xero API object exposes a simple API for retrieving and updating objects.\nFor example, to deal with contacts::\n\n```python\n# Retrieve all contact objects\n>>> xero.contacts.all()\n[{...contact info...}, {...contact info...}, {...contact info...}, ...]\n\n# Retrieve a specific contact object\n>>> xero.contacts.get(u'b2b5333a-2546-4975-891f-d71a8a640d23')\n{...contact info...}\n\n# Retrive all contacts updated since 1 Jan 2013\n>>> xero.contacts.filter(since=datetime(2013, 1, 1))\n[{...contact info...}, {...contact info...}, {...contact info...}]\n\n# Retrive all contacts whose name is 'John Smith'\n>>> xero.contacts.filter(Name='John Smith')\n[{...contact info...}, {...contact info...}, {...contact info...}]\n\n# Retrive all contacts whose name starts with 'John'\n>>> xero.contacts.filter(Name__startswith='John')\n[{...contact info...}, {...contact info...}, {...contact info...}]\n\n# Retrive all contacts whose name ends with 'Smith'\n>>> xero.contacts.filter(Name__endswith='Smith')\n[{...contact info...}, {...contact info...}, {...contact info...}]\n\n# Retrive all contacts whose name starts with 'John' and ends with 'Smith'\n>>> xero.contacts.filter(Name__startswith='John', Name__endswith='Smith')\n[{...contact info...}, {...contact info...}, {...contact info...}]\n\n# Retrive all contacts whose name contains 'mit'\n>>> xero.contacts.filter(Name__contains='mit')\n[{...contact info...}, {...contact info...}, {...contact info...}]\n\n# Create a new object\n>>> xero.contacts.put({...contact info...})\n\n# Create a new object\n>>> xero.contacts.put([{...contact info...}, {...contact info...}, {...contact info...}])\n\n# Save an update to an existing object\n>>> c = xero.contacts.get(u'b2b5333a-2546-4975-891f-d71a8a640d23')\n>>> c['Name'] = 'John Smith'\n>>> xero.contacts.save(c)\n\n# Save multiple objects\n>>> xero.contacts.save([c1, c2])\n```\n\nComplex filters can be constructed in the Django-way, for example retrieving invoices for a contact::\n\n```python\n>>> xero.invoices.filter(Contact_ContactID='83ad77d8-48a7-4f77-9146-e6933b7fb63b')\n```\n\nBe careful when dealing with large amounts of data, the Xero API will take an\nincreasingly long time to respond, or an error will be returned. If a query might\nreturn more than 100 results, you should make use of the ``page`` parameter::\n\n```python\n# Grab 100 invoices created after 01-01-2013\n>>> xero.invoices.filter(since=datetime(2013, 1, 1), page=1)\n```\n\nYou can also order the results to be returned::\n\n```python\n# Grab contacts ordered by EmailAddress\n>>> xero.contacts.filter(order='EmailAddress DESC')\n```\n\nFor invoices (and other objects that can be retrieved as PDFs), accessing the PDF is done\nvia setting the Accept header:\n\n```python\n# Fetch a PDF\ninvoice = xero.invoices.get('af722e93-b64f-482d-9955-1b027bfec896', \\\n headers={'Accept': 'application/pdf'})\n# Stream the PDF to the user (Django specific example)\nresponse = HttpResponse(invoice, content_type='application/pdf')\nresponse['Content-Disposition'] = 'attachment; filename=\"invoice.pdf\"'\nreturn response\n```\n\nDownload and uploading attachments is supported using the Xero GUID of the relevant object::\n\n```python\n# List attachments on a contact\n>>> xero.contacts.get_attachments(c['ContactID'])\n[{...attachment info...}, {...attachment info...}]\n\n# Attach a PDF to a contact\n>>> f = open('form.pdf', 'rb')\n>>> xero.contacts.put_attachment(c['ContactID'], 'form.pdf', f, 'application/pdf')\n>>> f.close()\n\n>>> xero.contacts.put_attachment_data(c['ContactID'], 'form.pdf', data, 'application/pdf')\n\n# Download an attachment\n>>> f = open('form.pdf', 'wb')\n>>> xero.contacts.get_attachment(c['ContactID'], 'form.pdf', f)\n>>> f.close()\n\n>>> data = xero.contacts.get_attachment_data(c['ContactID'], 'form.pdf')\n```\n\nThis same API pattern exists for the following API objects:\n\n* Accounts\n* Contacts\n* CreditNotes\n* Currencies\n* Invoices\n* Organisation\n* Payments\n* TaxRates\n* TrackingCategories\n* ManualJournals\n* BankTransactions\n* BankTransfers\n* ExpenseClaims\n* Receipts\n* Users\n\n## Contributing\n\nIf you're going to run the PyXero test suite, in addition to the dependencies\nfor PyXero, you need to add the following dependency to your environment:\n\n mock >= 1.0\n\nMock isn't included in the formal dependencies because they aren't required\nfor normal operation of PyXero. It's only required for testing purposes.\n\nOnce you've installed these dependencies, you can run the test suite by\nrunning the following from the root directory of the project:\n\n $ python setup.py test\n\nIf you find any problems with PyXero, you can log them on [Github Issues](https://github.com/freakboy3742/pyxero/issues).\nWhen reporting problems, it's extremely helpful if you can provide\nreproduction instructions -- the sequence of calls and/or test data that\ncan be used to reproduce the issue.\n\nNew features or bug fixes can be submitted via a pull request. If you want\nyour pull request to be merged quickly, make sure you either include\nregression test(s) for the behavior you are adding/fixing, or provide a\ngood explanation of why a regression test isn't possible.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/alexrybrown/pyxero", "keywords": null, "license": "New BSD", "maintainer": null, "maintainer_email": null, "name": "pyxero_ni_temp", "package_url": "https://pypi.org/project/pyxero_ni_temp/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/pyxero_ni_temp/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/alexrybrown/pyxero" }, "release_url": "https://pypi.org/project/pyxero_ni_temp/0.7.0-alpha2/", "requires_dist": null, "requires_python": null, "summary": "Python API for accessing the REST API of the Xero accounting tool.", "version": "0.7.0-alpha2" }, "last_serial": 1641799, "releases": { "0.7.0-alpha2": [ { "comment_text": "", "digests": { "md5": "c0beb2a2b6fddb14ccda9b4e0ad3ddb6", "sha256": "d251ddacc4244bbc51326694bd07d9d2df7eeae42cea779b0ea91fde1dc77c09" }, "downloads": -1, "filename": "pyxero_ni_temp-0.7.0-alpha2.tar.gz", "has_sig": false, "md5_digest": "c0beb2a2b6fddb14ccda9b4e0ad3ddb6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26653, "upload_time": "2015-06-25T16:13:18", "url": "https://files.pythonhosted.org/packages/0d/03/fd68382858bbb44dd55e67508ebd73a3d3c01c094b960358b5b2f7e0acf2/pyxero_ni_temp-0.7.0-alpha2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c0beb2a2b6fddb14ccda9b4e0ad3ddb6", "sha256": "d251ddacc4244bbc51326694bd07d9d2df7eeae42cea779b0ea91fde1dc77c09" }, "downloads": -1, "filename": "pyxero_ni_temp-0.7.0-alpha2.tar.gz", "has_sig": false, "md5_digest": "c0beb2a2b6fddb14ccda9b4e0ad3ddb6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26653, "upload_time": "2015-06-25T16:13:18", "url": "https://files.pythonhosted.org/packages/0d/03/fd68382858bbb44dd55e67508ebd73a3d3c01c094b960358b5b2f7e0acf2/pyxero_ni_temp-0.7.0-alpha2.tar.gz" } ] }