[Python-modules-commits] [aiopg] 01/03: Import aiopg_0.13.2.orig.tar.gz
Piotr Ożarowski
piotr at moszumanska.debian.org
Thu Feb 8 20:24:59 UTC 2018
This is an automated email from the git hooks/post-receive script.
piotr pushed a commit to branch master
in repository aiopg.
commit 4bf3e62a72e69227d3b2407acc44f7c6b7c63578
Author: Piotr Ożarowski <piotr at debian.org>
Date: Thu Feb 8 21:21:21 2018 +0100
Import aiopg_0.13.2.orig.tar.gz
---
CHANGES.txt | 8 ++
PKG-INFO | 10 ++-
aiopg.egg-info/PKG-INFO | 10 ++-
aiopg.egg-info/SOURCES.txt | 1 +
aiopg/__init__.py | 12 +--
aiopg/cursor.py | 15 +++-
aiopg/sa/result.py | 7 +-
aiopg/transaction.py | 191 +++++++++++++++++++++++++++++++++++++++++++++
aiopg/utils.py | 35 +++++++--
9 files changed, 271 insertions(+), 18 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 002b82a..f8d7292 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,14 @@
CHANGES
-------
+0.13.2 (2018-01-03)
+^^^^^^^^^^^^^^^^^^^
+
+* Fixed compatibility with SQLAlchemy 1.2.0 #412
+
+* Added support for transaction isolation levels #219
+
+
0.13.1 (2017-09-10)
^^^^^^^^^^^^^^^^^^^
diff --git a/PKG-INFO b/PKG-INFO
index abee651..78e0a3e 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: aiopg
-Version: 0.13.1
+Version: 0.13.2
Summary: Postgres integration with asyncio.
Home-page: https://aiopg.readthedocs.io
Author: Andrew Svetlov
@@ -99,6 +99,14 @@ Description: aiopg
CHANGES
-------
+ 0.13.2 (2018-01-03)
+ ^^^^^^^^^^^^^^^^^^^
+
+ * Fixed compatibility with SQLAlchemy 1.2.0 #412
+
+ * Added support for transaction isolation levels #219
+
+
0.13.1 (2017-09-10)
^^^^^^^^^^^^^^^^^^^
diff --git a/aiopg.egg-info/PKG-INFO b/aiopg.egg-info/PKG-INFO
index abee651..78e0a3e 100644
--- a/aiopg.egg-info/PKG-INFO
+++ b/aiopg.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: aiopg
-Version: 0.13.1
+Version: 0.13.2
Summary: Postgres integration with asyncio.
Home-page: https://aiopg.readthedocs.io
Author: Andrew Svetlov
@@ -99,6 +99,14 @@ Description: aiopg
CHANGES
-------
+ 0.13.2 (2018-01-03)
+ ^^^^^^^^^^^^^^^^^^^
+
+ * Fixed compatibility with SQLAlchemy 1.2.0 #412
+
+ * Added support for transaction isolation levels #219
+
+
0.13.1 (2017-09-10)
^^^^^^^^^^^^^^^^^^^
diff --git a/aiopg.egg-info/SOURCES.txt b/aiopg.egg-info/SOURCES.txt
index 65e87eb..43e412e 100644
--- a/aiopg.egg-info/SOURCES.txt
+++ b/aiopg.egg-info/SOURCES.txt
@@ -9,6 +9,7 @@ aiopg/connection.py
aiopg/cursor.py
aiopg/log.py
aiopg/pool.py
+aiopg/transaction.py
aiopg/utils.py
aiopg.egg-info/PKG-INFO
aiopg.egg-info/SOURCES.txt
diff --git a/aiopg/__init__.py b/aiopg/__init__.py
index b6f3462..c5005c0 100644
--- a/aiopg/__init__.py
+++ b/aiopg/__init__.py
@@ -5,16 +5,16 @@ from collections import namedtuple
from .connection import connect, Connection, TIMEOUT as DEFAULT_TIMEOUT
from .cursor import Cursor
from .pool import create_pool, Pool
-
+from .transaction import IsolationLevel, Transaction
__all__ = ('connect', 'create_pool', 'Connection', 'Cursor', 'Pool',
- 'version', 'version_info', 'DEFAULT_TIMEOUT')
+ 'version', 'version_info', 'DEFAULT_TIMEOUT', 'IsolationLevel',
+ 'Transaction')
-__version__ = '0.13.1'
+__version__ = '0.13.2'
version = __version__ + ' , Python ' + sys.version
-
VersionInfo = namedtuple('VersionInfo',
'major minor micro releaselevel serial')
@@ -40,6 +40,6 @@ def _parse_version(ver):
version_info = _parse_version(__version__)
-
# make pyflakes happy
-(connect, create_pool, Connection, Cursor, Pool, DEFAULT_TIMEOUT)
+(connect, create_pool, Connection, Cursor, Pool, DEFAULT_TIMEOUT,
+ IsolationLevel, Transaction)
diff --git a/aiopg/cursor.py b/aiopg/cursor.py
index f3db330..1ca7f8d 100644
--- a/aiopg/cursor.py
+++ b/aiopg/cursor.py
@@ -4,16 +4,17 @@ import warnings
import psycopg2
from .log import logger
-from .utils import PY_35, PY_352
+from .transaction import Transaction, IsolationLevel
+from .utils import PY_35, PY_352, _TransactionBeginContextManager
class Cursor:
-
def __init__(self, conn, impl, timeout, echo):
self._conn = conn
self._impl = impl
self._timeout = timeout
self._echo = echo
+ self._transaction = Transaction(self, IsolationLevel.repeatable_read)
@property
def echo(self):
@@ -146,6 +147,16 @@ class Cursor:
else:
yield from self._conn._poll(waiter, timeout)
+ def begin(self):
+ return _TransactionBeginContextManager(self._transaction.begin())
+
+ def begin_nested(self):
+ if not self._transaction.is_begin:
+ return _TransactionBeginContextManager(
+ self._transaction.begin())
+ else:
+ return self._transaction.point()
+
@asyncio.coroutine
def mogrify(self, operation, parameters=None):
"""Return a query string after arguments binding.
diff --git a/aiopg/sa/result.py b/aiopg/sa/result.py
index 1e47c4c..f3106d1 100644
--- a/aiopg/sa/result.py
+++ b/aiopg/sa/result.py
@@ -100,7 +100,12 @@ class ResultMetaData(object):
self._keymap = keymap = {}
self.keys = []
dialect = result_proxy.dialect
- typemap = dialect.dbapi_type_map
+
+ # `dbapi_type_map` property removed in SQLAlchemy 1.2+.
+ # Usage of `getattr` only needed for backward compatibility with
+ # older versions of SQLAlchemy.
+ typemap = getattr(dialect, 'dbapi_type_map', {})
+
assert dialect.case_sensitive, \
"Doesn't support case insensitive database connection"
diff --git a/aiopg/transaction.py b/aiopg/transaction.py
new file mode 100644
index 0000000..55f69ab
--- /dev/null
+++ b/aiopg/transaction.py
@@ -0,0 +1,191 @@
+import asyncio
+import enum
+import uuid
+import warnings
+from abc import ABC, abstractmethod
+
+import psycopg2
+from aiopg.utils import PY_35, _TransactionPointContextManager
+
+__all__ = ('IsolationLevel', 'Transaction')
+
+
+class IsolationCompiler(ABC):
+ name = ''
+
+ __slots__ = ('_readonly', '_deferrable')
+
+ def __init__(self, readonly, deferrable):
+ self._readonly = readonly
+ self._deferrable = deferrable
+ self._check_readonly_deferrable()
+
+ def _check_readonly_deferrable(self):
+ available = self._readonly or self._deferrable
+ if not isinstance(self, SerializableCompiler) and available:
+ raise ValueError('Is only available for serializable transactions')
+
+ def savepoint(self, unique_id):
+ return 'SAVEPOINT {}'.format(unique_id)
+
+ def release_savepoint(self, unique_id):
+ return 'RELEASE SAVEPOINT {}'.format(unique_id)
+
+ def rollback_savepoint(self, unique_id):
+ return 'ROLLBACK TO SAVEPOINT {}'.format(unique_id)
+
+ def commit(self):
+ return 'COMMIT'
+
+ def rollback(self):
+ return 'ROLLBACK'
+
+ @abstractmethod
+ def begin(self):
+ raise NotImplementedError("Please Implement this method")
+
+ def __repr__(self):
+ return self.name
+
+
+class ReadCommittedCompiler(IsolationCompiler):
+ name = 'Read committed'
+
+ def begin(self):
+ return 'BEGIN'
+
+
+class RepeatableReadCompiler(IsolationCompiler):
+ name = 'Repeatable read'
+
+ def begin(self):
+ return 'BEGIN ISOLATION LEVEL REPEATABLE READ'
+
+
+class SerializableCompiler(IsolationCompiler):
+ name = 'Serializable'
+
+ def begin(self):
+ query = 'BEGIN ISOLATION LEVEL SERIALIZABLE'
+
+ if self._readonly:
+ query += ' READ ONLY'
+
+ if self._deferrable:
+ query += ' DEFERRABLE'
+
+ return query
+
+
+class IsolationLevel(enum.Enum):
+ serializable = SerializableCompiler
+ repeatable_read = RepeatableReadCompiler
+ read_committed = ReadCommittedCompiler
+
+ def __call__(self, readonly, deferrable):
+ return self.value(readonly, deferrable)
+
+
+class Transaction:
+ __slots__ = ('_cur', '_is_begin', '_isolation', '_unique_id')
+
+ def __init__(self, cur, isolation_level,
+ readonly=False, deferrable=False):
+ self._cur = cur
+ self._is_begin = False
+ self._unique_id = None
+ self._isolation = isolation_level(readonly, deferrable)
+
+ @property
+ def is_begin(self):
+ return self._is_begin
+
+ @asyncio.coroutine
+ def begin(self):
+ if self._is_begin:
+ raise psycopg2.ProgrammingError(
+ 'You are trying to open a new transaction, use the save point')
+ self._is_begin = True
+ yield from self._cur.execute(self._isolation.begin())
+ return self
+
+ @asyncio.coroutine
+ def commit(self):
+ self._check_commit_rollback()
+ yield from self._cur.execute(self._isolation.commit())
+ self._is_begin = False
+
+ @asyncio.coroutine
+ def rollback(self):
+ self._check_commit_rollback()
+ yield from self._cur.execute(self._isolation.rollback())
+ self._is_begin = False
+
+ @asyncio.coroutine
+ def rollback_savepoint(self):
+ self._check_release_rollback()
+ yield from self._cur.execute(
+ self._isolation.rollback_savepoint(self._unique_id))
+ self._unique_id = None
+
+ @asyncio.coroutine
+ def release_savepoint(self):
+ self._check_release_rollback()
+ yield from self._cur.execute(
+ self._isolation.release_savepoint(self._unique_id))
+ self._unique_id = None
+
+ @asyncio.coroutine
+ def savepoint(self):
+ self._check_commit_rollback()
+ if self._unique_id is not None:
+ raise psycopg2.ProgrammingError('You do not shut down savepoint')
+
+ self._unique_id = 's{}'.format(uuid.uuid1().hex)
+ yield from self._cur.execute(
+ self._isolation.savepoint(self._unique_id))
+
+ return self
+
+ def point(self):
+ return _TransactionPointContextManager(self.savepoint())
+
+ def _check_commit_rollback(self):
+ if not self._is_begin:
+ raise psycopg2.ProgrammingError('You are trying to commit '
+ 'the transaction does not open')
+
+ def _check_release_rollback(self):
+ self._check_commit_rollback()
+ if self._unique_id is None:
+ raise psycopg2.ProgrammingError('You do not start savepoint')
+
+ def __repr__(self):
+ return "<{} transaction={} id={:#x}>".format(
+ self.__class__.__name__,
+ self._isolation,
+ id(self)
+ )
+
+ def __del__(self):
+ if self._is_begin:
+ warnings.warn(
+ "You have not closed transaction {!r}".format(self),
+ ResourceWarning)
+
+ if self._unique_id is not None:
+ warnings.warn(
+ "You have not closed savepoint {!r}".format(self),
+ ResourceWarning)
+
+ if PY_35:
+ @asyncio.coroutine
+ def __aenter__(self):
+ return (yield from self.begin())
+
+ @asyncio.coroutine
+ def __aexit__(self, exc_type, exc, tb):
+ if exc_type is not None:
+ yield from self.rollback()
+ else:
+ yield from self.commit()
diff --git a/aiopg/utils.py b/aiopg/utils.py
index 84a768d..99016d9 100644
--- a/aiopg/utils.py
+++ b/aiopg/utils.py
@@ -1,17 +1,16 @@
import asyncio
import sys
-
PY_35 = sys.version_info >= (3, 5)
PY_352 = sys.version_info >= (3, 5, 2)
if PY_35:
from collections.abc import Coroutine
+
base = Coroutine
else:
base = object
-
try:
ensure_future = asyncio.ensure_future
except AttributeError:
@@ -26,7 +25,6 @@ def create_future(loop):
class _ContextManager(base):
-
__slots__ = ('_coro', '_obj')
def __init__(self, coro):
@@ -84,7 +82,6 @@ class _ContextManager(base):
class _SAConnectionContextManager(_ContextManager):
-
if PY_35: # pragma: no branch
if PY_352:
def __aiter__(self):
@@ -97,7 +94,6 @@ class _SAConnectionContextManager(_ContextManager):
class _PoolContextManager(_ContextManager):
-
if PY_35:
@asyncio.coroutine
def __aexit__(self, exc_type, exc, tb):
@@ -106,8 +102,33 @@ class _PoolContextManager(_ContextManager):
self._obj = None
-class _TransactionContextManager(_ContextManager):
+class _TransactionPointContextManager(_ContextManager):
+ if PY_35:
+
+ @asyncio.coroutine
+ def __aexit__(self, exc_type, exc_val, exc_tb):
+ if exc_type is not None:
+ yield from self._obj.rollback_savepoint()
+ else:
+ yield from self._obj.release_savepoint()
+
+ self._obj = None
+
+class _TransactionBeginContextManager(_ContextManager):
+ if PY_35:
+
+ @asyncio.coroutine
+ def __aexit__(self, exc_type, exc_val, exc_tb):
+ if exc_type is not None:
+ yield from self._obj.rollback()
+ else:
+ yield from self._obj.commit()
+
+ self._obj = None
+
+
+class _TransactionContextManager(_ContextManager):
if PY_35:
@asyncio.coroutine
@@ -121,7 +142,6 @@ class _TransactionContextManager(_ContextManager):
class _PoolAcquireContextManager(_ContextManager):
-
__slots__ = ('_coro', '_conn', '_pool')
def __init__(self, coro, pool):
@@ -228,6 +248,7 @@ class _PoolCursorContextManager:
if not PY_35:
try:
from asyncio import coroutines
+
coroutines._COROUTINE_TYPES += (_ContextManager,)
except:
pass
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/aiopg.git
More information about the Python-modules-commits
mailing list