-
Notifications
You must be signed in to change notification settings - Fork 46
Dbapi2 #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Dbapi2 #161
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
e99662d
appveyor: Add python 3.8 to environment matrix
artembo c529767
Add sql execute to Connection
artembo 00d315b
Make use_list param configurable
artembo e43e41e
Add pep-249 dbapi module
artembo 5160aaf
Add unit tests for dbapi module
artembo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add pep-249 dbapi module
See [1] for details. The main motivation for the module creation was the integration Django with Tarantool database through django-tarantool database backend [2] which requires dbapi connector for the database. The most of the optional extensions and methods were ignored because Django does not require them. Anyway, feel free to suggest its implementation as needed. Interactive transactions are not currently supported by Tarantool and theirs implementation will be added in the connector when the feature is stable in Tarantool itself. [1] https://www.python.org/dev/peps/pep-0249/ [2] https://github.com/artembo/django-tarantool Co-authored-by: Denis Ignatenko <[email protected]>
- Loading branch information
commit e43e41e5e918aeac14dee3ec6642ade64f9dc35e
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,248 @@ | ||
| # -*- coding: utf-8 -*- | ||
| from tarantool.connection import Connection as BaseConnection | ||
| from tarantool.error import * | ||
|
|
||
artembo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| paramstyle = 'named' | ||
| apilevel = "2.0" | ||
| threadsafety = 1 | ||
|
|
||
|
|
||
| class Cursor: | ||
|
|
||
| def __init__(self, conn): | ||
| self._c = conn | ||
| self._lastrowid = None | ||
| self._rowcount = None | ||
| self.arraysize = 1 | ||
| self._rows = None | ||
|
|
||
| def callproc(self, procname, *params): | ||
| """ | ||
| Call a stored database procedure with the given name. The sequence of | ||
| parameters must contain one entry for each argument that the | ||
| procedure expects. The result of the call is returned as modified | ||
| copy of the input sequence. Input parameters are left untouched, | ||
| output and input/output parameters replaced with possibly new values. | ||
| """ | ||
| raise NotSupportedError("callproc() method is not supported") | ||
|
|
||
| @property | ||
| def rows(self): | ||
| return self._rows | ||
|
|
||
| @property | ||
| def description(self): | ||
| # FIXME Implement this method please | ||
| raise NotImplementedError("description() property is not implemented") | ||
|
|
||
| def close(self): | ||
| """ | ||
| Close the cursor now (rather than whenever __del__ is called). | ||
| The cursor will be unusable from this point forward; DatabaseError | ||
| exception will be raised if any operation is attempted with | ||
| the cursor. | ||
| """ | ||
| self._c = None | ||
artembo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self._rows = None | ||
| self._lastrowid = None | ||
| self._rowcount = None | ||
|
|
||
| def _check_not_closed(self, error=None): | ||
| if self._c is None: | ||
| raise InterfaceError(error or "Can not operate on a closed cursor") | ||
| if self._c.is_closed(): | ||
| raise InterfaceError("The cursor can not be used " | ||
| "with a closed connection") | ||
|
|
||
| def execute(self, query, params=None): | ||
| """ | ||
| Prepare and execute a database operation (query or command). | ||
| """ | ||
| self._check_not_closed("Can not execute on closed cursor.") | ||
|
|
||
| response = self._c.execute(query, params) | ||
|
|
||
| self._rows = response.data | ||
| self._rowcount = response.affected_row_count or -1 | ||
| if response.autoincrement_ids: | ||
| self._lastrowid = response.autoincrement_ids[-1] | ||
| else: | ||
| self._lastrowid = None | ||
|
|
||
| def executemany(self, query, param_sets): | ||
| self._check_not_closed("Can not execute on closed cursor.") | ||
| rowcount = 0 | ||
| for params in param_sets: | ||
| self.execute(query, params) | ||
| if self.rowcount == -1: | ||
| rowcount = -1 | ||
| if rowcount != -1: | ||
| rowcount += self.rowcount | ||
| self._rowcount = rowcount | ||
|
|
||
| @property | ||
| def lastrowid(self): | ||
| """ | ||
| This read-only attribute provides the rowid of the last modified row | ||
| (most databases return a rowid only when a single INSERT operation is | ||
| performed). | ||
| """ | ||
| return self._lastrowid | ||
|
|
||
| @property | ||
| def rowcount(self): | ||
| """ | ||
| This read-only attribute specifies the number of rows that the last | ||
| .execute*() produced (for DQL statements like SELECT) or affected ( | ||
| for DML statements like UPDATE or INSERT). | ||
| """ | ||
| return self._rowcount | ||
|
|
||
| def _check_result_set(self, error=None): | ||
| """ | ||
| Non-public method for raising an error when Cursor object does not have | ||
| any row to fetch. Useful for checking access after DQL requests. | ||
| """ | ||
| if self._rows is None: | ||
| raise InterfaceError(error or "No result set to fetch from") | ||
|
|
||
| def fetchone(self): | ||
| """ | ||
| Fetch the next row of a query result set, returning a single | ||
| sequence, or None when no more data is available. | ||
| """ | ||
| self._check_result_set() | ||
| return self.fetchmany(1)[0] if self._rows else None | ||
|
|
||
| def fetchmany(self, size=None): | ||
| """ | ||
| Fetch the next set of rows of a query result, returning a sequence of | ||
| sequences (e.g. a list of tuples). An empty sequence is returned when | ||
| no more rows are available. | ||
| """ | ||
| self._check_result_set() | ||
|
|
||
| size = size or self.arraysize | ||
|
|
||
| if len(self._rows) < size: | ||
| items = self._rows | ||
| self._rows = [] | ||
| else: | ||
| items, self._rows = self._rows[:size], self._rows[size:] | ||
|
|
||
| return items | ||
|
|
||
| def fetchall(self): | ||
| """Fetch all (remaining) rows of a query result, returning them as a | ||
| sequence of sequences (e.g. a list of tuples). Note that the cursor's | ||
| arraysize attribute can affect the performance of this operation. | ||
| """ | ||
| self._check_result_set() | ||
|
|
||
| items = self._rows | ||
| self._rows = [] | ||
| return items | ||
|
|
||
| def setinputsizes(self, sizes): | ||
| """PEP-249 allows to not implement this method and do nothing.""" | ||
|
|
||
| def setoutputsize(self, size, column=None): | ||
| """PEP-249 allows to not implement this method and do nothing.""" | ||
|
|
||
|
|
||
| class Connection(BaseConnection): | ||
|
|
||
| def __init__(self, *args, **kwargs): | ||
| super(Connection, self).__init__(*args, **kwargs) | ||
| self._set_autocommit(kwargs.get('autocommit', True)) | ||
|
|
||
| def _set_autocommit(self, autocommit): | ||
| """Autocommit is True by default and the default will be changed | ||
| to False. Set the autocommit property explicitly to True or verify | ||
| it when lean on autocommit behaviour.""" | ||
| if not isinstance(autocommit, bool): | ||
| raise InterfaceError("autocommit parameter must be boolean, " | ||
| "not %s" % autocommit.__class__.__name__) | ||
| if autocommit is False: | ||
| raise NotSupportedError("The connector supports " | ||
| "only autocommit mode") | ||
| self._autocommit = autocommit | ||
|
|
||
| @property | ||
| def autocommit(self): | ||
| """Autocommit state""" | ||
| return self._autocommit | ||
|
|
||
| @autocommit.setter | ||
| def autocommit(self, autocommit): | ||
| """Set autocommit state""" | ||
| self._set_autocommit(autocommit) | ||
|
|
||
artembo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def _check_not_closed(self, error=None): | ||
| """ | ||
| Checks if the connection is not closed and rises an error if it is. | ||
| """ | ||
| if self.is_closed(): | ||
| raise InterfaceError(error or "The connector is closed") | ||
|
|
||
| def close(self): | ||
| """ | ||
| Closes the connection | ||
| """ | ||
| self._check_not_closed("The closed connector can not be closed again.") | ||
| super(Connection, self).close() | ||
artembo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def commit(self): | ||
| """ | ||
| Commit any pending transaction to the database. | ||
| """ | ||
| self._check_not_closed("Can not commit on the closed connection") | ||
|
|
||
| def rollback(self): | ||
artembo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| Roll back pending transaction | ||
| """ | ||
| self._check_not_closed("Can not roll back on a closed connection") | ||
| raise NotSupportedError("Transactions are not supported in this" | ||
| "version of connector") | ||
|
|
||
| def cursor(self): | ||
| """ | ||
| Return a new Cursor Object using the connection. | ||
| """ | ||
| self._check_not_closed("Cursor creation is not allowed on a closed " | ||
| "connection") | ||
| return Cursor(self) | ||
artembo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| def connect(dsn=None, host=None, port=None, | ||
| user=None, password=None, **kwargs): | ||
| """ | ||
| Constructor for creating a connection to the database. | ||
|
|
||
| :param str dsn: Data source name (Tarantool URI) | ||
| ([[[username[:password]@]host:]port) | ||
| :param str host: Server hostname or IP-address | ||
| :param int port: Server port | ||
| :param str user: Tarantool user | ||
| :param str password: User password | ||
| :rtype: Connection | ||
| """ | ||
|
|
||
| if dsn: | ||
| raise NotImplementedError("dsn param is not implemented in" | ||
| "this version of dbapi module") | ||
| params = {} | ||
| if host: | ||
| params["host"] = host | ||
| if port: | ||
| params["port"] = port | ||
| if user: | ||
| params["user"] = user | ||
| if password: | ||
| params["password"] = password | ||
|
|
||
| kwargs.update(params) | ||
|
|
||
| return Connection(**kwargs) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.