[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