From 4c4c8f76776860fe9f264b999955ec32b47fad5d Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 03:10:50 +0900 Subject: [PATCH 01/20] Initial import --- .gitignore | 3 + .travis.yml | 10 ++ MANIFEST.in | 2 + influxdb/__init__.py | 7 ++ influxdb/client.py | 228 ++++++++++++++++++++++++++++++++++ requirements.txt | 1 + setup.py | 38 ++++++ test-requirements.txt | 2 + tests/__init__.py | 1 + tests/influxdb/__init__.py | 1 + tests/influxdb/client_test.py | 26 ++++ tox.ini | 14 +++ 12 files changed, 333 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 MANIFEST.in create mode 100644 influxdb/__init__.py create mode 100644 influxdb/client.py create mode 100644 requirements.txt create mode 100755 setup.py create mode 100644 test-requirements.txt create mode 100644 tests/__init__.py create mode 100644 tests/influxdb/__init__.py create mode 100644 tests/influxdb/client_test.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f5cb22f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.py.swp +.tox diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..a055493e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: python +python: + - "3.3" + - "3.2" + - "2.7" +install: + - "pip install -r requirements.txt --use-mirrors" + - "pip install -r test-requirements.txt --use-mirrors" + - "pip install --use-mirrors flake8 pep8-naming" +script: nosetests && flake8 influxdb diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..44ebdabd --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include requirements.txt +include test-requirements.txt diff --git a/influxdb/__init__.py b/influxdb/__init__.py new file mode 100644 index 00000000..40478066 --- /dev/null +++ b/influxdb/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from influxdb.client import InfluxDBClient + + +__all__ = ['InfluxDBClient'] + +__version__ = '0.1.0' diff --git a/influxdb/client.py b/influxdb/client.py new file mode 100644 index 00000000..686d4838 --- /dev/null +++ b/influxdb/client.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +""" +python client for influxdb +""" +import requests +import json + + +class InfluxDBClient(object): + """ + InfluxDB Client + """ + def __init__(self, host, port, username, password, database): + self._host = host + self._port = port + self._username = username + self._password = password + self._database = database + self._baseurl = "http://{0}:{1}".format(self._host, self._port) + + self._headers = json.dumps({ + 'Content-type': 'application/json', + 'Accept': 'text/plain'}) + + # Change member variables + + def switch_database(self, database): + """ + Change client database + + Parameters + ---------- + database : string + """ + self._database = database + + def switch_username(self, username, password): + """ + Change client username + + Parameters + ---------- + username : string + password : string + """ + self._username = username + self._password = password + + ### + # Administration & Security + + ### + # Creating and Dropping Databases + + def create_database(self, database): + """ + Create a database + + Parameters + ---------- + database: string + database name + """ + response = requests.post("{0}/db?u={1}&p={2}".format( + self._baseurl, + self._username, + self._password), + data=json.dumps({'name': database}), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def delete_database(self, database): + """ + Drop a database + + Parameters + ---------- + database: string + database name + """ + response = requests.delete("{0}/db/{1}?u={2}&p={3}".format( + self._baseurl, + database, + self._username, + self._password)) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + ### + # Security + + ### + # Limiting User Access + + def get_database_users(self): + """ + Get list of database users + """ + response = requests.get( + "{0}/db/{1}/users?u={2}&p={3}".format( + self._baseurl, + self._database, + self._username, + self._password)) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def add_database_user(self, new_username, new_password): + """ + Add database user + """ + response = requests.post( + "{0}/db/{1}/users?u={2}&p={3}".format( + self._baseurl, + self._database, + self._username, + self._password), + data=json.dumps({ + 'username': new_username, + 'password': new_password}), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def update_database_password(self, username, new_password): + """ + Update password + """ + response = requests.post( + "{0}/db/{1}/users/{2}?u={3}&p={4}".format( + self._baseurl, + self._database, + username, + self._username, + self._password), + data=json.dumps({ + 'password': new_password}), + headers=self._headers) + + if response.status_code == 200: + if username == self._username: + self._password = new_password + return True + else: + raise Exception(response.content) + + def delete_database_user(self, username): + """ + Delete database user + """ + response = requests.delete( + "{0}/db/{1}/users/{2}?u={3}&p={4}".format( + self._baseurl, + self._database, + username, + self._username, + self._password)) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + ### + # Writing Data + + def write_points(self, data): + """ + Write to multiple time series names + """ + response = requests.post( + "{0}/db/{1}/series?u={2}&p={3}".format( + self._baseurl, + self._database, + self._username, + self._password), + data=json.dumps(data), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def write_points_with_time_precision(self, data, time_precision='s'): + """ + Write to multiple time series names + """ + if time_precision not in ['s', 'm', 'u']: + raise Exception("Invalid time precision is given.") + + response = requests.post( + "{0}/db/{1}/series?u={2}&p={3}&time_precision={4}".format( + self._baseurl, + self._database, + self._username, + self._password, + time_precision), + data=json.dumps(data), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def delete_points(self, name, + regex=None, start_epoch=None, end_epoch=None): + pass + + ### + # Regularly Scheduled Deletes + + ### + # Querying Data diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..f2293605 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests diff --git a/setup.py b/setup.py new file mode 100755 index 00000000..8bff30ad --- /dev/null +++ b/setup.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +try: + import distribute_setup + distribute_setup.use_setuptools() +except: + pass + +try: + from setuptools import setup, find_packages +except ImportError: + from distutils.core import setup + +import os +import re + + +with open(os.path.join(os.path.dirname(__file__), + 'influxdb', '__init__.py')) as f: + version = re.search("__version__ = '([^']+)'", f.read()).group(1) + +with open('requirements.txt', 'r') as f: + requires = [x.strip() for x in f if x.strip()] + +with open('test-requirements.txt', 'r') as f: + test_requires = [x.strip() for x in f if x.strip()] + +setup( + name='influxdb', + version=version, + description="influxdb client", + packages=find_packages(exclude=['tests']), + test_suite='tests', + tests_require=test_requires, + install_requires=requires, + extras_require={'test': test_requires}, +) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..a6786964 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +nose +mock diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/tests/influxdb/__init__.py b/tests/influxdb/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/tests/influxdb/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py new file mode 100644 index 00000000..d61e6bce --- /dev/null +++ b/tests/influxdb/client_test.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +import requests +import nose.tools +from mock import patch + +from influxdb import InfluxDBClient + + +def _build_response_object(status_code=200, content=""): + resp = requests.Response() + resp.status_code = 200 + resp.content = content + return resp + + +class TestInfluxDBClient(object): + def test_switch_database(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'database') + cli.switch_database('another_database') + assert cli._database == 'another_database' + + def test_switch_username(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'database') + cli.switch_username('another_username', 'another_password') + assert cli._username == 'another_username' + assert cli._password == 'another_password' diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..f5128281 --- /dev/null +++ b/tox.ini @@ -0,0 +1,14 @@ +[tox] +envlist = py33, py27, flake8 + +[testenv] +commands = + pip install -r test-requirements.txt + nosetests + +[testenv:flake8] +deps = + flake8 + pep8-naming + +commands = flake8 influxdb From 58e749572b8e284dc382ad19ab7214a2e33f10cb Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 03:44:47 +0900 Subject: [PATCH 02/20] Update tests to check Exception --- test-requirements.txt | 1 + tests/influxdb/client_test.py | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/test-requirements.txt b/test-requirements.txt index a6786964..fac3bb36 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,3 @@ +requests nose mock diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index d61e6bce..c32bfebc 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- import requests -import nose.tools +from nose.tools import raises from mock import patch from influxdb import InfluxDBClient @@ -8,8 +8,8 @@ def _build_response_object(status_code=200, content=""): resp = requests.Response() - resp.status_code = 200 - resp.content = content + resp.status_code = status_code + resp._content = content return resp @@ -24,3 +24,31 @@ def test_switch_username(self): cli.switch_username('another_username', 'another_password') assert cli._username == 'another_username' assert cli._password == 'another_password' + + def test_create_database(self): + with patch.object(requests, 'post') as mocked_post: + mocked_post.return_value = _build_response_object() + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + assert cli.create_database('new_db') is True + + @raises(Exception) + def test_creata_database_fails(self): + with patch.object(requests, 'post') as mocked_post: + mocked_post.return_value = _build_response_object(status_code=401) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.create_database('new_db') + + def test_delete_database(self): + with patch.object(requests, 'delete') as mocked_post: + mocked_post.return_value = _build_response_object() + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + assert cli.delete_database('old_db') is True + + @raises(Exception) + def test_delete_database_fails(self): + with patch.object(requests, 'delete') as mocked_post: + mocked_post.return_value = _build_response_object(status_code=401) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.delete_database('old_db') + + From 97082cae60f878390b18a5f77bd7b84a4d1b27b2 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 03:56:01 +0900 Subject: [PATCH 03/20] Fix bug. No need to dump headers in python-requests --- influxdb/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index 686d4838..4cbefd2b 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -18,9 +18,9 @@ def __init__(self, host, port, username, password, database): self._database = database self._baseurl = "http://{0}:{1}".format(self._host, self._port) - self._headers = json.dumps({ + self._headers = { 'Content-type': 'application/json', - 'Accept': 'text/plain'}) + 'Accept': 'text/plain'} # Change member variables From 03d39ecb425bbaf26d860c86561776d8fcc89a5d Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 03:59:06 +0900 Subject: [PATCH 04/20] Fix bug. create_database returns 201. --- influxdb/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/influxdb/client.py b/influxdb/client.py index 4cbefd2b..5729580a 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -68,7 +68,7 @@ def create_database(self, database): data=json.dumps({'name': database}), headers=self._headers) - if response.status_code == 200: + if response.status_code == 201: return True else: raise Exception(response.content) From 7a2d440ce1d8a76527cc1d5838b7ec83103c128b Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 04:02:38 +0900 Subject: [PATCH 05/20] Fix bug. delete_database returns 201. --- influxdb/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/influxdb/client.py b/influxdb/client.py index 5729580a..9683117d 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -88,7 +88,7 @@ def delete_database(self, database): self._username, self._password)) - if response.status_code == 200: + if response.status_code == 201: return True else: raise Exception(response.content) From 4463d00058e957aafb3f097f77c0ff6b4e6e7031 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 04:06:42 +0900 Subject: [PATCH 06/20] Fix bug. delete_database returns 204 not 201 --- influxdb/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/influxdb/client.py b/influxdb/client.py index 9683117d..6e1ec264 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -88,7 +88,7 @@ def delete_database(self, database): self._username, self._password)) - if response.status_code == 201: + if response.status_code == 204: return True else: raise Exception(response.content) From 89039129f164b54170999c3b1d15ac39290da69e Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 04:21:44 +0900 Subject: [PATCH 07/20] Chanage return value of get_database_users --- influxdb/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/influxdb/client.py b/influxdb/client.py index 6e1ec264..62ce435d 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -111,7 +111,7 @@ def get_database_users(self): self._password)) if response.status_code == 200: - return True + return json.loads(response.content) else: raise Exception(response.content) From 580fc2e994603949cec19644af59310ab3ae149a Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 09:33:18 +0900 Subject: [PATCH 08/20] Udpate to handle administering requests --- influxdb/client.py | 290 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 244 insertions(+), 46 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index 62ce435d..79c300ba 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -46,11 +46,78 @@ def switch_username(self, username, password): self._username = username self._password = password - ### - # Administration & Security + # Writing Data + # + # Assuming you have a database named foo_production you can write data + # by doing a POST to /db/foo_production/series?u=some_user&p=some_password + # with a JSON body of points. + + def write_points(self, data): + """ + Write to multiple time series names + """ + response = requests.post( + "{0}/db/{1}/series?u={2}&p={3}".format( + self._baseurl, + self._database, + self._username, + self._password), + data=json.dumps(data), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def write_points_with_time_precision(self, data, time_precision='s'): + """ + Write to multiple time series names + """ + if time_precision not in ['s', 'm', 'u']: + raise Exception("Invalid time precision is given.") + + response = requests.post( + "{0}/db/{1}/series?u={2}&p={3}&time_precision={4}".format( + self._baseurl, + self._database, + self._username, + self._password, + time_precision), + data=json.dumps(data), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + # TODO: + # One Time Deletes + + def delete_points(self, name, + regex=None, start_epoch=None, end_epoch=None): + pass + + # TODO: + # Regularly Scheduled Deletes + # get list of deletes + # curl http://localhost:8086/db/site_dev/scheduled_deletes + # + # remove a regularly scheduled delete + # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id + + # TODO: + # Querying Data + # GET db/:name/series. It takes five parameters - ### # Creating and Dropping Databases + # + # ### create a database + # curl -X POST http://localhost:8086/db -d '{"name": "site_development"}' + # + # ### drop a database + # curl -X DELETE http://localhost:8086/db/site_development def create_database(self, database): """ @@ -93,20 +160,43 @@ def delete_database(self, database): else: raise Exception(response.content) - ### # Security + # get list of cluster admins + # curl http://localhost:8086/cluster_admins?u=root&p=root - ### - # Limiting User Access + # add cluster admin + # curl -X POST http://localhost:8086/cluster_admins?u=root&p=root \ + # -d '{"username": "paul", "password": "i write teh docz"}' - def get_database_users(self): + # update cluster admin password + # curl -X POST http://localhost:8086/cluster_admins/paul?u=root&p=root \ + # -d '{"password": "new pass"}' + + # delete cluster admin + # curl -X DELETE http://localhost:8086/cluster_admins/paul?u=root&p=root + + # Database admins, with a database name of site_dev + # get list of database admins + # curl http://localhost:8086/db/site_dev/admins?u=root&p=root + + # add database admin + # curl -X POST http://localhost:8086/db/site_dev/admins?u=root&p=root \ + # -d '{"username": "paul", "password": "i write teh docz"}' + + # update database admin password + # curl -X POST http://localhost:8086/db/site_dev/admins/paul?u=root&p=root \ + # -d '{"password": "new pass"}' + + # delete database admin + # curl -X DELETE http://localhost:8086/db/site_dev/admins/paul?u=root&p=root + + def get_list_cluster_admins(self, database): """ - Get list of database users + Get list of cluster admins """ response = requests.get( - "{0}/db/{1}/users?u={2}&p={3}".format( + "{0}/cluster_admins?u={1}&p={2}".format( self._baseurl, - self._database, self._username, self._password)) @@ -115,14 +205,13 @@ def get_database_users(self): else: raise Exception(response.content) - def add_database_user(self, new_username, new_password): + def add_cluster_admin(self, new_username, new_password): """ - Add database user + Add cluster admin """ response = requests.post( - "{0}/db/{1}/users?u={2}&p={3}".format( + "{0}/cluster_admins?u={1}&p={2}".format( self._baseurl, - self._database, self._username, self._password), data=json.dumps({ @@ -135,14 +224,13 @@ def add_database_user(self, new_username, new_password): else: raise Exception(response.content) - def update_database_password(self, username, new_password): + def update_cluster_admin_password(self, username, new_password): """ - Update password + Update cluster admin password """ response = requests.post( - "{0}/db/{1}/users/{2}?u={3}&p={4}".format( + "{0}/cluster_admins/{1}?u={2}&p={3}".format( self._baseurl, - self._database, username, self._username, self._password), @@ -151,43 +239,144 @@ def update_database_password(self, username, new_password): headers=self._headers) if response.status_code == 200: - if username == self._username: - self._password = new_password return True else: raise Exception(response.content) - def delete_database_user(self, username): + def delete_cluster_admin(self, username): """ - Delete database user + Delete cluster admin """ - response = requests.delete( - "{0}/db/{1}/users/{2}?u={3}&p={4}".format( + response = requests.delete("{0}/cluster_admin/{1}?u={2}&p={3}".format( + self._baseurl, + username, + self._username, + self._password)) + + if response.status_code == 204: + return True + else: + raise Exception(response.content) + + def get_list_database_admins(self): + """ + Get list of database admins + """ + response = requests.get( + "{0}/db/{1}/admins?u={2}&p={3}".format( self._baseurl, self._database, - username, self._username, self._password)) if response.status_code == 200: + return json.loads(response.content) + else: + raise Exception(response.content) + + def add_database_admin(self, new_username, new_password): + """ + Add cluster admin + """ + response = requests.post( + "{0}/db/{1}/admins?u={2}&p={3}".format( + self._baseurl, + self._database, + self._username, + self._password), + data=json.dumps({ + 'username': new_username, + 'password': new_password}), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def update_database_admin_password(self, username, new_password): + """ + Update database admin password + """ + response = requests.post( + "{0}/db/{1}/admins/{2}?u={3}&p={4}".format( + self._baseurl, + self._database, + username, + self._username, + self._password), + data=json.dumps({ + 'password': new_password}), + headers=self._headers) + + if response.status_code == 200: + return True + else: + raise Exception(response.content) + + def delete_database_admin(self, username): + """ + Delete database admin + """ + response = requests.delete("{0}/db/{1}/admins/{2}?u={3}&p={4}".format( + self._baseurl, + self._database, + username, + self._username, + self._password)) + + if response.status_code == 204: return True else: raise Exception(response.content) ### - # Writing Data + # Limiting User Access - def write_points(self, data): + # Database users + # get list of database users + # curl http://localhost:8086/db/site_dev/users?u=root&p=root + + # add database user + # curl -X POST http://localhost:8086/db/site_dev/users?u=root&p=root \ + # -d '{"username": "paul", "password": "i write teh docz"}' + + # update database user password + # curl -X POST http://localhost:8086/db/site_dev/users/paul?u=root&p=root \ + # -d '{"password": "new pass"}' + + # delete database user + # curl -X DELETE http://localhost:8086/db/site_dev/users/paul?u=root&p=root + + def get_database_users(self): """ - Write to multiple time series names + Get list of database users + """ + response = requests.get( + "{0}/db/{1}/users?u={2}&p={3}".format( + self._baseurl, + self._database, + self._username, + self._password)) + + if response.status_code == 200: + return json.loads(response.content) + else: + raise Exception(response.content) + + def add_database_user(self, new_username, new_password): + """ + Add database user """ response = requests.post( - "{0}/db/{1}/series?u={2}&p={3}".format( + "{0}/db/{1}/users?u={2}&p={3}".format( self._baseurl, self._database, self._username, self._password), - data=json.dumps(data), + data=json.dumps({ + 'username': new_username, + 'password': new_password}), headers=self._headers) if response.status_code == 200: @@ -195,34 +384,43 @@ def write_points(self, data): else: raise Exception(response.content) - def write_points_with_time_precision(self, data, time_precision='s'): + def update_database_password(self, username, new_password): """ - Write to multiple time series names + Update password """ - if time_precision not in ['s', 'm', 'u']: - raise Exception("Invalid time precision is given.") - response = requests.post( - "{0}/db/{1}/series?u={2}&p={3}&time_precision={4}".format( + "{0}/db/{1}/users/{2}?u={3}&p={4}".format( self._baseurl, self._database, + username, self._username, - self._password, - time_precision), - data=json.dumps(data), + self._password), + data=json.dumps({ + 'password': new_password}), headers=self._headers) if response.status_code == 200: + if username == self._username: + self._password = new_password return True else: raise Exception(response.content) - def delete_points(self, name, - regex=None, start_epoch=None, end_epoch=None): - pass + def delete_database_user(self, username): + """ + Delete database user + """ + response = requests.delete( + "{0}/db/{1}/users/{2}?u={3}&p={4}".format( + self._baseurl, + self._database, + username, + self._username, + self._password)) - ### - # Regularly Scheduled Deletes + if response.status_code == 200: + return True + else: + raise Exception(response.content) - ### - # Querying Data + # TODO: Change read/write permission From 0265440d8fc5584a4a9876bdfddf73680de74e83 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 09:54:36 +0900 Subject: [PATCH 09/20] Update testcases (use 201 or 204) --- influxdb/client.py | 42 +++++++++++++++++++---------------- tests/influxdb/client_test.py | 4 ++-- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index 79c300ba..41daaf49 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -68,7 +68,7 @@ def write_points(self, data): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def write_points_with_time_precision(self, data, time_precision='s'): """ @@ -90,7 +90,7 @@ def write_points_with_time_precision(self, data, time_precision='s'): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) # TODO: # One Time Deletes @@ -138,7 +138,7 @@ def create_database(self, database): if response.status_code == 201: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def delete_database(self, database): """ @@ -158,7 +158,7 @@ def delete_database(self, database): if response.status_code == 204: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) # Security # get list of cluster admins @@ -190,7 +190,7 @@ def delete_database(self, database): # delete database admin # curl -X DELETE http://localhost:8086/db/site_dev/admins/paul?u=root&p=root - def get_list_cluster_admins(self, database): + def get_list_cluster_admins(self): """ Get list of cluster admins """ @@ -203,7 +203,7 @@ def get_list_cluster_admins(self, database): if response.status_code == 200: return json.loads(response.content) else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def add_cluster_admin(self, new_username, new_password): """ @@ -222,7 +222,7 @@ def add_cluster_admin(self, new_username, new_password): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def update_cluster_admin_password(self, username, new_password): """ @@ -241,13 +241,13 @@ def update_cluster_admin_password(self, username, new_password): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def delete_cluster_admin(self, username): """ Delete cluster admin """ - response = requests.delete("{0}/cluster_admin/{1}?u={2}&p={3}".format( + response = requests.delete("{0}/cluster_admins/{1}?u={2}&p={3}".format( self._baseurl, username, self._username, @@ -256,8 +256,9 @@ def delete_cluster_admin(self, username): if response.status_code == 204: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) + # TODO: Not working def get_list_database_admins(self): """ Get list of database admins @@ -272,8 +273,9 @@ def get_list_database_admins(self): if response.status_code == 200: return json.loads(response.content) else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) + # TODO: Not working def add_database_admin(self, new_username, new_password): """ Add cluster admin @@ -292,8 +294,9 @@ def add_database_admin(self, new_username, new_password): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) + # TODO: Not working def update_database_admin_password(self, username, new_password): """ Update database admin password @@ -312,8 +315,9 @@ def update_database_admin_password(self, username, new_password): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) + # TODO: Not working def delete_database_admin(self, username): """ Delete database admin @@ -328,7 +332,7 @@ def delete_database_admin(self, username): if response.status_code == 204: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) ### # Limiting User Access @@ -362,7 +366,7 @@ def get_database_users(self): if response.status_code == 200: return json.loads(response.content) else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def add_database_user(self, new_username, new_password): """ @@ -382,9 +386,9 @@ def add_database_user(self, new_username, new_password): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) - def update_database_password(self, username, new_password): + def update_database_user_password(self, username, new_password): """ Update password """ @@ -404,7 +408,7 @@ def update_database_password(self, username, new_password): self._password = new_password return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) def delete_database_user(self, username): """ @@ -421,6 +425,6 @@ def delete_database_user(self, username): if response.status_code == 200: return True else: - raise Exception(response.content) + raise Exception("{0}: {1}".format(response.status_code, response.content)) # TODO: Change read/write permission diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index c32bfebc..250658ea 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -27,7 +27,7 @@ def test_switch_username(self): def test_create_database(self): with patch.object(requests, 'post') as mocked_post: - mocked_post.return_value = _build_response_object() + mocked_post.return_value = _build_response_object(status_code=201) cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') assert cli.create_database('new_db') is True @@ -40,7 +40,7 @@ def test_creata_database_fails(self): def test_delete_database(self): with patch.object(requests, 'delete') as mocked_post: - mocked_post.return_value = _build_response_object() + mocked_post.return_value = _build_response_object(status_code=204) cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') assert cli.delete_database('old_db') is True From c10a7a9bee71c825a4bd81781bb64461e8e34ae6 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 10:47:16 +0900 Subject: [PATCH 10/20] Declare methods (not implemented). --- influxdb/client.py | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index 41daaf49..60ca8fa4 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -92,24 +92,49 @@ def write_points_with_time_precision(self, data, time_precision='s'): else: raise Exception("{0}: {1}".format(response.status_code, response.content)) - # TODO: # One Time Deletes def delete_points(self, name, regex=None, start_epoch=None, end_epoch=None): - pass + """ + TODO: One Time Deletes + """ + raise NotImplemented() - # TODO: # Regularly Scheduled Deletes + + def create_scheduled_delete(self, json_body): + """ + TODO: Create scheduled delete + """ + raise NotImplemented() + # get list of deletes # curl http://localhost:8086/db/site_dev/scheduled_deletes # # remove a regularly scheduled delete # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id - # TODO: + def get_list_scheduled_delete(self): + """ + TODO: Get list of scheduled deletes + """ + raise NotImplemented() + + def remove_scheduled_delete(self, delete_id): + """ + TODO: Remove scheduled delete + """ + raise NotImplemented() + # Querying Data + # # GET db/:name/series. It takes five parameters + def query(self, query, time_precision, chunked=False): + """ + TODO: Quering data + """ + raise NotImplemented() # Creating and Dropping Databases # @@ -427,4 +452,10 @@ def delete_database_user(self, username): else: raise Exception("{0}: {1}".format(response.status_code, response.content)) - # TODO: Change read/write permission + # update the user by POSTing to db/site_dev/users/paul + + def update_permission(self, json_body): + """ + TODO: Update read/write permission + """ + raise NotImplemented() From 46818fb8e954127c37e9626fb8f756f19ee2c175 Mon Sep 17 00:00:00 2001 From: smly Date: Thu, 7 Nov 2013 11:53:12 +0900 Subject: [PATCH 11/20] Implement query method --- .gitignore | 1 + .travis.yml | 3 +-- README.md | 15 ++++++++++++ influxdb/client.py | 43 ++++++++++++++++++++++++++++------- tests/influxdb/client_test.py | 8 +++---- tox.ini | 2 +- 6 files changed, 57 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index f5cb22f3..a90b1009 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +influxdb.egg-info/ *.pyc *.py.swp .tox diff --git a/.travis.yml b/.travis.yml index a055493e..bb686f7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,4 @@ python: install: - "pip install -r requirements.txt --use-mirrors" - "pip install -r test-requirements.txt --use-mirrors" - - "pip install --use-mirrors flake8 pep8-naming" -script: nosetests && flake8 influxdb +script: nosetests diff --git a/README.md b/README.md index 9976fe41..feeff885 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,18 @@ influxdb-python =============== Python client for InfluxDB + +For developers +-------------- + +To test influxdb-python with multiple version of Python, you can use tox: + +```` +$ tox +```` + +If you don't have all Python version listed in tox.ini, then + +```` +$ tox -e py27 +```` diff --git a/influxdb/client.py b/influxdb/client.py index 60ca8fa4..15c5dce6 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -4,6 +4,7 @@ """ import requests import json +import urllib class InfluxDBClient(object): @@ -24,7 +25,7 @@ def __init__(self, host, port, username, password, database): # Change member variables - def switch_database(self, database): + def switch_db(self, database): """ Change client database @@ -34,7 +35,7 @@ def switch_database(self, database): """ self._database = database - def switch_username(self, username, password): + def switch_user(self, username, password): """ Change client username @@ -75,10 +76,11 @@ def write_points_with_time_precision(self, data, time_precision='s'): Write to multiple time series names """ if time_precision not in ['s', 'm', 'u']: - raise Exception("Invalid time precision is given.") + raise Exception("Invalid time precision is given. (use 's','m' or 'u')") - response = requests.post( - "{0}/db/{1}/series?u={2}&p={3}&time_precision={4}".format( + url_format = "{0}/db/{1}/series?u={2}&p={3}&time_precision={4}" + + response = requests.post(url_format.format( self._baseurl, self._database, self._username, @@ -130,11 +132,36 @@ def remove_scheduled_delete(self, delete_id): # Querying Data # # GET db/:name/series. It takes five parameters - def query(self, query, time_precision, chunked=False): + def query(self, query, time_precision='s', chunked=False): """ - TODO: Quering data + Quering data """ - raise NotImplemented() + if time_precision not in ['s', 'm', 'u']: + raise Exception("Invalid time precision is given. (use 's','m' or 'u')") + + if chunked is True: + chunked_param = 'true' + else: + chunked_param = 'false' + + encoded_query = urllib.urlencode(query) + + url_format = "{0}/db/{1}/series?q={2}&u={3}&p={4}" + url_format += "&time_precision={5}&chunked={6}" + + response = requests.get(url_format.format( + self._baseurl, + self._database, + encoded_query, + self._username, + self._password, + time_precision, + chunked_param)) + + if response.status_code == 200: + return response.content + else: + raise Exception("{0}: {1}".format(response.status_code, response.content)) # Creating and Dropping Databases # diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 250658ea..63ad28c6 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -14,14 +14,14 @@ def _build_response_object(status_code=200, content=""): class TestInfluxDBClient(object): - def test_switch_database(self): + def test_switch_db(self): cli = InfluxDBClient('host', 8086, 'username', 'password', 'database') - cli.switch_database('another_database') + cli.switch_db('another_database') assert cli._database == 'another_database' - def test_switch_username(self): + def test_switch_user(self): cli = InfluxDBClient('host', 8086, 'username', 'password', 'database') - cli.switch_username('another_username', 'another_password') + cli.switch_user('another_username', 'another_password') assert cli._username == 'another_username' assert cli._password == 'another_password' diff --git a/tox.ini b/tox.ini index f5128281..237ffa90 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py33, py27, flake8 +envlist = py32, py27, flake8 [testenv] commands = From 494e654903c09c2916ea62622631796a426bf9c7 Mon Sep 17 00:00:00 2001 From: smly Date: Thu, 7 Nov 2013 13:49:10 +0900 Subject: [PATCH 12/20] Fix bug in query parameter --- influxdb/client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index 15c5dce6..5a020682 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -144,9 +144,10 @@ def query(self, query, time_precision='s', chunked=False): else: chunked_param = 'false' - encoded_query = urllib.urlencode(query) + encoded_query = urllib.urlencode({ + 'q': query}) - url_format = "{0}/db/{1}/series?q={2}&u={3}&p={4}" + url_format = "{0}/db/{1}/series?{2}&u={3}&p={4}" url_format += "&time_precision={5}&chunked={6}" response = requests.get(url_format.format( From 8afb8e2a474b3cfb4d4f3e9a1defcaab6e37d986 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 22:35:35 +0900 Subject: [PATCH 13/20] Fix indent. Impl delete method --- influxdb/client.py | 57 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index 5a020682..fd6ca45d 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -69,39 +69,61 @@ def write_points(self, data): if response.status_code == 200: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def write_points_with_time_precision(self, data, time_precision='s'): """ Write to multiple time series names """ if time_precision not in ['s', 'm', 'u']: - raise Exception("Invalid time precision is given. (use 's','m' or 'u')") + raise Exception( + "Invalid time precision is given. (use 's','m' or 'u')") url_format = "{0}/db/{1}/series?u={2}&p={3}&time_precision={4}" response = requests.post(url_format.format( - self._baseurl, - self._database, - self._username, - self._password, - time_precision), + self._baseurl, + self._database, + self._username, + self._password, + time_precision), data=json.dumps(data), headers=self._headers) if response.status_code == 200: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) # One Time Deletes def delete_points(self, name, regex=None, start_epoch=None, end_epoch=None): """ - TODO: One Time Deletes + Delete a range of data """ - raise NotImplemented() + url_format = "{0}/db/{1}/series?u={2}&p={3}" + url_format += "&name={4}" + if regex is not None: + url_format += "®ex=" + regex + if start_epoch is not None: + url_format += "&start=" + start_epoch + if end_epoch is not None: + url_format += "&end=" + end_epoch + + response = requests.delete(url_format.format( + self._baseurl, + self._database, + self._username, + self._password, + name)) + if response.status_code == 200: + return True + else: + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) # Regularly Scheduled Deletes @@ -137,7 +159,8 @@ def query(self, query, time_precision='s', chunked=False): Quering data """ if time_precision not in ['s', 'm', 'u']: - raise Exception("Invalid time precision is given. (use 's','m' or 'u')") + raise Exception( + "Invalid time precision is given. (use 's','m' or 'u')") if chunked is True: chunked_param = 'true' @@ -162,7 +185,8 @@ def query(self, query, time_precision='s', chunked=False): if response.status_code == 200: return response.content else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) # Creating and Dropping Databases # @@ -211,7 +235,8 @@ def delete_database(self, database): if response.status_code == 204: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) # Security # get list of cluster admins @@ -256,7 +281,8 @@ def get_list_cluster_admins(self): if response.status_code == 200: return json.loads(response.content) else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def add_cluster_admin(self, new_username, new_password): """ @@ -275,7 +301,8 @@ def add_cluster_admin(self, new_username, new_password): if response.status_code == 200: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def update_cluster_admin_password(self, username, new_password): """ From e6c454c03f6cc143e394d5e8fd594a23a3fea082 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 23:29:14 +0900 Subject: [PATCH 14/20] Scheduled deletions are not implemented. Comment out them --- influxdb/client.py | 277 +++++++++++++++++++++++++-------------------- 1 file changed, 155 insertions(+), 122 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index fd6ca45d..aff3ea48 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -97,59 +97,42 @@ def write_points_with_time_precision(self, data, time_precision='s'): raise Exception( "{0}: {1}".format(response.status_code, response.content)) - # One Time Deletes - - def delete_points(self, name, - regex=None, start_epoch=None, end_epoch=None): - """ - Delete a range of data - """ - url_format = "{0}/db/{1}/series?u={2}&p={3}" - url_format += "&name={4}" - if regex is not None: - url_format += "®ex=" + regex - if start_epoch is not None: - url_format += "&start=" + start_epoch - if end_epoch is not None: - url_format += "&end=" + end_epoch - - response = requests.delete(url_format.format( - self._baseurl, - self._database, - self._username, - self._password, - name)) - if response.status_code == 200: - return True - else: - raise Exception( - "{0}: {1}".format(response.status_code, response.content)) - - # Regularly Scheduled Deletes - - def create_scheduled_delete(self, json_body): - """ - TODO: Create scheduled delete - """ - raise NotImplemented() - - # get list of deletes - # curl http://localhost:8086/db/site_dev/scheduled_deletes - # - # remove a regularly scheduled delete - # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id - - def get_list_scheduled_delete(self): - """ - TODO: Get list of scheduled deletes - """ - raise NotImplemented() - - def remove_scheduled_delete(self, delete_id): - """ - TODO: Remove scheduled delete - """ - raise NotImplemented() +# # One Time Deletes +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) +# def delete_points(self, name, +# regex=None, start_epoch=None, end_epoch=None): +# """ +# TODO: Delete a range of data +# """ +# raise NotImplemented() +# +# # Regularly Scheduled Deletes +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) +# def create_scheduled_delete(self, json_body): +# """ +# TODO: Create scheduled delete +# """ +# raise NotImplemented() +# +# # get list of deletes +# # curl http://localhost:8086/db/site_dev/scheduled_deletes +# # +# # remove a regularly scheduled delete +# # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id +# +# def get_list_scheduled_delete(self): +# """ +# TODO: Get list of scheduled deletes +# """ +# raise NotImplemented() +# +# def remove_scheduled_delete(self, delete_id): +# """ +# TODO: Remove scheduled delete +# """ +# raise NotImplemented() # Querying Data # @@ -215,7 +198,8 @@ def create_database(self, database): if response.status_code == 201: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def delete_database(self, database): """ @@ -321,7 +305,8 @@ def update_cluster_admin_password(self, username, new_password): if response.status_code == 200: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def delete_cluster_admin(self, username): """ @@ -336,83 +321,127 @@ def delete_cluster_admin(self, username): if response.status_code == 204: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) - - # TODO: Not working - def get_list_database_admins(self): - """ - Get list of database admins - """ - response = requests.get( - "{0}/db/{1}/admins?u={2}&p={3}".format( - self._baseurl, - self._database, - self._username, - self._password)) - - if response.status_code == 200: - return json.loads(response.content) - else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) - # TODO: Not working - def add_database_admin(self, new_username, new_password): + def set_database_admin(self, username): """ - Add cluster admin + Set user as database admin """ response = requests.post( - "{0}/db/{1}/admins?u={2}&p={3}".format( + "{0}/db/{1}/admins/{2}?u={3}&p={4}".format( self._baseurl, self._database, + username, self._username, - self._password), - data=json.dumps({ - 'username': new_username, - 'password': new_password}), - headers=self._headers) - - if response.status_code == 200: + self._password)) + if response.status_code == 204: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) - # TODO: Not working - def update_database_admin_password(self, username, new_password): + def unset_database_admin(self, username): """ - Update database admin password + Unset user as database admin """ - response = requests.post( + response = requests.delete( "{0}/db/{1}/admins/{2}?u={3}&p={4}".format( self._baseurl, self._database, username, self._username, - self._password), - data=json.dumps({ - 'password': new_password}), - headers=self._headers) - - if response.status_code == 200: + self._password)) + if response.status_code == 204: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) - # TODO: Not working - def delete_database_admin(self, username): - """ - Delete database admin - """ - response = requests.delete("{0}/db/{1}/admins/{2}?u={3}&p={4}".format( - self._baseurl, - self._database, - username, - self._username, - self._password)) - if response.status_code == 204: - return True - else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) +# # TODO: Not working +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) +# def get_list_database_admins(self): +# """ +# Get list of database admins +# """ +# response = requests.get( +# "{0}/db/{1}/admins?u={2}&p={3}".format( +# self._baseurl, +# self._database, +# self._username, +# self._password)) +# +# if response.status_code == 200: +# return json.loads(response.content) +# else: +# raise Exception("{0}: {1}".format(response.status_code, response.content)) +# +# # TODO: Not working +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) +# def add_database_admin(self, new_username, new_password): +# """ +# Add cluster admin +# """ +# response = requests.post( +# "{0}/db/{1}/admins?u={2}&p={3}".format( +# self._baseurl, +# self._database, +# self._username, +# self._password), +# data=json.dumps({ +# 'username': new_username, +# 'password': new_password}), +# headers=self._headers) +# +# if response.status_code == 200: +# return True +# else: +# raise Exception("{0}: {1}".format(response.status_code, response.content)) +# +# # TODO: Not working +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) +# def update_database_admin_password(self, username, new_password): +# """ +# Update database admin password +# """ +# response = requests.post( +# "{0}/db/{1}/admins/{2}?u={3}&p={4}".format( +# self._baseurl, +# self._database, +# username, +# self._username, +# self._password), +# data=json.dumps({ +# 'password': new_password}), +# headers=self._headers) +# +# if response.status_code == 200: +# return True +# else: +# raise Exception("{0}: {1}".format(response.status_code, response.content)) +# +# # TODO: Not working +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) +# def delete_database_admin(self, username): +# """ +# Delete database admin +# """ +# response = requests.delete("{0}/db/{1}/admins/{2}?u={3}&p={4}".format( +# self._baseurl, +# self._database, +# username, +# self._username, +# self._password)) +# +# if response.status_code == 204: +# return True +# else: +# raise Exception("{0}: {1}".format(response.status_code, response.content)) ### # Limiting User Access @@ -446,7 +475,8 @@ def get_database_users(self): if response.status_code == 200: return json.loads(response.content) else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def add_database_user(self, new_username, new_password): """ @@ -466,7 +496,8 @@ def add_database_user(self, new_username, new_password): if response.status_code == 200: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def update_database_user_password(self, username, new_password): """ @@ -488,7 +519,8 @@ def update_database_user_password(self, username, new_password): self._password = new_password return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) def delete_database_user(self, username): """ @@ -505,12 +537,13 @@ def delete_database_user(self, username): if response.status_code == 200: return True else: - raise Exception("{0}: {1}".format(response.status_code, response.content)) - - # update the user by POSTing to db/site_dev/users/paul + raise Exception( + "{0}: {1}".format(response.status_code, response.content)) - def update_permission(self, json_body): - """ - TODO: Update read/write permission - """ - raise NotImplemented() +# # update the user by POSTing to db/site_dev/users/paul +# +# def update_permission(self, json_body): +# """ +# TODO: Update read/write permission +# """ +# raise NotImplemented() From 3a24c5281865b219d45b455d847c24cef0103e19 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 23:39:57 +0900 Subject: [PATCH 15/20] unset/setDbAdmin returns 200, not 204 --- influxdb/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index aff3ea48..cf86a6b6 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -335,7 +335,7 @@ def set_database_admin(self, username): username, self._username, self._password)) - if response.status_code == 204: + if response.status_code == 200: return True else: raise Exception( @@ -352,7 +352,7 @@ def unset_database_admin(self, username): username, self._username, self._password)) - if response.status_code == 204: + if response.status_code == 200: return True else: raise Exception( @@ -541,6 +541,8 @@ def delete_database_user(self, username): "{0}: {1}".format(response.status_code, response.content)) # # update the user by POSTing to db/site_dev/users/paul +# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 +# # see also: src/api/http/api.go:l57) # # def update_permission(self, json_body): # """ From acc27c3637af3ddee5565c2cefb0cb858ffc2be8 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Thu, 7 Nov 2013 23:59:44 +0900 Subject: [PATCH 16/20] Use NotImplementedError exceptions --- influxdb/client.py | 238 ++++++++++++++++++++------------------------- 1 file changed, 106 insertions(+), 132 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index cf86a6b6..7a788ad3 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -2,16 +2,21 @@ """ python client for influxdb """ -import requests import json import urllib +import requests + class InfluxDBClient(object): """ InfluxDB Client """ + def __init__(self, host, port, username, password, database): + """ + Initialize client + """ self._host = host self._port = port self._username = username @@ -72,7 +77,7 @@ def write_points(self, data): raise Exception( "{0}: {1}".format(response.status_code, response.content)) - def write_points_with_time_precision(self, data, time_precision='s'): + def write_points_with_precision(self, data, time_precision='s'): """ Write to multiple time series names """ @@ -97,42 +102,56 @@ def write_points_with_time_precision(self, data, time_precision='s'): raise Exception( "{0}: {1}".format(response.status_code, response.content)) -# # One Time Deletes -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# def delete_points(self, name, -# regex=None, start_epoch=None, end_epoch=None): -# """ -# TODO: Delete a range of data -# """ -# raise NotImplemented() -# -# # Regularly Scheduled Deletes -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# def create_scheduled_delete(self, json_body): -# """ -# TODO: Create scheduled delete -# """ -# raise NotImplemented() -# -# # get list of deletes -# # curl http://localhost:8086/db/site_dev/scheduled_deletes -# # -# # remove a regularly scheduled delete -# # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id -# -# def get_list_scheduled_delete(self): -# """ -# TODO: Get list of scheduled deletes -# """ -# raise NotImplemented() -# -# def remove_scheduled_delete(self, delete_id): -# """ -# TODO: Remove scheduled delete -# """ -# raise NotImplemented() + # One Time Deletes + + # todo + def delete_points(self, name, + regex=None, start_epoch=None, end_epoch=None): + """ + Delete a range of data + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() + + # Regularly Scheduled Deletes + + # todo + def create_scheduled_delete(self, json_body): + """ + Create scheduled delete + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() + + # get list of deletes + # curl http://localhost:8086/db/site_dev/scheduled_deletes + # + # remove a regularly scheduled delete + # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id + + # todo + def get_list_scheduled_delete(self): + """ + Get list of scheduled deletes + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() + + # todo + def remove_scheduled_delete(self, delete_id): + """ + Remove scheduled delete + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() # Querying Data # @@ -246,11 +265,12 @@ def delete_database(self, database): # -d '{"username": "paul", "password": "i write teh docz"}' # update database admin password - # curl -X POST http://localhost:8086/db/site_dev/admins/paul?u=root&p=root \ + # curl -X POST http://localhost:8086/db/site_dev/admins/paul?u=root&p=root\ # -d '{"password": "new pass"}' # delete database admin - # curl -X DELETE http://localhost:8086/db/site_dev/admins/paul?u=root&p=root + # curl -X DELETE \ + # http://localhost:8086/db/site_dev/admins/paul?u=root&p=root def get_list_cluster_admins(self): """ @@ -358,90 +378,45 @@ def unset_database_admin(self, username): raise Exception( "{0}: {1}".format(response.status_code, response.content)) + # todo + def get_list_database_admins(self): + """ + Get list of database admins -# # TODO: Not working -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# def get_list_database_admins(self): -# """ -# Get list of database admins -# """ -# response = requests.get( -# "{0}/db/{1}/admins?u={2}&p={3}".format( -# self._baseurl, -# self._database, -# self._username, -# self._password)) -# -# if response.status_code == 200: -# return json.loads(response.content) -# else: -# raise Exception("{0}: {1}".format(response.status_code, response.content)) -# -# # TODO: Not working -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# def add_database_admin(self, new_username, new_password): -# """ -# Add cluster admin -# """ -# response = requests.post( -# "{0}/db/{1}/admins?u={2}&p={3}".format( -# self._baseurl, -# self._database, -# self._username, -# self._password), -# data=json.dumps({ -# 'username': new_username, -# 'password': new_password}), -# headers=self._headers) -# -# if response.status_code == 200: -# return True -# else: -# raise Exception("{0}: {1}".format(response.status_code, response.content)) -# -# # TODO: Not working -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# def update_database_admin_password(self, username, new_password): -# """ -# Update database admin password -# """ -# response = requests.post( -# "{0}/db/{1}/admins/{2}?u={3}&p={4}".format( -# self._baseurl, -# self._database, -# username, -# self._username, -# self._password), -# data=json.dumps({ -# 'password': new_password}), -# headers=self._headers) -# -# if response.status_code == 200: -# return True -# else: -# raise Exception("{0}: {1}".format(response.status_code, response.content)) -# -# # TODO: Not working -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# def delete_database_admin(self, username): -# """ -# Delete database admin -# """ -# response = requests.delete("{0}/db/{1}/admins/{2}?u={3}&p={4}".format( -# self._baseurl, -# self._database, -# username, -# self._username, -# self._password)) -# -# if response.status_code == 204: -# return True -# else: -# raise Exception("{0}: {1}".format(response.status_code, response.content)) + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() + + # todo + def add_database_admin(self, new_username, new_password): + """ + Add cluster admin + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() + + # todo + def update_database_admin_password(self, username, new_password): + """ + Update database admin password + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() + + # todo + def delete_database_admin(self, username): + """ + Delete database admin + + This endpoint has been not implemented yet in InfluxDB ver0.0.8 + See also: src/api/http/api.go:l57 + """ + raise NotImplementedError() ### # Limiting User Access @@ -540,12 +515,11 @@ def delete_database_user(self, username): raise Exception( "{0}: {1}".format(response.status_code, response.content)) -# # update the user by POSTing to db/site_dev/users/paul -# # (I guess this endpoint is not implemented in InfluxDB v0.0.7 -# # see also: src/api/http/api.go:l57) -# -# def update_permission(self, json_body): -# """ -# TODO: Update read/write permission -# """ -# raise NotImplemented() + # update the user by POSTing to db/site_dev/users/paul + + # todo + def update_permission(self, json_body): + """ + Update read/write permission + """ + raise NotImplementedError() From 5ead1d8c4583ef2acf90334c1f1319ee0c4d6931 Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Fri, 8 Nov 2013 10:50:08 +0900 Subject: [PATCH 17/20] Update unit tests --- influxdb/client.py | 2 +- tests/influxdb/client_test.py | 127 ++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/influxdb/client.py b/influxdb/client.py index 7a788ad3..cc262e15 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -518,7 +518,7 @@ def delete_database_user(self, username): # update the user by POSTing to db/site_dev/users/paul # todo - def update_permission(self, json_body): + def update_permission(self, username, json_body): """ Update read/write permission """ diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 63ad28c6..987a0605 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- +""" +unit tests +""" import requests from nose.tools import raises from mock import patch @@ -25,6 +28,77 @@ def test_switch_user(self): assert cli._username == 'another_username' assert cli._password == 'another_password' + def test_write_points(self): + data = [ + { + "points": [ + ["1", 1, 1.0], + ["2", 2, 2.0] + ], + "name": "foo", + "columns": ["column_one", "column_two", "column_three"] + } + ] + + with patch.object(requests, 'post') as mocked_post: + mocked_post.return_value = _build_response_object(status_code=200) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + assert cli.write_points(data) is True + + @raises(Exception) + def test_write_points_fails(self): + with patch.object(requests, 'post') as mocked_post: + mocked_post.return_value = _build_response_object(status_code=500) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.write_points([]) + + def test_write_points_with_precision(self): + data = [ + { + "points": [ + ["1", 1, 1.0], + ["2", 2, 2.0] + ], + "name": "foo", + "columns": ["column_one", "column_two", "column_three"] + } + ] + + with patch.object(requests, 'post') as mocked_post: + mocked_post.return_value = _build_response_object(status_code=200) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + assert cli.write_points_with_precision(data) is True + + @raises(Exception) + def test_write_points_with_precision_fails(self): + with patch.object(requests, 'post') as mocked_post: + mocked_post.return_value = _build_response_object(status_code=500) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.write_points_with_precision([]) + + @raises(NotImplementedError) + def test_delete_points(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.delete_points([]) + + @raises(NotImplementedError) + def test_create_scheduled_delete(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.create_scheduled_delete([]) + + @raises(NotImplementedError) + def test_get_list_scheduled_delete(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.get_list_scheduled_delete() + + @raises(NotImplementedError) + def test_remove_scheduled_delete(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.remove_scheduled_delete(1) + + def test_query(self): + pass + def test_create_database(self): with patch.object(requests, 'post') as mocked_post: mocked_post.return_value = _build_response_object(status_code=201) @@ -51,4 +125,57 @@ def test_delete_database_fails(self): cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') cli.delete_database('old_db') + def test_get_list_cluster_admins(self): + pass + + def test_add_cluster_admin(self): + pass + + def test_update_cluster_admin_password(self): + pass + + def test_delete_cluster_admin(self): + pass + + def test_set_database_admin(self): + pass + + def test_unset_database_admin(self): + pass + + @raises(NotImplementedError) + def test_get_list_database_admins(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.get_list_database_admins() + + @raises(NotImplementedError) + def test_add_database_admin(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.add_database_admin('admin', 'admin_secret_password') + + @raises(NotImplementedError) + def test_update_database_admin_password(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.update_database_admin_password('admin', 'admin_secret_password') + + @raises(NotImplementedError) + def test_delete_database_admin(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.delete_database_admin('admin') + + def test_get_database_user(self): + pass + + def test_add_database_user(self): + pass + + def test_update_database_user_password(self): + pass + + def test_delete_database_user(self): + pass + @raises(NotImplementedError) + def test_update_permission(self): + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.update_permission('admin', []) From 56cab640303a018189dbde70b117078bc860f8ac Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Fri, 8 Nov 2013 10:58:58 +0900 Subject: [PATCH 18/20] Update docstring of unimplemented API --- influxdb/client.py | 55 ++++++++++++++++++++++++---------------------- tox.ini | 2 +- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index cc262e15..edaf4c1f 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -104,25 +104,25 @@ def write_points_with_precision(self, data, time_precision='s'): # One Time Deletes - # todo def delete_points(self, name, regex=None, start_epoch=None, end_epoch=None): """ - Delete a range of data + TODO: Delete a range of data - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() # Regularly Scheduled Deletes - # todo def create_scheduled_delete(self, json_body): """ - Create scheduled delete + TODO: Create scheduled delete - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() @@ -133,22 +133,22 @@ def create_scheduled_delete(self, json_body): # remove a regularly scheduled delete # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id - # todo def get_list_scheduled_delete(self): """ - Get list of scheduled deletes + TODO: Get list of scheduled deletes - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() - # todo def remove_scheduled_delete(self, delete_id): """ - Remove scheduled delete + TODO: Remove scheduled delete - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() @@ -378,42 +378,42 @@ def unset_database_admin(self, username): raise Exception( "{0}: {1}".format(response.status_code, response.content)) - # todo def get_list_database_admins(self): """ - Get list of database admins + TODO: Get list of database admins - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() - # todo def add_database_admin(self, new_username, new_password): """ - Add cluster admin + TODO: Add cluster admin - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() - # todo def update_database_admin_password(self, username, new_password): """ - Update database admin password + TODO: Update database admin password - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() - # todo def delete_database_admin(self, username): """ - Delete database admin + TODO: Delete database admin - This endpoint has been not implemented yet in InfluxDB ver0.0.8 + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. See also: src/api/http/api.go:l57 """ raise NotImplementedError() @@ -517,9 +517,12 @@ def delete_database_user(self, username): # update the user by POSTing to db/site_dev/users/paul - # todo def update_permission(self, username, json_body): """ - Update read/write permission + TODO: Update read/write permission + + 2013-11-08: This endpoint has not been implemented yet in ver0.0.8, + but it is documented in http://influxdb.org/docs/api/http.html. + See also: src/api/http/api.go:l57 """ raise NotImplementedError() diff --git a/tox.ini b/tox.ini index 237ffa90..f5128281 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py32, py27, flake8 +envlist = py33, py27, flake8 [testenv] commands = From ed17edaebb1fbc53d60ad69205ec65a1cc5e895f Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Fri, 8 Nov 2013 11:20:21 +0900 Subject: [PATCH 19/20] Use six for python3/2 compatibility --- influxdb/client.py | 5 +++-- requirements.txt | 1 + tests/influxdb/client_test.py | 11 ++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/influxdb/client.py b/influxdb/client.py index edaf4c1f..90d1ff3a 100644 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -3,7 +3,8 @@ python client for influxdb """ import json -import urllib + +from six.moves.urllib.parse import urlencode import requests @@ -169,7 +170,7 @@ def query(self, query, time_precision='s', chunked=False): else: chunked_param = 'false' - encoded_query = urllib.urlencode({ + encoded_query = urlencode({ 'q': query}) url_format = "{0}/db/{1}/series?{2}&u={3}&p={4}" diff --git a/requirements.txt b/requirements.txt index f2293605..c7d0ccea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ +six requests diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 987a0605..9adbe4af 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -2,6 +2,8 @@ """ unit tests """ +import json + import requests from nose.tools import raises from mock import patch @@ -97,7 +99,14 @@ def test_remove_scheduled_delete(self): cli.remove_scheduled_delete(1) def test_query(self): - pass + expected = """[{"name":"foo","columns":["time","sequence_number","column_one"],"points":[[1383876043,16,"2"],[1383876043,15,"1"],[1383876035,14,"2"],[1383876035,13,"1"]]}]""" + with patch.object(requests, 'get') as mocked_get: + mocked_get.return_value = _build_response_object( + status_code=200, + content=expected) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + result = cli.query('select column_one from foo;') + assert len(json.loads(result)[0]['points']) == 4 def test_create_database(self): with patch.object(requests, 'post') as mocked_post: From e05df22d06a42c1fb68d3546a11a42826a99c5da Mon Sep 17 00:00:00 2001 From: Kohei Ozaki Date: Fri, 8 Nov 2013 11:22:22 +0900 Subject: [PATCH 20/20] Add testcase of query() --- tests/influxdb/client_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 9adbe4af..811548d3 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -108,6 +108,13 @@ def test_query(self): result = cli.query('select column_one from foo;') assert len(json.loads(result)[0]['points']) == 4 + @raises(Exception) + def test_query_fail(self): + with patch.object(requests, 'get') as mocked_get: + mocked_get.return_value = _build_response_object(status_code=401) + cli = InfluxDBClient('host', 8086, 'username', 'password', 'db') + cli.query('select column_one from foo;') + def test_create_database(self): with patch.object(requests, 'post') as mocked_post: mocked_post.return_value = _build_response_object(status_code=201)