/carto-python

CARTO Python client

Primary LanguagePythonBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

carto-python

Documentation Status

Python SDK for Carto's APIs:

carto-python is a full, backwards incompatible rewrite of the deprecated cartodb-python SDK. Since the initial rewrite, carto-python has been loaded with a lot of new features, not present in old cartodb-python.

Installation

You can install carto-python by cloning this repository or by using Pip:

pip install carto

If you want to use the development version, you can install directly from github:

pip install -e git+git://github.com/CartoDB/carto-python.git#egg=carto

If using, the development version, you might want to install Carto's dependencies as well:

pip install -r requirements.txt

Test Suite

Create a secret.py from secret.py.example, fill the variables, cd into the repo folder, create and enable virtualenv, install pytest and run tests:

cd carto-python
virtualenv env
source env/bin/activate
pip install -e .
pip install -r test_requirements.txt
pip install pytest
py.test tests

Authentication

Before making API calls, we need to define how those calls are going to be authenticated. Currently, we support two different authentication methods: unauthenticated and API key based. Therefore, we first need to create an authentication client that will be used when instantiating the Python classes that deal with API requests.

For unauthenticated requests, we need to create a NoAuthClient object:

from carto.auth import NoAuthClient

USERNAME="type here your username"
USR_BASE_URL = "https://{user}.carto.com/".format(user=USERNAME)
auth_client = NoAuthClient(base_url=USR_BASE_URL)

For API key authenticated requests, we need to create an APIKeyAuthClient instance:

from carto.auth import APIKeyAuthClient

USERNAME="type here your username"
USR_BASE_URL = "https://{user}.carto.com/".format(user=USERNAME)
auth_client = APIKeyAuthClient(api_key="myapikey", base_url=USR_BASE_URL)

API key is mandatory for all API requests except for sending SQL queries to public datasets.

The base_url parameter must include the user and or the organization

BASE_URL = "https://{organization}.carto.com/user/{user}/". \
    format(organization=ORGANIZATION,
           user=USERNAME)
USR_BASE_URL = "https://{user}.carto.com/".format(user=USERNAME)

Additionally, see test_auth.py for supported formats for the base_url parameter.

For a detailed description of the rest of parameters both constructors accept, please take a look at the documentation of the source code.

SQL API

Making requests to the SQL API is pretty straightforward:

from carto.sql import SQLClient

sql = SQLClient(auth_client)

try:
    data = sql.send('select * from mytable')
except CartoException as e:
    print("some error ocurred", e)

print data['rows']

Please refer to the source code documentation to find out about the rest of the parameters accepted by the constructor and the send method. In particular, the send method allows you to control the format of the results.

Batch SQL requests

For long lasting SQL queries you can use the batch SQL API.

from carto.sql import BatchSQLClient

LIST_OF_SQL_QUERIES = []

batchSQLClient = BatchSQLClient(auth_client)
createJob = batchSQLClient.create(LIST_OF_SQL_QUERIES)

print(createJob['job_id'])

The BatchSQLClient is asynchronous, but it offers methods to check the status of a job, update it or cancel it:

# check the status of a job after it has been created and you have the job_id
readJob = batchSQLClient.read(job_id)

# update the query of a batch job
updateJob = batchSQLClient.update(job_id, NEW_QUERY)

# cancel a job given its job_id
cancelJob = batchSQLClient.cancel(job_id)

COPY queries

COPY queries allow you to use the PostgreSQL COPY command for efficient streaming of data to and from CARTO.

Here is a basic example of its usage:

from carto.sql import SQLClient
from carto.sql import CopySQLClient

sql_client = SQLClient(auth_client)
copy_client = CopySQLClient(auth_client)

# Create a destination table for the copy with the right schema
sql_client.send("""
    CREATE TABLE IF NOT EXISTS copy_example (
      the_geom geometry(Geometry,4326),
      name text,
      age integer
    )
    """)
sql_client.send("SELECT CDB_CartodbfyTable(current_schema, 'copy_example')")

# COPY FROM a csv file in the filesytem
from_query = 'COPY copy_example (the_geom, name, age) FROM stdin WITH (FORMAT csv, HEADER true)'
result = copy_client.copyfrom_file_path(from_query, 'copy_from.csv')

# COPY TO a file in the filesystem
to_query = 'COPY copy_example TO stdout WITH (FORMAT csv, HEADER true)'
copy_client.copyto_file_path(to_query, 'export.csv')

Here's an equivalent, more pythonic example of the COPY FROM, using a file object:

with open('copy_from.csv', 'rb') as f:
    copy_client.copyfrom_file_object(from_query, f)

And here is a demonstration of how to generate and stream data directly (no need for a file at all):

def rows():
    # note the \n to delimit rows
    yield bytearray(u'the_geom,name,age\n', 'utf-8')
    for i in range(1,80):
        row = u'SRID=4326;POINT({lon} {lat}),{name},{age}\n'.format(
            lon = i,
            lat = i,
            name = 'fulano',
            age = 100 - i
        )
        yield bytearray(row, 'utf-8')
copy_client.copyfrom(from_query, rows())

For more examples on how to use the SQL API, please refer to the examples folder or the API docs.

Import API

You can import local or remote datasets into CARTO like this:

from carto.datasets import DatasetManager

# write here the path to a local file or remote URL
LOCAL_FILE_OR_URL = ""

dataset_manager = DatasetManager(auth_client)
dataset = dataset_manager.create(LOCAL_FILE_OR_URL)

The Import API is asynchronous, but the DatasetManager waits a maximum of 150 seconds for the dataset to be uploaded, so once it finishes the dataset has been created in CARTO.

Import a sync dataset

You can do it in the same way as a regular dataset, just include a sync_time parameter with a value >= 900 seconds

from carto.datasets import DatasetManager

# how often to sync the dataset (in seconds)
SYNC_TIME = 900
# write here the URL for the dataset to sync
URL_TO_DATASET = ""

dataset_manager = DatasetManager(auth_client)
dataset = dataset_manager.create(URL_TO_DATASET, SYNC_TIME)

Alternatively, if you need to do further work with the sync dataset, you can use the SyncTableJobManager

from carto.sync_tables import SyncTableJobManager
import time

# how often to sync the dataset (in seconds)
SYNC_TIME = 900
# write here the URL for the dataset to sync
URL_TO_DATASET = ""

syncTableManager = SyncTableJobManager(auth_client)
syncTable = syncTableManager.create(URL_TO_DATASET, SYNC_TIME)

# return the id of the sync
sync_id = syncTable.get_id()

while(syncTable.state != 'success'):
    time.sleep(5)
    syncTable.refresh()
    if (syncTable.state == 'failure'):
        print('The error code is: ' + str(syncTable.error_code))
        print('The error message is: ' + str(syncTable.error_message))
        break

# force sync
syncTable.refresh()
syncTable.force_sync()

Get a list of all the current import jobs

from carto.file_import import FileImportJobManager

file_import_manager = FileImportJobManager(auth_client)
file_imports = file_import_manager.all()

Get all the datasets

from carto.datasets import DatasetManager

dataset_manager = DatasetManager(auth_client)
datasets = dataset_manager.all()

Get a specific dataset

from carto.datasets import DatasetManager

# write here the ID of the dataset to retrieve
DATASET_ID = ""

dataset_manager = DatasetManager(auth_client)
dataset = dataset_manager.get(DATASET_ID)

Update the properties of a dataset (non-public API)

from carto.datasets import DatasetManager
from carto.permissions import PRIVATE, PUBLIC, LINK

# write here the ID of the dataset to retrieve
DATASET_ID = ""

dataset_manager = DatasetManager(auth_client)
dataset = dataset_manager.get(DATASET_ID)

# make the dataset PUBLIC
dataset.privacy = PUBLIC
dataset.save()

Delete a dataset

from carto.datasets import DatasetManager

# write here the ID of the dataset to retrieve
DATASET_ID = ""

dataset_manager = DatasetManager(auth_client)
dataset = dataset_manager.get(DATASET_ID)
dataset.delete()

Export a CARTO visualization (non-public API)

from carto.visualizations import VisualizationManager

# write here the name of the map to export
MAP_NAME = ""

visualization_manager = VisualizationManager(auth_client)
visualization = visualization_manager.get(MAP_NAME)

url = visualization.export()

# the URL points to a .carto file
print(url)

Please refer to the source code documentation and the examples folder to find out about the rest of the parameters accepted by constructors and methods.

Maps API

The Maps API allows to create and instantiate named and anonymous maps:

from carto.maps import NamedMapManager, NamedMap
import json

# write the path to a local file with a JSON named map template
JSON_TEMPLATE = ""

named_map_manager = NamedMapManager(auth_client)
named_map = NamedMap(named_map_manager.client)

with open(JSON_TEMPLATE) as named_map_json:
    template = json.load(named_map_json)

# Create named map
named = named_map_manager.create(template=template)
from carto.maps import AnonymousMap
import json

# write the path to a local file with a JSON named map template
JSON_TEMPLATE = ""

anonymous = AnonymousMap(auth_client)
with open(JSON_TEMPLATE) as anonymous_map_json:
    template = json.load(anonymous_map_json)

# Create anonymous map
anonymous.instantiate(template)

Instantiate a named map

from carto.maps import NamedMapManager, NamedMap
import json

# write the path to a local file with a JSON named map template
JSON_TEMPLATE = ""

# write here the ID of the named map
NAMED_MAP_ID = ""

# write here the token you set to the named map when created
NAMED_MAP_TOKEN = ""

named_map_manager = NamedMapManager(auth_client)
named_map = named_map_manager.get(NAMED_MAP_ID)

with open(JSON_TEMPLATE) as template_json:
    template = json.load(template_json)

named_map.instantiate(template, NAMED_MAP_TOKEN)

Work with named maps

from carto.maps import NamedMapManager, NamedMap

# write here the ID of the named map
NAMED_MAP_ID = ""

# get the named map created
named_map = named_map_manager.get(NAMED_MAP_ID)

# update named map
named_map.view = None
named_map.save()

# delete named map
named_map.delete()

# list all named maps
named_maps = named_map_manager.all()

For more examples on how to use the Maps API, please refer to the examples folder or the API docs.

API Documentation

API documentation is written with Sphinx. To build the API docs:

pip install sphinx
pip install sphinx_rtd_theme
cd doc
make html

Docs are generated inside the doc/build/hmtl folder. Please refer to them for a complete list of objects, functions and attributes of the carto-python API.

non-public APIs

Non-public APIs may change in the future and will thrown a warnings.warn message when used.

Please be aware if you plan to run them on a production environment.

Refer to the API docs for a list of non-public APIs

Examples

Inside the examples folder there are sample code snippets of the carto-python client.

To run examples, you should need to install additional dependencies:

pip install -r examples/requirements.txt

carto-python examples need to setup environment variables.

  • CARTO_ORG: The name of your organization
  • CARTO_API_URL: The base_url including your user and/or organization
  • CARTO_API_KEY: Your user API key

Please refer to the examples source code for additional info about parameters of each one