modelstatus-client

Modelstatus REST API client


License
Other
Install
pip install modelstatus-client==2.0.0

Documentation

python-productstatus-client

Abstract

This is a Python module used to access a Productstatus REST API server.

The Productstatus code can be found on Github.

Setting up a development environment

mkvirtualenv python-productstatus-client
python setup.py develop

Building for pypi

python setup.py sdist bdist_wheel
twine upload dist/*

Examples of use

Load your virtualenv and run the example scripts in the examples/ directory.

Running unit tests

source deps/bin/activate
nosetests

Making requests

Import the module productstatus.api, and instantiate an Api object. You are now ready to use the Productstatus server.

import productstatus.api

# username and api key is only needed for write access
api = productstatus.api.Api('https://productstatus.fqdn', username='foo', api_key='bar')

REST API resource collections (e.g. /api/v1/product/) can be accessed as objects directly underneath the Api object. REST API resources (e.g. /api/v1/product/f314a536-bb96-4d2a-83cd-9764e2e3e16a/) can be accessed using indexing:

product = api.product['f314a536-bb96-4d2a-83cd-9764e2e3e16a']
print(product.name)  # 'AROME MetCoOp 2500m'

Foreign keys on resources are automatically resolved into objects:

print(product.institution.name)  # 'MET Norway'

You can run filtering queries to find the object you are looking for:

productinstances = api.productinstance.objects
productinstances.filter(product=product, reference_time=datetime.datetime(2015, 1, 1))
productinstances.order_by('-version')
productinstances.limit(2)
print(productinstances.count())  # 2
productinstance = productinstances[0]
print(productinstance.product.resource_uri == product.resource_uri)  # True

Creating new objects are done using the resource collection:

new_productinstance = api.productinstance.create()
new_productinstance.reference_time = datetime.datetime.now()
new_productinstance.product = product
new_productinstance.save()
print(new_productinstance.id)  # '4560279d-ef3e-49ae-bf2e-0dabac1b9e74'

You can also edit an existing object:

productinstance.reference_time += datetime.timedelta(seconds=1)
productinstance.save()

Lastly, you can access the schema to get an idea of how the data model looks like:

print(api.productinstance.schema)  # { 'huge': 'dictionary' }

Command-line utility

The Productstatus client ships with a handy "swiss army knife" that enables you to read and write remote objects from the command line.

Some examples of usage follow. Below, we create a new service backend object:

$ python productstatus/cli.py \
    --username X \
    --api_key Y \
    http://localhost:8000 \
    servicebackend create \
    --name /dev/null \
    --documentation_url 'https://example.com'
{
    "created": "2015-11-10T17:35:17+0000",
    "documentation_url": "https://example.com",
    "id": "013f06f9-8cf3-4123-94b1-4206b2807cbd",
    "modified": "2015-11-10T17:35:17+0000",
    "name": "/dev/null",
    "resource_uri": "/api/v1/servicebackend/013f06f9-8cf3-4123-94b1-4206b2807cbd/"
}

Searching by specific parameters. If you omit the parameters, all results will be returned.

$ python productstatus/cli.py http://localhost:8000 productinstance search --reference_time 2015-01-01T12:00:00Z --product 8efab026-434e-4baf-b8ed-d921a1b0b427
[
    {
        "created": "2015-11-10T17:27:13+0000",
        "id": "1ddb75c9-d5b4-49a8-9c27-79a47dd396b5",
        "product": "/api/v1/product/8efab026-434e-4baf-b8ed-d921a1b0b427/",
        "modified": "2015-11-10T17:27:13+0000",
        "reference_time": "2015-01-01T12:00:00+0000",
        "resource_uri": "/api/v1/productinstance/1ddb75c9-d5b4-49a8-9c27-79a47dd396b5/",
        "version": 1
    },
    {
        "created": "2015-11-10T17:27:20+0000",
        "id": "3789bc4b-eeb1-488b-96df-a1b2e680bf27",
        "product": "/api/v1/product/8efab026-434e-4baf-b8ed-d921a1b0b427/",
        "modified": "2015-11-10T17:27:20+0000",
        "reference_time": "2015-01-01T12:00:00+0000",
        "resource_uri": "/api/v1/productinstance/3789bc4b-eeb1-488b-96df-a1b2e680bf27/",
        "version": 2
    }
]

Requesting a specific resource item:

$ python productstatus/cli.py http://localhost:8000 product get 8efab026-434e-4baf-b8ed-d921a1b0b427
{
    "bounding_box": "0,0,0,0",
    "contact": "/api/v1/person/8e547c76-6639-450d-a077-5dbcabeb3581/",
    "created": "2015-11-05T11:32:59+0000",
    "grib_center": "ecmf",
    "grib_generating_process_id": "145",
    "grid_resolution": "4000.00000",
    "grid_resolution_unit": "m",
    "id": "8efab026-434e-4baf-b8ed-d921a1b0b427",
    "institution": "/api/v1/institution/a5eb5df1-704c-4450-a7a4-388f7e54c496/",
    "modified": "2015-11-10T11:37:58+0000",
    "name": "Nordic",
    "parent": null,
    "prognosis_length": 60,
    "projection": "/api/v1/projection/c2b3d081-bb4d-4dea-975b-0126bdab6691/",
    "resource_uri": "/api/v1/product/8efab026-434e-4baf-b8ed-d921a1b0b427/",
    "time_steps": 60,
    "wdb_data_provider": "nordic_roms"
}

Exit codes

See cli.py code for the mapping between exceptions and various exit codes.

Listening for Productstatus message queue events

The event listener is asynchronous, and will queue incoming messages until you fetch them with get_next_event().

See examples/events.py

import productstatus.api
import productstatus.exceptions

import json

api = productstatus.api.Api(
    'https://productstatus.met.no'
)

# You can easily set up an event listener using the API client. The default operation is to block
# until an event is received, or you can specify a timeout in the constructor.
event_listener = api.get_event_listener()

print('Listening for events...')
print()

# Loop through received events.
while True:
    try:
        event = event_listener.get_next_event()
    except productstatus.exceptions.EventTimeoutException:
        pass
    print(json.dumps(event, indent=4))
    print()

    if event.type == 'heartbeat':
        print('Received heartbeat with timestamp', event.message_timestamp)
    elif event.type == 'resource':
        print('Received resource of type', event.resource)
        if event.resource == 'datainstance':
            datainstance = api[event.uri]
            print('DataInstance URL:', datainstance.url)
            print('DataInstance product name:', datainstance.data.productinstance.product.name)
            print('DataInstance product slug:', datainstance.data.productinstance.product.slug)

    print()