From 040a52f61fb108f4351e0d2a36bcfd676c85c271 Mon Sep 17 00:00:00 2001 From: Moritz Pein Date: Fri, 29 Jun 2018 10:49:45 +0200 Subject: [PATCH 1/8] Switch readme to markdown. --- README.md | 12 ++++++++++++ README.rst | 11 ----------- 2 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 0000000..97f7b0c --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +[![Build Status](https://travis-ci.org/figome/python-festung.svg?branch=master)][build status] +[![Version](https://img.shields.io/pypi/v/festung.svg?style=flat-square)][version] + +Festung DBAPI for Python +======================== + +This library provides a [Database API v2.0] to [Festung]. + +[build status]: https://travis-ci.org/figome/python-festung +[version]: https://pypi.python.org/pypi/festung +[Database API v2.0]: https://www.python.org/dev/peps/pep-0249/ +[Festung]: https://github.com/figome/festung diff --git a/README.rst b/README.rst deleted file mode 100644 index 440ebe0..0000000 --- a/README.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. image:: https://img.shields.io/travis/figome/python-festung/master.svg?style=flat-square - :target: https://travis-ci.org/figome/python-festung -.. image:: https://img.shields.io/pypi/v/festung.svg?style=flat-square - :target: https://pypi.python.org/pypi/festung - -Festung DBAPI for Python -======================== - -This library provides a `Database API v2.0`_ to Festung. - -.. _Database API v2.0: https://www.python.org/dev/peps/pep-0249/ From c61490e70795bf685fd33a0f97f84a9f28a949b2 Mon Sep 17 00:00:00 2001 From: Moritz Pein Date: Fri, 29 Jun 2018 10:49:45 +0200 Subject: [PATCH 2/8] Switch readme to markdown. --- README.md | 12 ++++++++++++ README.rst | 11 ----------- setup.cfg | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 0000000..97f7b0c --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +[![Build Status](https://travis-ci.org/figome/python-festung.svg?branch=master)][build status] +[![Version](https://img.shields.io/pypi/v/festung.svg?style=flat-square)][version] + +Festung DBAPI for Python +======================== + +This library provides a [Database API v2.0] to [Festung]. + +[build status]: https://travis-ci.org/figome/python-festung +[version]: https://pypi.python.org/pypi/festung +[Database API v2.0]: https://www.python.org/dev/peps/pep-0249/ +[Festung]: https://github.com/figome/festung diff --git a/README.rst b/README.rst deleted file mode 100644 index 440ebe0..0000000 --- a/README.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. image:: https://img.shields.io/travis/figome/python-festung/master.svg?style=flat-square - :target: https://travis-ci.org/figome/python-festung -.. image:: https://img.shields.io/pypi/v/festung.svg?style=flat-square - :target: https://pypi.python.org/pypi/festung - -Festung DBAPI for Python -======================== - -This library provides a `Database API v2.0`_ to Festung. - -.. _Database API v2.0: https://www.python.org/dev/peps/pep-0249/ diff --git a/setup.cfg b/setup.cfg index 542a29c..5aac9c0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ name = festung author = figo GmbH author-email = develop@figo.io summary = DBAPIv2 to Festung -description-file = README.rst +description-file = README.md home-page = https://github.com/figome/python-festung license = ISC classifier = From 489d5d929248cd2b0a17ec65b6fac115e17bffeb Mon Sep 17 00:00:00 2001 From: Alex Korotkikh Date: Wed, 11 Jul 2018 10:56:43 +0200 Subject: [PATCH 3/8] support bulk insert in cursor's executemany() method --- festung/_private.py | 2 ++ festung/dbapi.py | 10 +++------- tests/test_dbapi.py | 15 +++++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/festung/_private.py b/festung/_private.py index 57f2ad9..50f4683 100644 --- a/festung/_private.py +++ b/festung/_private.py @@ -77,6 +77,8 @@ def qs_to_headers(url): def cast(obj): """Cast most python types to valid types to be serialized in JSON and passed to SQLite""" + if isinstance(obj, list): + return [cast(p) for p in obj] if isinstance(obj, bool): # checking bool first as it is also an instance of int return int(obj) diff --git a/festung/dbapi.py b/festung/dbapi.py index dd66855..1fbe125 100644 --- a/festung/dbapi.py +++ b/festung/dbapi.py @@ -161,13 +161,9 @@ def execute(self, operation, parameters=None): self._description = _generate_description(response['headers']) def executemany(self, operation, parameters_sequence): - rowcount = 0 - for parameters in parameters_sequence: - self.execute(operation, parameters) - rowcount += self._rowcount - if self.fetchone() is not NO_MORE_ROW: - raise ProgrammingError("The statement shall not produce a result.") - self._rowcount = rowcount + self.execute(operation, parameters_sequence) + if self.fetchone() is not NO_MORE_ROW: + raise ProgrammingError("The statement shall not produce a result.") def fetchone(self): if self._iter is NO_EXECUTE_ITER: diff --git a/tests/test_dbapi.py b/tests/test_dbapi.py index 08f0fae..014c059 100644 --- a/tests/test_dbapi.py +++ b/tests/test_dbapi.py @@ -117,17 +117,16 @@ def test_executemany(self, festung, cursor): ['def', 2, 1.2], ['ghi', 3, None], ] - n_rows_changed = [7, 8, 9] - for n_changed in n_rows_changed: - festung.add_json_response( - {'data': [], 'headers': [], 'last_row_id': 0, 'rows_changed': n_changed}) + festung.add_json_response( + {'data': [], 'headers': [], 'last_row_id': 0, 'rows_changed': 3}) cursor.executemany(query, params_list) - for params, data in zip(params_list, festung.json_requests): - assert data['sql'] == query - assert data['params'] == params - assert cursor.rowcount == sum(n_rows_changed) + + requests = festung.json_requests + assert len(requests) == 1 + assert requests[0]['sql'] == query + assert requests[0]['params'] == params_list def test_executemany_with_result(self, festung, cursor): festung.add_json_response({ From f1d2e3ac6f2204925728bf9efbdd4d5bf5bed5c7 Mon Sep 17 00:00:00 2001 From: Alex Korotkikh Date: Wed, 11 Jul 2018 12:54:03 +0200 Subject: [PATCH 4/8] fix param name and usage --- festung/_private.py | 2 -- festung/dbapi.py | 19 ++++++++++++------- tests/test_dbapi.py | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/festung/_private.py b/festung/_private.py index 50f4683..57f2ad9 100644 --- a/festung/_private.py +++ b/festung/_private.py @@ -77,8 +77,6 @@ def qs_to_headers(url): def cast(obj): """Cast most python types to valid types to be serialized in JSON and passed to SQLite""" - if isinstance(obj, list): - return [cast(p) for p in obj] if isinstance(obj, bool): # checking bool first as it is also an instance of int return int(obj) diff --git a/festung/dbapi.py b/festung/dbapi.py index 1fbe125..5d2f7d6 100644 --- a/festung/dbapi.py +++ b/festung/dbapi.py @@ -154,14 +154,12 @@ def drop(self): def execute(self, operation, parameters=None): parameters = parameters or [] data = dict(sql=operation, params=[cast(p) for p in parameters]) - response = self._request('POST', json=data).json() - self._iter = iter(response['data']) - self.lastrowid = response['last_row_id'] - self._rowcount = response['rows_changed'] - self._description = _generate_description(response['headers']) + self._make_request(data) - def executemany(self, operation, parameters_sequence): - self.execute(operation, parameters_sequence) + def executemany(self, operation, many_rows=None): + many_rows = many_rows or [] + data = dict(sql=operation, bulk_params=[[cast(p) for p in row] for row in many_rows]) + self._make_request(data) if self.fetchone() is not NO_MORE_ROW: raise ProgrammingError("The statement shall not produce a result.") @@ -231,3 +229,10 @@ def _raise_for_error(self, response): description = error['description'] exception_class = error_to_exception[type_] raise exception_class(description) + + def _make_request(self, data): + response = self._request('POST', json=data).json() + self._iter = iter(response['data']) + self.lastrowid = response['last_row_id'] + self._rowcount = response['rows_changed'] + self._description = _generate_description(response['headers']) diff --git a/tests/test_dbapi.py b/tests/test_dbapi.py index 014c059..3cb0827 100644 --- a/tests/test_dbapi.py +++ b/tests/test_dbapi.py @@ -126,7 +126,7 @@ def test_executemany(self, festung, cursor): requests = festung.json_requests assert len(requests) == 1 assert requests[0]['sql'] == query - assert requests[0]['params'] == params_list + assert requests[0]['bulk_params'] == params_list def test_executemany_with_result(self, festung, cursor): festung.add_json_response({ From 219c6b03f122f5da50248b5dd0309b66f814d3d9 Mon Sep 17 00:00:00 2001 From: Alex Korotkikh Date: Wed, 11 Jul 2018 13:09:36 +0200 Subject: [PATCH 5/8] use dict literals instead of dict constructors --- festung/dbapi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/festung/dbapi.py b/festung/dbapi.py index 5d2f7d6..343d444 100644 --- a/festung/dbapi.py +++ b/festung/dbapi.py @@ -153,12 +153,12 @@ def drop(self): def execute(self, operation, parameters=None): parameters = parameters or [] - data = dict(sql=operation, params=[cast(p) for p in parameters]) + data = {'sql': operation, 'params': [cast(p) for p in parameters]} self._make_request(data) def executemany(self, operation, many_rows=None): many_rows = many_rows or [] - data = dict(sql=operation, bulk_params=[[cast(p) for p in row] for row in many_rows]) + data = {'sql': operation, 'bulk_params': [[cast(p) for p in row] for row in many_rows]} self._make_request(data) if self.fetchone() is not NO_MORE_ROW: raise ProgrammingError("The statement shall not produce a result.") From 201b213ccf16f8e49f6fdd7843d61bfc7d872979 Mon Sep 17 00:00:00 2001 From: Martin Domke Date: Wed, 11 Jul 2018 18:02:59 +0200 Subject: [PATCH 6/8] style: Stick to DBAPI 2.0 specification --- festung/dbapi.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/festung/dbapi.py b/festung/dbapi.py index 343d444..4ee4dc2 100644 --- a/festung/dbapi.py +++ b/festung/dbapi.py @@ -156,9 +156,11 @@ def execute(self, operation, parameters=None): data = {'sql': operation, 'params': [cast(p) for p in parameters]} self._make_request(data) - def executemany(self, operation, many_rows=None): - many_rows = many_rows or [] - data = {'sql': operation, 'bulk_params': [[cast(p) for p in row] for row in many_rows]} + def executemany(self, operation, parameters_sequence): + data = { + 'sql': operation, + 'bulk_params': [[cast(p) for p in row] for row in parameters_sequence], + } self._make_request(data) if self.fetchone() is not NO_MORE_ROW: raise ProgrammingError("The statement shall not produce a result.") @@ -223,7 +225,7 @@ def _raise_for_error(self, response): error = response.json()['error'] except ValueError as e: raise InternalError("Invalid JSON: {}".format(e)) - except KeyError as e: + except KeyError: raise InternalError("Missing error in response.") type_ = error['type'] description = error['description'] From bb90a25d65aa5a43aaa10d3d0730c74784f9f3b0 Mon Sep 17 00:00:00 2001 From: Martin Domke Date: Thu, 25 Oct 2018 12:55:16 +0200 Subject: [PATCH 7/8] Upgrade requirements --- requirements.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 51f143e..f969c31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile --output-file requirements.txt requirements.in # +certifi==2018.10.15 # via requests +chardet==3.0.4 # via requests enum34==1.1.6 -furl==1.0.0 -orderedmultidict==0.7.11 # via furl -requests==2.13.0 -simplejson==3.10.0 -six==1.10.0 # via furl, orderedmultidict +furl==2.0.0 +idna==2.7 # via requests +orderedmultidict==1.0 # via furl +requests==2.20.0 +simplejson==3.16.0 +six==1.11.0 # via furl, orderedmultidict +urllib3==1.24 # via requests From b2ae4c86abf3e3bdb85b61644d977a5b290e9373 Mon Sep 17 00:00:00 2001 From: Martin Domke Date: Thu, 25 Oct 2018 12:55:43 +0200 Subject: [PATCH 8/8] Replace dict construct with literal --- tests/test_dbapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dbapi.py b/tests/test_dbapi.py index 3cb0827..d815463 100644 --- a/tests/test_dbapi.py +++ b/tests/test_dbapi.py @@ -23,7 +23,7 @@ def connection_kwargs(request, connection_session): if request.param == 'managed': return {} elif request.param == 'external': - return dict(session=connection_session) + return {'session': connection_session} else: assert False, "Not all parameters are supported"