User Guide

Introduction

The Panoptes Client provides high level access to the HTTP API for common project management tasks. The client module provides a set of classes which act as an object-relational mapping (ORM) layer on top of the API, allowing you to perform tasks such as creating/uploading subjects, retiring subjects, and downloading data exports without having to concern yourself with the low level detail of how the API functions.

Most of the classes you’ll need can be imported directly from the panoptes_client package; see the module reference for a complete list.

Of special note is the Panoptes class which provides the Panoptes.connect() method. This method must be called to log into the API before you can perform any privileged, project owner-specific actions (though some things, such as listing public projects or available workflows, can be done anonymously, without logging in).

Most of the classes you’ll be using are subclasses of the abstract PanoptesObject class. Any references in this documentation to “Panoptes object classes” or “model classes” refer to these subclasses. You should familiarise yourself with the methods that Panoptes object classes all have, in particular PanoptesObject.save() and PanoptesObject.where().

Installation

Install latest stable release:

$ pip install panoptes-client

Or for development or testing, you can install the development version directly from GitHub:

$ pip install -U git+git://github.com/zooniverse/panoptes-python-client.git

Upgrade an existing installation:

$ pip install -U panoptes-client

Uploading non-image media types

If you wish to upload subjects with non-image media (e.g. audio or video), you will need to make sure you have the libmagic library installed. If you don’t already have libmagic, please see the dependency information for python-magic for more details.

Usage Examples

Tutorial: Creating a new project

Once you have the client installed, you can import the modules you need from the panoptes_client package. For this tutorial, we’re going to log into the Panoptes API, create a project, create a subject set, and finally create some subjects to go in the new set. Let’s start by importing all the classes we’ll need for that:

from panoptes_client import Panoptes, Project, SubjectSet, Subject

Now that we’ve imported all that, we can use the Panoptes.connect() method to log in:

Panoptes.connect(username='example', password='example')

Next we will create our new project. All we need to do is instantiate a new instance of Project, set some required attributes, and then save it, like so:

tutorial_project = Project()

tutorial_project.display_name = 'Tutorial Project'
tutorial_project.description = 'My first project created in Python'
tutorial_project.primary_language = 'en'
tutorial_project.private = True

tutorial_project.save()

Now if you log into the Zooniverse project builder you should see the new project listed there. Next we will create a subject set in the same way:

subject_set = SubjectSet()

subject_set.links.project = tutorial_project
subject_set.display_name = 'Tutorial subject set'

subject_set.save()

Here you’ll notice we set the subject_set.links.project attribute. links is a special attribute that handles connecting related Panoptes objects to each other. You can directly assign a Panoptes object instance, as above, or you can assign an object’s ID number if you have it. As well as assigning objects, you can use links to access related objects. Now that we’ve created our new subject set, we will also see a link to it on tutorial_project if we reload it:

tutorial_project.reload()
print(tutorial_project.links.subject_sets)

This would output something like this:

[<SubjectSet 1234>]

Showing a list of the linked subject sets (containing only our new set in this case). Here 1234 is the internal ID number of the subject set (also accessible as subject_set.id), so the exact result you get will be slightly different.

Now that we have a subject set, let’s create some subjects and add them to it. For this tutorial, we’ll assume you have a dict containing filenames and subject metadata. In reality you might load this from a CSV file, or query a database, or generate it in any number of different ways, but this would be outside the scope of this tutorial:

subject_metadata = {
    '/Users/me/file1.png': {
        'subject_reference': 1,
        'date': '2017-01-01',
    },
    '/Users/me/file2.png': {
        'subject_reference': 2,
        'date': '2017-01-02',
    },
    '/Users/me/file3.png': {
        'subject_reference': 3,
        'date': '2017-01-03',
    },
}

Now we create a Subject instance for each one:

new_subjects = []

for filename, metadata in subject_metadata.items():
    subject = Subject()

    subject.links.project = tutorial_project
    subject.add_location(filename)

    subject.metadata.update(metadata)

    subject.save()
    new_subjects.append(subject)

Saving the subject will create the subject in Panoptes and then upload the image file. The Subject.add_location() method prepares files to be uploaded. You can give it a string, as above, to point to a path on the local filesystem, or you can give it an open file object, or a dict for remote URLs. See the Subject.add_location() documentation for examples.

Note that by default the metadata attribute is an empty dict, so in this example we just call dict.update() to merge it with our existing metadata. You can also set individual keys as normal:

subject.metadata['my_metadata'] = 'abcd'

Or you can leave it empty if you don’t need to set anything.

All that’s left to do now is to link our new subjects to our new subject set. That can be done with the SubjectSet.add() method:

subject_set.add(new_subjects)

That takes the list of subjects and links them all in one go. This is the preferred way of doing it if you have several subjects to link (because it’s faster than making several separate calls), but you can also link subjects one at a time if you need to:

subject_set.add(subject1)
subject_set.add(subject2)

And that’s all there is to it! Your new subjects are now linked to the new subject set.

Other examples

Print all project titles:

for project in Project.where():
    print(project.title)

Find a project by slug and print all its workflow names:

project = Project.find(slug='zooniverse/example')
for workflow in project.links.workflows:
    print(workflow.display_name)

List the subjects in a subject_set:

subject_set = SubjectSet.find(1234)
for subject in subject_set.subjects:
    print(subject.id)

Add subject set to 1st workflow in project:

workflow = project.links.workflows[0]
workflow.add_subject_sets(subject_set)

Project owners with client credentials can update their users’ project settings (workflow_id only):

Panoptes.connect(client_id="example", client_secret="example")

user = User.find("1234")
project = Project.find("1234")
new_settings = {"workflow_id": "1234"}

ProjectPreferences.save_settings(
    project=project,
    user=user,
    settings=new_settings,
)

Alternatively, the project ID and user ID can be passed in directly if they are already known:

ProjectPreferences.save_settings(
    project=project_id,
    user=user_id,
    settings=new_settings,
)