Our API supports lots of common PythonAnywhere operations, like creating and managing consoles, scheduled and always-on tasks, and websites. We recently added support for reading/writing files; this blog post gives a brief overview of how you can use it to do that.
The first step when using the API is to get an API token – this is what you use to authenticate yourself with our servers when using it. To do that, log in to PythonAnywhere, and go to the “Account” page using the link at the top right. Click on the “API token” tab; if you don’t already have a token, it will look like this:
Click the “Create a new API token” button to get your token, and you’ll see this:
That string of letters and numbers (d870f0cac74964b27db563aeda9e418565a0d60d in the screenshot) is an API token, and anyone who has it can access your PythonAnywhere account and do stuff – so keep it secret. If someone does somehow get hold of it, you can revoke it on this page by clicking the red button – that stops it from working in the future, and creates a new one for you to use.
Now let’s use that token to access some files.
Preparing for using the API¶
On a machine with Python and requests installed, start a Python interpreter and run this:
from pprint import pprint
import requests
from urllib.parse import urljoin
api_token = "YOUR TOKEN HERE"
username = "YOUR USERNAME HERE"
pythonanywhere_host = "www.pythonanywhere.com"
api_base = "https://{pythonanywhere_host}/api/v0/user/{username}/".format(
pythonanywhere_host=pythonanywhere_host,
username=username,
)
…replacing "YOUR TOKEN HERE"
and "YOUR USERNAME HERE"
with the appropriate stuff. If you’re on our EU-based system, you should also replace www.pythonanywhere.com
with eu.pythonanywhere.com
.
If you’re using Python 2.7, the line
from urllib.parse import urljoin
should be
from urlparse import urljoin
Listing files¶
Now let’s make a request to see what files you have:
resp = requests.get(
urljoin(api_base, "files/path/home/{username}/".format(username=username)),
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
You should get a 200 status code:
>>> print(resp.status_code)
200
…and the JSON data in the response should be a reasonably-understandable description of the files and directories in your home directory – note the type
field that tells you what is what.
>>> pprint(resp.json())
{u'.bashrc': {u'type': u'file',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/.bashrc'},
u'.gitconfig': {u'type': u'file',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/.gitconfig'},
u'.local': {u'type': u'directory',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/.local'},
u'.profile': {u'type': u'file',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/.profile'},
u'.pythonstartup.py': {u'type': u'file',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/.pythonstartup.py'},
u'.vimrc': {u'type': u'file',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/.vimrc'},
u'README.txt': {u'type': u'file',
u'url': u'https://www.pythonanywhere.com/api/v0/user/yourusername/files/path/home/yourusername/README.txt'}}
So that shows how to get a directory listing.
Downloading a file¶
Let’s try downloading a file:
resp = requests.get(
urljoin(api_base, "files/path/home/{username}/README.txt".format(username=username)),
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
Again, the status code should be 200:
>>> print(resp.status_code)
200
…and the content of the response will be the contents of the file:
>>> print(resp.content)
# vim: set ft=rst:
See https://help.pythonanywhere.com/ (or click the "Help" link at the top
right) for help on how to use PythonAnywhere, including tips on copying and
pasting from consoles, and writing your own web applications.
Uploading a file¶
Let’s upload a file. We’ll put the text hello, world
into a file called foo.txt
in your home directory:
resp = requests.post(
urljoin(api_base, "files/path/home/{username}/foo.txt".format(username=username)),
files={"content": "hello world"},
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
This time, the status code should be 201 (which means “created”):
>>> print(resp.status_code)
201
Now you can go to the “Files” page on PythonAnywhere, and you’ll see the file; click on the filename to open an editor and see its contents:
The API will also show the new contents if you use it to get the file:
resp = requests.get(
urljoin(api_base, "files/path/home/{username}/foo.txt".format(username=username)),
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
You’ll get a 200 status code:
>>> print(resp.status_code)
200
And the expected content:
>>> print(resp.content)
hello world
Updating an existing file¶
You can update your file with new contents:
resp = requests.post(
urljoin(api_base, "files/path/home/{username}/foo.txt".format(username=username)),
files={"content": "some new contents"},
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
This time, the status code should be 200 (which means “successfully updated” in this context):
>>> print(resp.status_code)
200
…and if you refresh your editor window, you’ll see the updated contents.
Deleting a file¶
Finally we can delete the file:
resp = requests.delete(
urljoin(api_base, "files/path/home/{username}/foo.txt".format(username=username)),
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
And we get a “204” status code, meaning “successfully deleted”:
>>> print(resp.status_code)
204
Refresh the editor page again, and you’ll see a 404 not found error:
And if we try to download it using the API:
resp = requests.get(
urljoin(api_base, "files/path/home/{username}/foo.txt".format(username=username)),
headers={"Authorization": "Token {api_token}".format(api_token=api_token)}
)
We get the same status:
>>> print(resp.status_code)
404
Conclusion¶
That’s been a quick high-level overview of our new file API. Let us know what you think! And if you have any questions, just leave a comment below.