Kinto python client
###################
.. image:: https://github.com/Kinto/kinto-http.py/actions/workflows/test.yml/badge.svg
:target: https://github.com/Kinto/kinto-http.py/actions
.. image:: https://img.shields.io/pypi/v/kinto-http.svg
:target: https://pypi.python.org/pypi/kinto-http
*kinto-http* is the Python library to interact with a *Kinto* server.
There is also a similar `client in JavaScript <https://github.com/kinto/kinto-http.js>`_.
Installation
============
Use pip::
$ pip install kinto-http
Usage
=====
Here is an overview of what the API provides:
.. code-block:: python
import kinto_http
client = kinto_http.Client(server_url="http://localhost:8888/v1",
auth=('alexis', 'p4ssw0rd'))
records = client.get_records(bucket='default', collection='todos')
for i, record in enumerate(records):
record['title'] = 'Todo {}'.format(i)
client.update_record(data=record)
Instantiating a client
----------------------
The passed ``auth`` parameter is a `requests <http://docs.python-requests.org>`_
authentication policy.
By default, a simple tuple will become a ``Basic Auth`` authorization request header, that can authenticate users with `Kinto Accounts <https://kinto.readthedocs.io/en/stable/api/1.x/accounts.html>`_.
.. code-block:: python
import kinto_http
auth = ('alexis', 'p4ssw0rd')
client = kinto_http.Client(server_url='http://localhost:8888/v1',
auth=auth)
It is also possible to pass a ``bucket`` ID and/or ``collection`` ID to set them as default values for the parameters of the client operations.
.. code-block:: python
client = Client(bucket="payments", collection="receipts", auth=auth)
After creating a client, you can also replicate an existing one and overwrite
some key arguments.
.. code-block:: python
client2 = client.clone(collection="orders")
An asynchronous client is also available. It has all the same endpoints as the sync client except for the batch operations.
.. code-block:: python
from kinto_http import AsyncClient
auth = ('alexis', 'p4ssw0rd')
client = AsyncClient(server_url='http://localhost:8888/v1', auth=auth)
info = await client.server_info()
assert 'schema' in info['capabilities'], "Server doesn't support schema validation."
Dry Mode
--------
The ``dry_mode`` parameter can be set to simulate requests without actually sending them over the network.
When enabled, dry mode ensures that no external calls are made, making it useful for testing or debugging.
Instead of performing real HTTP operations, the client logs the requests with ``DEBUG`` level.
Using a Bearer access token to authenticate (OpenID)
----------------------------------------------------
.. code-block:: python
import kinto_http
client = kinto_http.Client(auth=kinto_http.BearerTokenAuth("XYPJTNsFKV2"))
The authorization header is prefixed with ``Bearer`` by default. If the ``header_type``
is `customized on the server <https://kinto.readthedocs.io/en/stable/configuration/settings.html#openid-connect>`_,
the client must specify the expected type: ``kinto_http.BearerTokenAuth("XYPJTNsFKV2", type="Bearer+OIDC")``
.. note::
Passing a string containing ``Bearer`` will be instantiate a ``kinto_http.BearerTokenAuth()`` object automatically.
In other words, ``kinto_http.Client(auth="Bearer+OIDC XYPJTNsFKV2")`` is equivalent to ``kinto_http.Client(auth=kinto_http.BearerTokenAuth("XYPJTNsFKV2", type="Bearer+OIDC"))``
Using the browser to authenticate via OAuth
-------------------------------------------
.. code-block:: python
import kinto_http
client = kinto_http.Client(server_url='http://localhost:8888/v1', auth=kinto_http.BrowserOAuth())
The client will open a browser page and will catch the Bearer token obtained after the OAuth dance.
Custom headers
--------------
Custom headers can be specified in the Client constructor, and will be sent in every request:
.. code-block:: python
import kinto_http
client = kinto_http.Client(server_url="http://server/v1", headers={
"Allow-Access": "CDN",
"User-Agent": "blocklist-updater"
})
Getting server information
--------------------------
You can use the ``server_info()`` method to fetch the server information:
.. code-block:: python
from kinto_http import Client
client = Client(server_url='http://localhost:8888/v1')
info = client.server_info()
assert 'schema' in info['capabilities'], "Server doesn't support schema validation."
Bucket operations
-----------------
* ``get_bucket(id=None, **kwargs)``: retrieve single bucket
* ``get_buckets(**kwargs)``: retrieve all readable buckets
* ``create_bucket(id=None, data=None, **kwargs)``: create a bucket
* ``update_bucket(id=None, data=None, **kwargs)``: create or replace an existing bucket
* ``patch_bucket(id=None, changes=None, **kwargs)``: modify some fields in an existing bucket
* ``delete_bucket(id=None, **kwargs)``: delete a bucket and everything under it
* ``delete_buckets(**kwargs)``: delete every writable buckets
Groups operations
-----------------
* ``get_group(id=None, bucket=None, **kwargs)``: retrieve single group
* ``get_groups(bucket=None, **kwargs)``: retrieve all readable groups
* ``create_group(id=None, data=None, bucket=None, **kwargs)``: create a group
* ``update_group(id=None, data=None, bucket=None, **kwargs)``: create or replace an existing group
* ``patch_group(id=None, changes=None, bucket=None, **kwargs)``: modify some fields in an existing group
* ``delete_group(id=None, bucket=None, **kwargs)``: delete a group and everything under it
* ``delete_groups(bucket=None, **kwargs)``: delete every writable groups
Collections
-----------
* ``get_collection(id=None, bucket=None, **kwargs)``: retrieve single collection
* ``get_collections(bucket=None, **kwargs)``: retrieve all readable collections
* ``create_collection(id=None, data=None, bucket=None, **kwargs)``: create a collection
* ``update_collection(id=None, data=None, bucket=None, **kwargs)``: create or replace an existing collection
* ``patch_collection(id=None, changes=None, bucket=None, **kwargs)``: modify some fields in an existing collection
* ``delete_collection(id=None, bucket=None, **kwargs)``: delete a collection and everything under it
* ``delete_collections(bucket=None, **kwargs)``: delete every writable collections
Records
-------
* ``get_record(id=None, bucket=None, collection=None, **kwargs)``: retrieve single record
* ``get_records(bucket=None, collection=None, **kwargs)``: retrieve all readable records
* ``get_paginated_records(bucket=None, collection=None, **kwargs)``: paginated list of records
* ``get_records_timestamp(bucket=None, collection=None, **kwargs)``: return the records timestamp of this collection
* ``create_record(id=None, data=None, bucket=None, collection=None, **kwargs)``: create a record
* ``update_record(id=None, data=None, bucket=None, collection=None, **kwargs)``: create or replace an existing record
* ``patch_record(id=None, changes=None, bucket=None, collection=None, **kwargs)``: modify some fields in an existing record
* ``delete_record(id=None, bucket=None, collection=None, **kwargs)``: delete a record and everything under it
* ``delete_records(bucket=None, collection=None, **kwargs)``: delete every writable records
Permissions
-----------
The objects permissions can be specified or modified by passing a ``permissions`` to ``create_*()``, ``patch_*()``, or ``update_*()`` methods:
.. code-block:: python
client.create_record(data={'foo': 'bar'},
permissions={'read': ['group:groupid']})
record = client.get_record('123', collection='todos', bucket='alexis')
record['permissions']['write'].append('leplatrem')
client.update_record(data=record)
In order to obtain a list of all the permissions, on every object, use the ``get_permissions()`` method:
.. code-block:: python
all_perms = client.get_permissions(exclude_resource_names=("record",))
has_collection_perms = any(
p for p in all_perms
if p["collection_id"] == "my-collection"
and "write" in p["permissions"]
)
Get or create
-------------
In some cases, you might want to create a bucket, collection, group or record only if
it doesn't exist already. To do so, you can pass the ``if_not_exists=True``
to the ``create_*()`` methods::
client.create_bucket(id='blog', if_not_exists=True)
client.create_collection(id='articles', bucket='blog', if_not_exists=True)
Delete if exists
----------------
In some cases, you might want to delete a bucket, collection, group or record only if
it exists already. To do so, you can pass the ``if_exists=True``
to the ``delete_*`` methods::
client.delete_bucket(id='bucket', if_exists=True)
Patch operations
----------------
The ``.patch_*()`` operations receive a ``changes`` parameter.
.. code-block:: python
from kinto_http.patch_type import BasicPatch, MergePatch, JSONPatch
client.patch_record(id='abc', changes=BasicPatch({'over': 'write'}))
client.patch_record(id='todo', changes=MergePatch({'assignee': 'bob'}))
client.patch_record(id='receipts', changes=JSONPatch([
{'op': 'add', 'path': '/data/members/0', 'value': 'ldap:user@corp.com'}
]))
Concurrency control
-------------------
The ``create_*()``, ``patch_*()``, and ``update_*()`` methods take a ``safe`` argument (default: ``True``).
If ``True``, the client will ensure that the object doesn't exist already for creations, or wasn't modified on the server side since we fetched it. The timestamp will be implicitly read from the ``last_modified`` field in the passed ``data`` object, or taken explicitly from the ``if_match`` parameter.
Batching operations
-------------------
Rather than issuing a request for each and every operation, it is possible to
batch several operations in one request (sync client only).
Using the ``batch()`` method as a Python context manager (``with``):
.. code-block:: python
with client.batch() as batch:
for idx in range(0, 100):
batch.update_record(data={'id': idx})
.. note::
Besides the ``results()`` method, a batch object shares all the same methods as
another client.
Reading data from batch operations is achieved by using the ``results()`` method
available after a batch context is closed.
.. code-block:: python
with client.batch() as batch:
batch.get_record('r1')
batch.get_record('r2')
batch.get_record('r3')
r1, r2, r3 = batch.results()
Errors
------
Failing operations will raise a ``KintoException``, which has ``request`` and ``response`` attributes.
.. code-block:: python
try:
client.create_group(id="friends")
except kinto_http.KintoException as e:
if e.response and e.response.status_code == 403:
print("Not allowed!")
Requests Timeout
----------------
A ``timeout`` value in seconds can be specified in the client constructor:
.. code-block:: python
client = KintoClient(server_url="...", timeout=5)
To distinguish the connect from the read timeout, use a tuple:
.. code-block:: python
client = KintoClient(server_url="...", timeout=(3.05, 27))
For an infinit timeout, use ``None``:
.. code-block:: python
client = KintoClient(server_url="...", timeout=None)
See the `timeout documentation <https://2.python-requests.org//en/master/user/advanced/#timeouts>`_ of the underlying ``requests`` library.
Retry on error
--------------
When the server is throttled (under heavy load or maintenance) it can
return error responses.
The client can hence retry to send the same request until it succeeds.
To enable this, specify the number of retries on the client:
.. code-block:: python
client = Client(server_url='http://localhost:8888/v1',
auth=credentials,
retry=10)
The Kinto protocol lets the server `define the duration in seconds between retries
<https://kinto.readthedocs.io/en/latest/api/1.x/backoff.html>`_.
It is possible (but not recommended) to force this value in the clients:
.. code-block:: python
client = Client(server_url='http://localhost:8888/v1',
auth=credentials,
retry=10,
retry_after=5)
Pagination
----------
When the server responses are paginated, the client will download every page and
merge them transparently.
The ``get_paginated_records()`` method returns a generator that will yield each page:
.. code-block:: python
for page in client.get_paginated_records():
records = page["data"]
It is possible to specify a limit for the number of items to be retrieved in one page:
.. code-block:: python
records = client.get_records(_limit=10)
In order to retrieve every available pages with a limited number of items in each
of them, you can specify the number of pages:
.. code-block:: python
records = client.get_records(_limit=10, pages=float('inf')) # Infinity
History
-------
If the built-in `history plugin <https://kinto.readthedocs.io/en/latest/api/1.x/history.html>`_ is enabled, it is possible to retrieve the history of changes:
.. code-block:: python
# Get the complete history of a bucket
changes = client.get_history(bucket='default')
# and optionally use filters
hist = client.get_history(bucket='default', _limit=2, _sort='-last_modified', _since='1533762576015')
hist = client.get_history(bucket='default', resource_name='collection')
The history of a bucket can also be purged with:
.. code-block:: python
client.purge_history(bucket='default')
Attachments
-----------
If the `kinto-attachment plugin <https://github.com/Kinto/kinto-attachment/>`_ is enabled, it is possible to fetch, add, or remove attachments on records:
.. code-block:: python
filepath = client.download_attachment(record_obj)
.. code-block:: python
client.add_attachment(id="record-id", filepath="/path/to/image.png")
Or remove them:
.. code-block:: python
client.remove_attachment(id="record-id")
Endpoint URLs
-------------
The ``get_endpoint()`` method returns an endpoint URL on the server:
.. code-block:: python
client = Client(server_url='http://localhost:8888/v1',
auth=('token', 'your-token'),
bucket="payments",
collection="receipts")
print(client.get_endpoint("record",
id="c6894b2c-1856-11e6-9415-3c970ede22b0"))
# '/buckets/payments/collections/receipts/records/c6894b2c-1856-11e6-9415-3c970ede22b0'
Handling datetime and date objects
----------------------------------
In addition to the data types supported by JSON, kinto-http.py also
supports native Python date and datetime objects.
In case a payload contain a date or a datetime object, kinto-http.py
will encode it as an ISO formatted string.
Please note that this transformation is only one-way. While reading a
record, if a string contains a ISO formated string, kinto-http.py will
not convert it to a native Python date or datetime object.
If you know that a field will be a datetime, you might consider
encoding it yourself to be more explicit about it being a string for
Kinto.
Command-line scripts
--------------------
In order to have common arguments and options for scripts, some utilities are provided
to ease configuration and initialization of client from command-line arguments.
.. code-block:: python
import argparse
import logging
from kinto_http import cli_utils
logger = logging.getLogger(__name__)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Download records")
cli_utils.set_parser_server_options(parser)
args = parser.parse_args()
cli_utils.setup_logger(logger, args)
logger.debug("Instantiate Kinto client.")
client = cli_utils.create_client_from_args(args)
logger.info("Fetch records.")
records = client.get_records()
logger.warn("{} records.".format(len(records)))
The script now accepts basic options:
::
$ python example.py --help
usage: example.py [-h] [-s SERVER] [-a AUTH] [-b BUCKET] [-c COLLECTION] [-v]
[-q] [-D]
Download records
optional arguments:
-h, --help show this help message and exit
-s SERVER, --server SERVER
The location of the remote server (with prefix)
-a AUTH, --auth AUTH BasicAuth credentials: `token:my-secret` or
Authorization header: `Bearer token`
-b BUCKET, --bucket BUCKET
Bucket name.
-c COLLECTION, --collection COLLECTION
Collection name.
--retry RETRY Number of retries when a request fails
--retry-after RETRY_AFTER
Delay in seconds between retries when requests fail
(default: provided by server)
-v, --verbose Show all messages.
-q, --quiet Show only critical errors.
-D, --debug Show all messages, including debug messages.
Development
===========
See `contributing docs <./.github/CONTRIBUTING.md>`_
Raw data
{
"_id": null,
"home_page": null,
"name": "kinto-http",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "web services",
"author": null,
"author_email": "Mozilla Services <developers@kinto-storage.org>",
"download_url": "https://files.pythonhosted.org/packages/a8/d4/a17e4ca9d369af652bb8ea65fcdd375b3ca1c501db6d9fd28f5ba5e24564/kinto_http-11.7.1.tar.gz",
"platform": null,
"description": "Kinto python client\n###################\n\n.. image:: https://github.com/Kinto/kinto-http.py/actions/workflows/test.yml/badge.svg\n :target: https://github.com/Kinto/kinto-http.py/actions\n\n.. image:: https://img.shields.io/pypi/v/kinto-http.svg\n :target: https://pypi.python.org/pypi/kinto-http\n\n*kinto-http* is the Python library to interact with a *Kinto* server.\n\nThere is also a similar `client in JavaScript <https://github.com/kinto/kinto-http.js>`_.\n\n\nInstallation\n============\n\nUse pip::\n\n $ pip install kinto-http\n\n\nUsage\n=====\n\nHere is an overview of what the API provides:\n\n.. code-block:: python\n\n import kinto_http\n\n client = kinto_http.Client(server_url=\"http://localhost:8888/v1\",\n auth=('alexis', 'p4ssw0rd'))\n\n records = client.get_records(bucket='default', collection='todos')\n for i, record in enumerate(records):\n record['title'] = 'Todo {}'.format(i)\n client.update_record(data=record)\n\n\nInstantiating a client\n----------------------\n\nThe passed ``auth`` parameter is a `requests <http://docs.python-requests.org>`_\nauthentication policy.\n\nBy default, a simple tuple will become a ``Basic Auth`` authorization request header, that can authenticate users with `Kinto Accounts <https://kinto.readthedocs.io/en/stable/api/1.x/accounts.html>`_.\n\n.. code-block:: python\n\n import kinto_http\n\n auth = ('alexis', 'p4ssw0rd')\n\n client = kinto_http.Client(server_url='http://localhost:8888/v1',\n auth=auth)\n\nIt is also possible to pass a ``bucket`` ID and/or ``collection`` ID to set them as default values for the parameters of the client operations.\n\n.. code-block:: python\n\n client = Client(bucket=\"payments\", collection=\"receipts\", auth=auth)\n\nAfter creating a client, you can also replicate an existing one and overwrite\nsome key arguments.\n\n.. code-block:: python\n\n client2 = client.clone(collection=\"orders\")\n\nAn asynchronous client is also available. It has all the same endpoints as the sync client except for the batch operations.\n\n.. code-block:: python\n\n from kinto_http import AsyncClient\n\n auth = ('alexis', 'p4ssw0rd')\n\n client = AsyncClient(server_url='http://localhost:8888/v1', auth=auth)\n info = await client.server_info()\n assert 'schema' in info['capabilities'], \"Server doesn't support schema validation.\"\n\n\nDry Mode\n--------\n\nThe ``dry_mode`` parameter can be set to simulate requests without actually sending them over the network.\nWhen enabled, dry mode ensures that no external calls are made, making it useful for testing or debugging.\nInstead of performing real HTTP operations, the client logs the requests with ``DEBUG`` level.\n\n\nUsing a Bearer access token to authenticate (OpenID)\n----------------------------------------------------\n\n.. code-block:: python\n\n import kinto_http\n\n client = kinto_http.Client(auth=kinto_http.BearerTokenAuth(\"XYPJTNsFKV2\"))\n\n\nThe authorization header is prefixed with ``Bearer`` by default. If the ``header_type``\nis `customized on the server <https://kinto.readthedocs.io/en/stable/configuration/settings.html#openid-connect>`_,\nthe client must specify the expected type: ``kinto_http.BearerTokenAuth(\"XYPJTNsFKV2\", type=\"Bearer+OIDC\")``\n\n.. note::\n\n Passing a string containing ``Bearer`` will be instantiate a ``kinto_http.BearerTokenAuth()`` object automatically.\n\n In other words, ``kinto_http.Client(auth=\"Bearer+OIDC XYPJTNsFKV2\")`` is equivalent to ``kinto_http.Client(auth=kinto_http.BearerTokenAuth(\"XYPJTNsFKV2\", type=\"Bearer+OIDC\"))``\n\nUsing the browser to authenticate via OAuth\n-------------------------------------------\n\n.. code-block:: python\n\n import kinto_http\n\n client = kinto_http.Client(server_url='http://localhost:8888/v1', auth=kinto_http.BrowserOAuth())\n\nThe client will open a browser page and will catch the Bearer token obtained after the OAuth dance.\n\n\nCustom headers\n--------------\n\nCustom headers can be specified in the Client constructor, and will be sent in every request:\n\n.. code-block:: python\n\n import kinto_http\n\n client = kinto_http.Client(server_url=\"http://server/v1\", headers={\n \"Allow-Access\": \"CDN\",\n \"User-Agent\": \"blocklist-updater\"\n })\n\n\nGetting server information\n--------------------------\n\nYou can use the ``server_info()`` method to fetch the server information:\n\n.. code-block:: python\n\n from kinto_http import Client\n\n client = Client(server_url='http://localhost:8888/v1')\n info = client.server_info()\n assert 'schema' in info['capabilities'], \"Server doesn't support schema validation.\"\n\n\nBucket operations\n-----------------\n\n* ``get_bucket(id=None, **kwargs)``: retrieve single bucket\n* ``get_buckets(**kwargs)``: retrieve all readable buckets\n* ``create_bucket(id=None, data=None, **kwargs)``: create a bucket\n* ``update_bucket(id=None, data=None, **kwargs)``: create or replace an existing bucket\n* ``patch_bucket(id=None, changes=None, **kwargs)``: modify some fields in an existing bucket\n* ``delete_bucket(id=None, **kwargs)``: delete a bucket and everything under it\n* ``delete_buckets(**kwargs)``: delete every writable buckets\n\n\nGroups operations\n-----------------\n\n* ``get_group(id=None, bucket=None, **kwargs)``: retrieve single group\n* ``get_groups(bucket=None, **kwargs)``: retrieve all readable groups\n* ``create_group(id=None, data=None, bucket=None, **kwargs)``: create a group\n* ``update_group(id=None, data=None, bucket=None, **kwargs)``: create or replace an existing group\n* ``patch_group(id=None, changes=None, bucket=None, **kwargs)``: modify some fields in an existing group\n* ``delete_group(id=None, bucket=None, **kwargs)``: delete a group and everything under it\n* ``delete_groups(bucket=None, **kwargs)``: delete every writable groups\n\n\nCollections\n-----------\n\n* ``get_collection(id=None, bucket=None, **kwargs)``: retrieve single collection\n* ``get_collections(bucket=None, **kwargs)``: retrieve all readable collections\n* ``create_collection(id=None, data=None, bucket=None, **kwargs)``: create a collection\n* ``update_collection(id=None, data=None, bucket=None, **kwargs)``: create or replace an existing collection\n* ``patch_collection(id=None, changes=None, bucket=None, **kwargs)``: modify some fields in an existing collection\n* ``delete_collection(id=None, bucket=None, **kwargs)``: delete a collection and everything under it\n* ``delete_collections(bucket=None, **kwargs)``: delete every writable collections\n\n\nRecords\n-------\n\n* ``get_record(id=None, bucket=None, collection=None, **kwargs)``: retrieve single record\n* ``get_records(bucket=None, collection=None, **kwargs)``: retrieve all readable records\n* ``get_paginated_records(bucket=None, collection=None, **kwargs)``: paginated list of records\n* ``get_records_timestamp(bucket=None, collection=None, **kwargs)``: return the records timestamp of this collection\n* ``create_record(id=None, data=None, bucket=None, collection=None, **kwargs)``: create a record\n* ``update_record(id=None, data=None, bucket=None, collection=None, **kwargs)``: create or replace an existing record\n* ``patch_record(id=None, changes=None, bucket=None, collection=None, **kwargs)``: modify some fields in an existing record\n* ``delete_record(id=None, bucket=None, collection=None, **kwargs)``: delete a record and everything under it\n* ``delete_records(bucket=None, collection=None, **kwargs)``: delete every writable records\n\n\nPermissions\n-----------\n\nThe objects permissions can be specified or modified by passing a ``permissions`` to ``create_*()``, ``patch_*()``, or ``update_*()`` methods:\n\n.. code-block:: python\n\n client.create_record(data={'foo': 'bar'},\n permissions={'read': ['group:groupid']})\n\n\n record = client.get_record('123', collection='todos', bucket='alexis')\n record['permissions']['write'].append('leplatrem')\n client.update_record(data=record)\n\n\nIn order to obtain a list of all the permissions, on every object, use the ``get_permissions()`` method:\n\n.. code-block:: python\n\n all_perms = client.get_permissions(exclude_resource_names=(\"record\",))\n\n has_collection_perms = any(\n p for p in all_perms\n if p[\"collection_id\"] == \"my-collection\"\n and \"write\" in p[\"permissions\"]\n )\n\n\nGet or create\n-------------\n\nIn some cases, you might want to create a bucket, collection, group or record only if\nit doesn't exist already. To do so, you can pass the ``if_not_exists=True``\nto the ``create_*()`` methods::\n\n client.create_bucket(id='blog', if_not_exists=True)\n client.create_collection(id='articles', bucket='blog', if_not_exists=True)\n\n\nDelete if exists\n----------------\n\nIn some cases, you might want to delete a bucket, collection, group or record only if\nit exists already. To do so, you can pass the ``if_exists=True``\nto the ``delete_*`` methods::\n\n client.delete_bucket(id='bucket', if_exists=True)\n\n\nPatch operations\n----------------\n\nThe ``.patch_*()`` operations receive a ``changes`` parameter.\n\n\n.. code-block:: python\n\n from kinto_http.patch_type import BasicPatch, MergePatch, JSONPatch\n\n\n client.patch_record(id='abc', changes=BasicPatch({'over': 'write'}))\n\n client.patch_record(id='todo', changes=MergePatch({'assignee': 'bob'}))\n\n client.patch_record(id='receipts', changes=JSONPatch([\n {'op': 'add', 'path': '/data/members/0', 'value': 'ldap:user@corp.com'}\n ]))\n\n\nConcurrency control\n-------------------\n\nThe ``create_*()``, ``patch_*()``, and ``update_*()`` methods take a ``safe`` argument (default: ``True``).\n\nIf ``True``, the client will ensure that the object doesn't exist already for creations, or wasn't modified on the server side since we fetched it. The timestamp will be implicitly read from the ``last_modified`` field in the passed ``data`` object, or taken explicitly from the ``if_match`` parameter.\n\n\nBatching operations\n-------------------\n\nRather than issuing a request for each and every operation, it is possible to\nbatch several operations in one request (sync client only).\n\nUsing the ``batch()`` method as a Python context manager (``with``):\n\n.. code-block:: python\n\n with client.batch() as batch:\n for idx in range(0, 100):\n batch.update_record(data={'id': idx})\n\n.. note::\n\n Besides the ``results()`` method, a batch object shares all the same methods as\n another client.\n\nReading data from batch operations is achieved by using the ``results()`` method\navailable after a batch context is closed.\n\n.. code-block:: python\n\n with client.batch() as batch:\n batch.get_record('r1')\n batch.get_record('r2')\n batch.get_record('r3')\n\n r1, r2, r3 = batch.results()\n\n\nErrors\n------\n\nFailing operations will raise a ``KintoException``, which has ``request`` and ``response`` attributes.\n\n.. code-block:: python\n\n try:\n client.create_group(id=\"friends\")\n except kinto_http.KintoException as e:\n if e.response and e.response.status_code == 403:\n print(\"Not allowed!\")\n\n\nRequests Timeout\n----------------\n\nA ``timeout`` value in seconds can be specified in the client constructor:\n\n.. code-block:: python\n\n client = KintoClient(server_url=\"...\", timeout=5)\n\nTo distinguish the connect from the read timeout, use a tuple:\n\n.. code-block:: python\n\n client = KintoClient(server_url=\"...\", timeout=(3.05, 27))\n\nFor an infinit timeout, use ``None``:\n\n.. code-block:: python\n\n client = KintoClient(server_url=\"...\", timeout=None)\n\nSee the `timeout documentation <https://2.python-requests.org//en/master/user/advanced/#timeouts>`_ of the underlying ``requests`` library.\n\n\nRetry on error\n--------------\n\nWhen the server is throttled (under heavy load or maintenance) it can\nreturn error responses.\n\nThe client can hence retry to send the same request until it succeeds.\nTo enable this, specify the number of retries on the client:\n\n.. code-block:: python\n\n client = Client(server_url='http://localhost:8888/v1',\n auth=credentials,\n retry=10)\n\nThe Kinto protocol lets the server `define the duration in seconds between retries\n<https://kinto.readthedocs.io/en/latest/api/1.x/backoff.html>`_.\nIt is possible (but not recommended) to force this value in the clients:\n\n.. code-block:: python\n\n client = Client(server_url='http://localhost:8888/v1',\n auth=credentials,\n retry=10,\n retry_after=5)\n\nPagination\n----------\n\nWhen the server responses are paginated, the client will download every page and\nmerge them transparently.\n\nThe ``get_paginated_records()`` method returns a generator that will yield each page:\n\n\n.. code-block:: python\n\n for page in client.get_paginated_records():\n records = page[\"data\"]\n\nIt is possible to specify a limit for the number of items to be retrieved in one page:\n\n.. code-block:: python\n\n records = client.get_records(_limit=10)\n\nIn order to retrieve every available pages with a limited number of items in each\nof them, you can specify the number of pages:\n\n.. code-block:: python\n\n records = client.get_records(_limit=10, pages=float('inf')) # Infinity\n\n\nHistory\n-------\n\nIf the built-in `history plugin <https://kinto.readthedocs.io/en/latest/api/1.x/history.html>`_ is enabled, it is possible to retrieve the history of changes:\n\n.. code-block:: python\n\n # Get the complete history of a bucket\n changes = client.get_history(bucket='default')\n\n # and optionally use filters\n hist = client.get_history(bucket='default', _limit=2, _sort='-last_modified', _since='1533762576015')\n hist = client.get_history(bucket='default', resource_name='collection')\n\n\nThe history of a bucket can also be purged with:\n\n.. code-block:: python\n\n client.purge_history(bucket='default')\n\n\nAttachments\n-----------\n\nIf the `kinto-attachment plugin <https://github.com/Kinto/kinto-attachment/>`_ is enabled, it is possible to fetch, add, or remove attachments on records:\n\n.. code-block:: python\n\n filepath = client.download_attachment(record_obj)\n\n.. code-block:: python\n\n client.add_attachment(id=\"record-id\", filepath=\"/path/to/image.png\")\n\nOr remove them:\n\n.. code-block:: python\n\n client.remove_attachment(id=\"record-id\")\n\n\nEndpoint URLs\n-------------\n\nThe ``get_endpoint()`` method returns an endpoint URL on the server:\n\n.. code-block:: python\n\n client = Client(server_url='http://localhost:8888/v1',\n auth=('token', 'your-token'),\n bucket=\"payments\",\n collection=\"receipts\")\n\n print(client.get_endpoint(\"record\",\n id=\"c6894b2c-1856-11e6-9415-3c970ede22b0\"))\n\n # '/buckets/payments/collections/receipts/records/c6894b2c-1856-11e6-9415-3c970ede22b0'\n\n\nHandling datetime and date objects\n----------------------------------\n\nIn addition to the data types supported by JSON, kinto-http.py also\nsupports native Python date and datetime objects.\n\nIn case a payload contain a date or a datetime object, kinto-http.py\nwill encode it as an ISO formatted string.\n\nPlease note that this transformation is only one-way. While reading a\nrecord, if a string contains a ISO formated string, kinto-http.py will\nnot convert it to a native Python date or datetime object.\n\nIf you know that a field will be a datetime, you might consider\nencoding it yourself to be more explicit about it being a string for\nKinto.\n\n\n\nCommand-line scripts\n--------------------\n\nIn order to have common arguments and options for scripts, some utilities are provided\nto ease configuration and initialization of client from command-line arguments.\n\n.. code-block:: python\n\n import argparse\n import logging\n\n from kinto_http import cli_utils\n\n logger = logging.getLogger(__name__)\n\n if __name__ == \"__main__\":\n parser = argparse.ArgumentParser(description=\"Download records\")\n cli_utils.set_parser_server_options(parser)\n\n args = parser.parse_args()\n\n cli_utils.setup_logger(logger, args)\n\n logger.debug(\"Instantiate Kinto client.\")\n client = cli_utils.create_client_from_args(args)\n\n logger.info(\"Fetch records.\")\n records = client.get_records()\n logger.warn(\"{} records.\".format(len(records)))\n\nThe script now accepts basic options:\n\n::\n\n $ python example.py --help\n\n usage: example.py [-h] [-s SERVER] [-a AUTH] [-b BUCKET] [-c COLLECTION] [-v]\n [-q] [-D]\n\n Download records\n\n optional arguments:\n -h, --help show this help message and exit\n -s SERVER, --server SERVER\n The location of the remote server (with prefix)\n -a AUTH, --auth AUTH BasicAuth credentials: `token:my-secret` or\n Authorization header: `Bearer token`\n -b BUCKET, --bucket BUCKET\n Bucket name.\n -c COLLECTION, --collection COLLECTION\n Collection name.\n --retry RETRY Number of retries when a request fails\n --retry-after RETRY_AFTER\n Delay in seconds between retries when requests fail\n (default: provided by server)\n -v, --verbose Show all messages.\n -q, --quiet Show only critical errors.\n -D, --debug Show all messages, including debug messages.\n\n\nDevelopment\n===========\n\nSee `contributing docs <./.github/CONTRIBUTING.md>`_\n",
"bugtrack_url": null,
"license": "Copyright 2012 - Mozilla Foundation Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ",
"summary": "Kinto client",
"version": "11.7.1",
"project_urls": {
"Repository": "https://github.com/Kinto/kinto-http.py"
},
"split_keywords": [
"web",
"services"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ce34c3900f640ac0e6e4e6c7598b69150314c6280fd1d0e3b877f6e803f29847",
"md5": "669bf6b65baab1c9c971bda0809a5f3b",
"sha256": "837ba12bea4eaafa8a4ce67730f8a40c9cf00c60f506ad42be03426c7236bc41"
},
"downloads": -1,
"filename": "kinto_http-11.7.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "669bf6b65baab1c9c971bda0809a5f3b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 26929,
"upload_time": "2024-12-11T16:26:03",
"upload_time_iso_8601": "2024-12-11T16:26:03.483436Z",
"url": "https://files.pythonhosted.org/packages/ce/34/c3900f640ac0e6e4e6c7598b69150314c6280fd1d0e3b877f6e803f29847/kinto_http-11.7.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a8d4a17e4ca9d369af652bb8ea65fcdd375b3ca1c501db6d9fd28f5ba5e24564",
"md5": "97f9e55b2b0e7ab1f1d721bd196e2bcd",
"sha256": "8e2cb010969c433bc65f7191e7b3314e214ecc5c035dd22d891d1cca27f821f0"
},
"downloads": -1,
"filename": "kinto_http-11.7.1.tar.gz",
"has_sig": false,
"md5_digest": "97f9e55b2b0e7ab1f1d721bd196e2bcd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 68376,
"upload_time": "2024-12-11T16:26:06",
"upload_time_iso_8601": "2024-12-11T16:26:06.218055Z",
"url": "https://files.pythonhosted.org/packages/a8/d4/a17e4ca9d369af652bb8ea65fcdd375b3ca1c501db6d9fd28f5ba5e24564/kinto_http-11.7.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-11 16:26:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Kinto",
"github_project": "kinto-http.py",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "kinto-http"
}