Introducing: A New Python Client for the MapRoulette API

MapRoulette is a powerful micro-tasking platform that provides professional and community mappers tools to improve the quality and coverage of OpenStreetMap. While most users are familiar with maproulette.org, the publicly available MapRoulette API enables users to build custom tools that utilize MapRoulette data.

The MapRoulette API documentation page.

Finding the right endpoint for your workflow can be challenging. The MapRoulette Java Client helps abstract some of the must-have Project, Challenge, and Task management functionality into a single Java library.
We wanted to provide a similar experience for the growing Python community. That’s where our latest Python Client steps into the spotlight. The Locana OSM team is excited to introduce the new MapRoulette Python Client!

We decided to build a Python Client with two goals in mind:

The new API Client is essentially a wrapper for the Requests library that supports several common use-cases. In just two months since our first release, we’ve managed to eliminate duplicate code while maintaining core functionality.

This article introduces some of the Python Client’s features. Let’s walk through some examples.

Creating a Configuration Object

The Configuration object controls how we connect to the MapRoulette server. You can pass a number of parameters including hostnameprotocolapi_key, and certs. A common parameter to set would be the api_key as many API calls require passing an API key in the request headers. While the default hostname is maproulette.org, this parameter is configurable because the MapRoulette application can be deployed in different locations. You can also control whether to use HTTPS or HTTP protocols. If the instance of MapRoulette you’re trying to connect to requires client-side certs, you can pass those when creating the Configuration object. In this example I’ll stick to the default hostname, but pass my custom API key (intentionally removed):

import maproulette
config = maproulette.Configuration(api_key='{YOUR_API_KEY}')

That’s it! Now you have a Configuration object that you can use to make API calls.

Creating API Objects

API objects are another fundamental part of the Python Client. At the time of writing, you have access to four objects containing different API calls: Project, Challenge, Task, and User. Each object requires a Configuration object as an argument. For example, if you want access to the Project methods, create a Project API object.

project_api = maproulette.Project(config)

By creating a Project API object, you can access all of the Project-related methods within the Python Client.

If you want access to the Challenge methods, create a Challenge object.

challenge_api = maproulette.Challenge(config)

Using Models

Models are a blueprint for constructing custom MapRoulette objects. As of Version 1.2.1, we support Models for Tasks, Challenges, Projects, and Priority rules. Use the ChallengeModel to add properties to a new Challenge. For example, you can create a ChallengeModel with one of the required properties — name.

challenge_model = maproulette.ChallengeModel(name='My Test Challenge')

And easily add more properties.

challenge_model.description = "A description of my new challenge"
challenge_model.instruction = "Do something"

Priority rules are commonly used properties for Challenges. These allow you to construct a set of Priority values for Tasks within a Challenge, indicating which Tasks are most important to resolve. A Challenge can have up to three rules— high, medium, and low — and each rule can be made up of several sub-rules joined by AND/OR logic. I find the PriorityRuleModel especially useful due to the layers of complexity involved in correctly formatting a Priority rule for the API. See the following example.

Goal: Create a PriorityRuleModel object with two sub-rules constituting a single high Priority rule for a Challenge.

rule_1 = maproulette.PriorityRule(
    priority_value='highway.footway',
    priority_type=maproulette.priority_rule.Types.STRING,
    priority_operator=maproulette.priority_rule.StringOperators.EQUAL
)
rule_2 = maproulette.PriorityRule(
    priority_value='highway.pedestrian',
    priority_type=maproulette.priority_rule.Types.STRING,
    priority_operator=maproulette.priority_rule.StringOperators.EQUAL
)
high_priority_rule = maproulette.PriorityRuleModel(
    condition=maproulette.priority_rule.Conditions.OR, 
    rules=[rule_1, rule_2]
).to_json()

The PriorityRuleModel creates the following JSON structure.

{
    "condition": "OR",
    "rules": [
        {
            "value": "highway.footway",
            "type": "string",
            "operator": "equal"
        },
        {
            "value": "highway.pedestrian",
            "type": "string",
            "operator": "equal"
        }
    ]
}

This example signifies the power of Models! The PriorityRuleModel ensures the proper format is created for the MapRoulette API. Now you can assign this PriorityRuleModel as the ChallengeModel’s high_priority_rule property.

challenge_model.high_priority_rule = high_priority_rule

For simplicity, you can use an Overpass query to define the Tasks within the Challenge. For example, this query selects two ways — one that should get assigned a high Priority value based on its highway tag and one that shouldn’t.

query = "way(id:612034979,91581586);\nout body geom qt;"
challenge_model.overpassQL = query

Now create your Challenge!

import json
print(json.dumps(api.create_challenge(challenge_data), indent=4, sort_keys=True))

The create_challenge method returns a JSON object of the newly created Challenge and its associated properties.

{
    "data": {
        "blurb": "",
        "checkinComment": "",
        "checkinSource": "",
        "cooperativeType": 0,
        "created": "2020-06-26T19:28:07.511Z",
        "customBasemap": "",
        "dataOriginDate": "2020-06-26T19:28:07.514Z",
        "defaultBasemap": -1,
        "defaultBasemapId": "",
        "defaultPriority": 0,
        "defaultZoom": 13,
        "deleted": false,
        "description": "A description of my new challenge",
        "difficulty": 2,
        "enabled": true,
        "exportableProperties": "",
        "featured": false,
        "highPriorityRule": {},
        "id": 13814,
        "infoLink": "",
        "instruction": "Do something",
        "lastTaskRefresh": "2020-06-26T19:28:07.514Z",
        "lowPriorityRule": {},
        "maxZoom": 19,
        "mediumPriorityRule": {
            "condition": "OR",
            "rules": [
                {
                    "operator": "equal",
                    "type": "string",
                    "value": "highway.footway"
                },
                {
                    "operator": "equal",
                    "type": "string",
                    "value": "highway.pedestrian"
                }
            ]
        },
        "minZoom": 1,
        "modified": "2020-06-26T19:28:07.518Z",
        "name": "My Test Challenge 1",
        "osmIdProperty": "",
        "overpassQL": "way(id:612034979,91581586);\nout body geom qt;",
        "owner": 1814383,
        "parent": 3006,
        "popularity": 1593199687,
        "remoteGeoJson": "",
        "requiresLocal": false,
        "status": 1,
        "statusMessage": "",
        "tags": [],
        "updateTasks": false,
        "virtualParents": []
    },
    "status": 201
}

Let’s open this test Challenge in MapRoulette! You’ll notice that there are two Tasks.

The Challenge’s overview page in MapRoulette.

 

As expected, one Task has a high Priority value, while the other has a medium value (the project’s default Priority).

Notice, each Task has a Priority value assigned.

 

Conclusion

These are just a few features in the MapRoulette Python Client that we’re excited to introduce, and hopefully, help users streamline their workflows. See something we should add? Submit an issue! Or better yet, contribute!

Remember MapRoulette is the game of chance where everyone is a winner. Users get happy by getting mappy!

Helpful links

· Github repo

· PyPI Package

· Documentation

· Examples

Share this post
Releated Posts

Become an insider

Sign up for quarterly insights on topics you care about, including GIS, geospatial, enterprise systems, open data and development, and more. We’ll share industry best practices, user stories, and relevant information you can use in your own work.