Package: influx-sansio
influx-sansio=============Python client for InfluxDB following the `SansIO`_ principle.InfluxDB is an open-source distributed time series database. Find moreabout InfluxDB at http://influxdata.com/Installation------------To install the latest release:.. code:: bash$ pip install influx-sansioThe library is still in beta, so you may also want to install the latest version fromthe development branch:.. code:: bash$ pip install git+https://github.com/miracle2k/influx-sansio@devDependencies~~~~~~~~~~~~The library supports Python 3.5+.There is one optional third-party library dependency:|pandas|_ for (optional) ``DataFrame`` reading/writing support.For the concrete IO implementations, there are aditional dependencies... |pandas| replace:: ``pandas``.. _pandas: https://github.com/pandas-dev/pandas.. _`SansIO`: https://sans-io.readthedocs.io/Usage-----The module has these parts:- Low-level utilities that implement generating and parsing the InfluxDBline protocol (for writing data), and some helpers for generating queries.This is Sans-IO, and you can use this to implement your own client.- An abstract base class that provides a easy to use `client` interface,which lets you do `client.query()` or `client.write()` calls.- Concrete implementations of this base class for various IO backends,currently the `asks` library which supports both `trio` and `curio`.Sans-IO (low-level utilities)~~~~~~~~~~~See the modules `influx_sansio.serialization` and `influx_sansio.http`.Client~~~~~~.. code:: pythonimport asyncioimport triofrom influx_sansio.asks import InfluxDBClientpoint = dict(time='2009-11-10T23:00:00Z',measurement='cpu_load_short',tags={'host': 'server01','region': 'us-west'},fields={'value': 0.64})client = InfluxDBClient(db='testdb')coros = [client.create_database(db='testdb'),client.write(point),client.query('SELECT value FROM cpu_load_short')]loop = asyncio.get_event_loop()results = loop.run_until_complete(asyncio.gather(*coros))for result in results:print(result)Writing data~~~~~~~~~~~~Input data can be:1. A string properly formatted in InfluxDB's line protocol2. A dictionary containing the following keys: ``measurement``, ``time``, ``tags``, ``fields``3. A Pandas ``DataFrame`` with a ``DatetimeIndex``4. An iterable of one of the aboveInput data in formats 2-4 are parsed into the `line protocol`_ before being written to InfluxDB.Beware that serialization is not highly optimized (cythonization PRs are welcome!) and may becomea bottleneck depending on your application.The ``write`` method returns ``True`` when successful and raises an``InfluxDBError`` otherwise... _`line protocol`: https://docs.influxdata.com/influxdb/latest/write_protocols/line_protocol_reference/Writing dictionary-like objects^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^We accept any dictionary-like object (mapping) as input.However, that dictionary must be properly formatted and contain thefollowing keys:1) **measurement**: Optional. Must be a string-like object. Ifomitted, must be specified when calling ``InfluxDBClient.write``by passing a ``measurement`` argument.2) **time**: Optional. The value can be ``datetime.datetime``,date-like string (e.g., ``2017-01-01``, ``2009-11-10T23:00:00Z``) oranything else that can be parsed by Pandas' |Timestamp|_ class initializer.3) **tags**: Optional. This must contain another mapping of fieldnames and values. Both tag keys and values should be strings.4) **fields**: Mandatory. This must contain another mapping of fieldnames and values. Field keys should be strings. Field values can be``float``, ``int``, ``str``, or ``bool`` or any equivalent type (e.g. Numpy types)... |Timestamp| replace:: ``Timestamp``.. _Timestamp: https://pandas.pydata.org/pandas-docs/stable/timeseries.htmlAny fields other then the above will be ignored when writing data toInfluxDB.A typical dictionary-like point would look something like the following:.. code:: python{'time': '2009-11-10T23:00:00Z','measurement': 'cpu_load_short','tags': {'host': 'server01', 'region': 'us-west'},'fields': {'value1': 0.64, 'value2': True, 'value3': 10}}Writing DataFrames^^^^^^^^^^^^^^^^^^We also accept Pandas dataframes as input. The only requirementsfor the dataframe is that the index **must** be of type``DatetimeIndex``. Also, any column whose ``dtype`` is ``object`` willbe converted to a string representation.A typical dataframe input should look something like the following:.. code:: textLUY       BEM       AJW tag2017-06-24 08:45:17.929097+00:00  2.545409  5.173134  5.532397   B2017-06-24 10:15:17.929097+00:00 -0.306673 -1.132941 -2.130625   E2017-06-24 11:45:17.929097+00:00  0.894738 -0.561979 -1.487940   B2017-06-24 13:15:17.929097+00:00 -1.799512 -1.722805 -2.308823   D2017-06-24 14:45:17.929097+00:00  0.390137 -0.016709 -0.667895   EThe measurement name must be specified with the ``measurement`` argumentwhen calling ``InfluxDBClient.write``. Additional tags can also bepassed using arbitrary keyword arguments.**Example:**.. code:: pythonclient = InfluxDBClient(db='testdb')client.write(df, measurement='prices', tag_columns=['tag'], asset_class='equities')In the example above, ``df`` is the dataframe we are trying to write toInfluxDB and ``measurement`` is the measurement we are writing to.``tag_columns`` is in an optional iterable telling which of thedataframe columns should be parsed as tag values. If ``tag_columns`` isnot explicitly passed, all columns in the dataframe will be treated asInfluxDB field values.Any other keyword arguments passed to ``InfluxDBClient.write`` aretreated as extra tags which will be attached to the data being writtento InfluxDB. Any string which is a valid `InfluxDB identifier`_ andvalid `Python identifier`_ can be used as an extra tag key (with theexception of they strings ``data``, ``measurement`` and ``tag_columns``).See ``InfluxDBClient.write`` docstring for details... _`InfluxDB identifier`: https://docs.influxdata.com/influxdb/latest/query_language/spec/#identifiers.. _`Python identifier`: https://docs.python.org/3/reference/lexical_analysis.html#identifiersQuerying data~~~~~~~~~~~~~Querying data is as simple as passing an InfluxDB query string to``InfluxDBClient.query``:.. code:: pythonclient.query('SELECT myfield FROM mymeasurement')The result (in ``blocking`` and ``async`` modes) is a dictionarycontaining the parsed JSON data returned by the InfluxDB `HTTP API`_:.. _`HTTP API`: https://docs.influxdata.com/influxdb/latest/guides/querying_data/#querying-data-using-the-http-api.. code:: python{'results': [{'series': [{'columns': ['time', 'Price', 'Volume'],'name': 'mymeasurement','values': [[1491963424224703000, 5783, 100],[1491963424375146000, 5783, 200],[1491963428374895000, 5783, 100],[1491963429645478000, 5783, 1100],[1491963429655289000, 5783, 100],[1491963437084443000, 5783, 100],[1491963442274656000, 5783, 900],[1491963442274657000, 5782, 5500],[1491963442274658000, 5781, 3200],[1491963442314710000, 5782, 100]]}],'statement_id': 0}]}Retrieving DataFrames^^^^^^^^^^^^^^^^^^^^^When the client is in ``dataframe`` mode, ``InfluxDBClient.query`` willreturn a Pandas ``DataFrame``:.. code:: textPrice  Volume2017-04-12 02:17:04.224703+00:00   5783     1002017-04-12 02:17:04.375146+00:00   5783     2002017-04-12 02:17:08.374895+00:00   5783     1002017-04-12 02:17:09.645478+00:00   5783    11002017-04-12 02:17:09.655289+00:00   5783     1002017-04-12 02:17:17.084443+00:00   5783     1002017-04-12 02:17:22.274656+00:00   5783     9002017-04-12 02:17:22.274657+00:00   5782    55002017-04-12 02:17:22.274658+00:00   5781    32002017-04-12 02:17:22.314710+00:00   5782     100Mode can be chosen not only during object instantiation but also bysimply |changing_mode|_... |changing_mode| replace:: changing the ``mode`` attribute.. _changing_mode: #switching-modesChunked responses^^^^^^^^^^^^^^^^^The library supports InfluxDB chunked queries. Passing ``chunked=True`` when calling``InfluxDBClient.query``, returns an AsyncGenerator object, which can asynchronouslyiterated. Using chunked requests allows response processing to be partially done beforethe full response is retrieved, reducing overall query time... code:: pythonchunks = await client.query("SELECT * FROM mymeasurement", chunked=True)async for chunk in chunks:# do somethingawait process_chunk(...)For Python 3.5, this relies on the async_generator (https://github.com/python-trio/async_generator)library.Iterating responses^^^^^^^^^^^^^^^^^^^``InfluxDBClient.query`` returns a parsed JSON response from InfluxDB. In order to easilyiterate over that JSON response point by point, we provide the ``iter_resp`` generator:.. code:: pythonfrom influx_sansio import iter_respr = client.query('SELECT * from h2o_quality LIMIT 10')for i in iter_resp(r):print(i).. code:: text[1439856000000000000, 41, 'coyote_creek', '1'][1439856000000000000, 99, 'santa_monica', '2'][1439856360000000000, 11, 'coyote_creek', '3'][1439856360000000000, 56, 'santa_monica', '2'][1439856720000000000, 65, 'santa_monica', '3']``iter_resp`` can also be used with chunked responses:.. code:: pythonchunks = await client.query('SELECT * from h2o_quality', chunked=True)async for chunk in chunks:for point in iter_resp(chunk):# do somethingBy default, ``iter_resp`` yields a plain list of values without doing any expensive parsing.However, in case a specific format is needed, an optional ``parser`` argument can be passed.``parser`` is a function that takes the raw value list for each data point and an additionalmetadata dictionary containing all or a subset of the following:``{'columns', 'name', 'tags', 'statement_id'}``... code:: pythonr = await client.query('SELECT * from h2o_quality LIMIT 5')for i in iter_resp(r, lambda x, meta: dict(zip(meta['columns'], x))):print(i).. code:: text{'time': 1439856000000000000, 'index': 41, 'location': 'coyote_creek', 'randtag': '1'}{'time': 1439856000000000000, 'index': 99, 'location': 'santa_monica', 'randtag': '2'}{'time': 1439856360000000000, 'index': 11, 'location': 'coyote_creek', 'randtag': '3'}{'time': 1439856360000000000, 'index': 56, 'location': 'santa_monica', 'randtag': '2'}{'time': 1439856720000000000, 'index': 65, 'location': 'santa_monica', 'randtag': '3'}Query patterns^^^^^^^^^^^^^^The library provides a wrapping mechanism around ``InfluxDBClient.query`` inorder to provide convenient access to commonly used query patterns.Query patterns are query strings containing optional named "replacement fields"surrounded by curly braces ``{}``, just as in |str_format|_.Replacement field values are defined by keyword arguments when calling the methodassociated with the query pattern. Differently from plain |str_format|, positionalarguments are also supported and can be mixed with keyword arguments.Built-in query patterns are defined on the class.Users can also dynamically define additional query patterns by usingthe |set_qp|_ helper function.User-defined query patterns have the disadvantage of not being shown forauto-completion in IDEs such as Pycharm.However, they do show up in dynamic environments such as Jupyter.If you have a query pattern that you think will used by many people and should be built-in,please submit a PR.Built-in query pattern examples:.. code:: pythonclient.create_database(db='foo')   # CREATE DATABASE {db}client.drop_measurement('bar')     # DROP MEASUREMENT {measurement}'client.show_users()                # SHOW USERS# Positional and keyword arguments can be mixedclient.show_tag_values_from('bar', key='spam')  # SHOW TAG VALUES FROM {measurement} WITH key = "{key}"Please refer to InfluxDB documentation_ for further query-related information... _documentation: https://docs.influxdata.com/influxdb/latest/query_language/.. |str_format| replace:: ``str_format()``.. _str_format: https://docs.python.org/3/library/string.html#formatstringsOther functionality~~~~~~~~~~~~~~~~~~~Authentication^^^^^^^^^^^^^^The library supports basic HTTP authenticatio. Simply pass ``username`` and ``password``when instantiating ``InfluxDBClient``:.. code:: pythonclient = InfluxDBClient(username='user', password='pass)Unix domain sockets^^^^^^^^^^^^^^^^^^^If your InfluxDB server uses UNIX domain sockets you can use ``unix_socket``when instantiating ``InfluxDBClient``:.. code:: pythonclient = InfluxDBClient(unix_socket='/path/to/socket')HTTPS/SSL^^^^^^^^^The library uses HTTP by default, but HTTPS can be used by passing ``ssl=True``when instantiating ``InfluxDBClient``:.. code:: pythonclient = InfluxDBClient(host='my.host.io', ssl=True)Database selection^^^^^^^^^^^^^^^^^^After the instantiation of the ``InfluxDBClient`` object, databasecan be switched by changing the ``db`` attribute:.. code:: pythonclient = InfluxDBClient(db='db1')client.db = 'db2'Beware that differently from some NoSQL databases (such as MongoDB),InfluxDB requires that a databases is explicitly created (by using the|CREATE_DATABASE|_ query) before doing any operations on it... |CREATE_DATABASE| replace:: ``CREATE DATABASE``.. _`CREATE_DATABASE`: https://docs.influxdata.com/influxdb/latest/query_language/database_management/#create-databaseImplementation--------------Since InfluxDB exposes all its functionality through an `HTTPAPI <https://docs.influxdata.com/influxdb/latest/tools/api/>`__,``InfluxDBClient`` tries to be nothing more than a thin and simplewrapper around that API.The InfluxDB HTTP API exposes exactly three endpoints/functions:``ping``, ``write`` and ``query``.``InfluxDBClient`` merely wraps these three functions and providessome parsing functionality for generating line protocol data (whenwriting) and parsing JSON responses (when querying).Additionally,`partials <https://en.wikipedia.org/wiki/Partial_application>`__ areused in order to provide convenient access to commonly used querypatterns. See the `Query patterns <#query-patterns>`__section for details.Credits-------Forked from `aioinflux <https://github.com/plugaai/aioinflux>`_.