[Python-modules-commits] [aioredis] 01/03: Import aioredis_0.2.6.orig.tar.gz

Piotr Ożarowski piotr at moszumanska.debian.org
Thu Apr 14 18:56:40 UTC 2016


This is an automated email from the git hooks/post-receive script.

piotr pushed a commit to branch master
in repository aioredis.

commit 85fc2e91b133f1849faf4fadbdcd95d1a9287f56
Author: Piotr Ożarowski <piotr at debian.org>
Date:   Thu Apr 14 20:52:48 2016 +0200

    Import aioredis_0.2.6.orig.tar.gz
---
 CHANGES.txt                      | 23 ++++++++++++++
 PKG-INFO                         | 26 +++++++++++++++-
 README.rst                       |  1 +
 aioredis.egg-info/PKG-INFO       | 26 +++++++++++++++-
 aioredis.egg-info/requires.txt   |  2 +-
 aioredis/__init__.py             |  2 +-
 aioredis/commands/__init__.py    |  7 +++--
 aioredis/commands/server.py      | 65 +++++++++++++++++++++++++++++++++++-----
 aioredis/commands/transaction.py | 45 ++++++++++++++--------------
 aioredis/connection.py           | 47 ++++++++++++++++-------------
 aioredis/pool.py                 |  8 +++--
 aioredis/util.py                 | 20 +++++++++++++
 setup.cfg                        |  2 +-
 13 files changed, 212 insertions(+), 62 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index c703b17..ac45c9f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,29 @@
 Changes
 -------
 
+0.2.6 (2016-03-30)
+^^^^^^^^^^^^^^^^^^
+
+* Fixed Multi/Exec transactions cancellation issue
+  (see `#110 <https://github.com/aio-libs/aioredis/issues/110>`_
+  and `#114 <https://github.com/aio-libs/aioredis/issues/114>`_);
+
+* Fixed Pub/Sub subscribe concurrency issue
+  (see `#113 <https://github.com/aio-libs/aioredis/issues/113>`_
+  and `#115 <https://github.com/aio-libs/aioredis/issues/115>`_);
+
+* Add SSL/TLS support
+  (see  `#116 <https://github.com/aio-libs/aioredis/issues/116>`_);
+
+* ``aioredis.ConnectionClosedError`` raised in ``execute_pubsub`` as well
+  (see `#108 <https://github.com/aio-libs/aioredis/issues/108>`_);
+
+* ``Redis.slaveof()`` method signature changed: now to disable
+  replication one should call ``redis.slaveof(None)`` instead of ``redis.slaveof()``;
+
+* More tests added;
+
+
 0.2.5 (2016-03-02)
 ^^^^^^^^^^^^^^^^^^
 
diff --git a/PKG-INFO b/PKG-INFO
index ea61354..ab189d1 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: aioredis
-Version: 0.2.5
+Version: 0.2.6
 Summary: asyncio (PEP 3156) Redis support
 Home-page: https://github.com/aio-libs/aioredis
 Author: Alexey Popravka
@@ -28,6 +28,7 @@ Description: aioredis
         Connections Pool                    Yes
         Pipelining support                  Yes
         Pub/Sub support                     Yes
+        SSL/TLS support                     Yes
         Redis Cluster support               WIP
         Trollius (python 2.7)               No
         Tested python versions              `3.3, 3.4, 3.5`_
@@ -138,6 +139,29 @@ Description: aioredis
         Changes
         -------
         
+        0.2.6 (2016-03-30)
+        ^^^^^^^^^^^^^^^^^^
+        
+        * Fixed Multi/Exec transactions cancellation issue
+          (see `#110 <https://github.com/aio-libs/aioredis/issues/110>`_
+          and `#114 <https://github.com/aio-libs/aioredis/issues/114>`_);
+        
+        * Fixed Pub/Sub subscribe concurrency issue
+          (see `#113 <https://github.com/aio-libs/aioredis/issues/113>`_
+          and `#115 <https://github.com/aio-libs/aioredis/issues/115>`_);
+        
+        * Add SSL/TLS support
+          (see  `#116 <https://github.com/aio-libs/aioredis/issues/116>`_);
+        
+        * ``aioredis.ConnectionClosedError`` raised in ``execute_pubsub`` as well
+          (see `#108 <https://github.com/aio-libs/aioredis/issues/108>`_);
+        
+        * ``Redis.slaveof()`` method signature changed: now to disable
+          replication one should call ``redis.slaveof(None)`` instead of ``redis.slaveof()``;
+        
+        * More tests added;
+        
+        
         0.2.5 (2016-03-02)
         ^^^^^^^^^^^^^^^^^^
         
diff --git a/README.rst b/README.rst
index c1f01a2..f77a5c0 100644
--- a/README.rst
+++ b/README.rst
@@ -20,6 +20,7 @@ Low-level & High-level APIs         Yes
 Connections Pool                    Yes
 Pipelining support                  Yes
 Pub/Sub support                     Yes
+SSL/TLS support                     Yes
 Redis Cluster support               WIP
 Trollius (python 2.7)               No
 Tested python versions              `3.3, 3.4, 3.5`_
diff --git a/aioredis.egg-info/PKG-INFO b/aioredis.egg-info/PKG-INFO
index ea61354..ab189d1 100644
--- a/aioredis.egg-info/PKG-INFO
+++ b/aioredis.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: aioredis
-Version: 0.2.5
+Version: 0.2.6
 Summary: asyncio (PEP 3156) Redis support
 Home-page: https://github.com/aio-libs/aioredis
 Author: Alexey Popravka
@@ -28,6 +28,7 @@ Description: aioredis
         Connections Pool                    Yes
         Pipelining support                  Yes
         Pub/Sub support                     Yes
+        SSL/TLS support                     Yes
         Redis Cluster support               WIP
         Trollius (python 2.7)               No
         Tested python versions              `3.3, 3.4, 3.5`_
@@ -138,6 +139,29 @@ Description: aioredis
         Changes
         -------
         
+        0.2.6 (2016-03-30)
+        ^^^^^^^^^^^^^^^^^^
+        
+        * Fixed Multi/Exec transactions cancellation issue
+          (see `#110 <https://github.com/aio-libs/aioredis/issues/110>`_
+          and `#114 <https://github.com/aio-libs/aioredis/issues/114>`_);
+        
+        * Fixed Pub/Sub subscribe concurrency issue
+          (see `#113 <https://github.com/aio-libs/aioredis/issues/113>`_
+          and `#115 <https://github.com/aio-libs/aioredis/issues/115>`_);
+        
+        * Add SSL/TLS support
+          (see  `#116 <https://github.com/aio-libs/aioredis/issues/116>`_);
+        
+        * ``aioredis.ConnectionClosedError`` raised in ``execute_pubsub`` as well
+          (see `#108 <https://github.com/aio-libs/aioredis/issues/108>`_);
+        
+        * ``Redis.slaveof()`` method signature changed: now to disable
+          replication one should call ``redis.slaveof(None)`` instead of ``redis.slaveof()``;
+        
+        * More tests added;
+        
+        
         0.2.5 (2016-03-02)
         ^^^^^^^^^^^^^^^^^^
         
diff --git a/aioredis.egg-info/requires.txt b/aioredis.egg-info/requires.txt
index ebc4fdc..01e7805 100644
--- a/aioredis.egg-info/requires.txt
+++ b/aioredis.egg-info/requires.txt
@@ -1 +1 @@
-hiredis
\ No newline at end of file
+hiredis
diff --git a/aioredis/__init__.py b/aioredis/__init__.py
index b7e7d09..be5fd0e 100644
--- a/aioredis/__init__.py
+++ b/aioredis/__init__.py
@@ -12,7 +12,7 @@ from .errors import (
     )
 
 
-__version__ = '0.2.5'
+__version__ = '0.2.6'
 
 # make pyflakes happy
 (create_connection, RedisConnection,
diff --git a/aioredis/commands/__init__.py b/aioredis/commands/__init__.py
index 170be91..abff333 100644
--- a/aioredis/commands/__init__.py
+++ b/aioredis/commands/__init__.py
@@ -126,7 +126,7 @@ class Redis(GenericCommandsMixin, StringCommandsMixin,
 
 
 @asyncio.coroutine
-def create_redis(address, *, db=None, password=None,
+def create_redis(address, *, db=None, password=None, ssl=None,
                  encoding=None, commands_factory=Redis,
                  loop=None):
     """Creates high-level Redis interface.
@@ -135,13 +135,14 @@ def create_redis(address, *, db=None, password=None,
     """
     conn = yield from create_connection(address, db=db,
                                         password=password,
+                                        ssl=ssl,
                                         encoding=encoding,
                                         loop=loop)
     return commands_factory(conn)
 
 
 @asyncio.coroutine
-def create_reconnecting_redis(address, *, db=None, password=None,
+def create_reconnecting_redis(address, *, db=None, password=None, ssl=None,
                               encoding=None, commands_factory=Redis,
                               loop=None):
     """Creates high-level Redis interface.
@@ -152,7 +153,7 @@ def create_reconnecting_redis(address, *, db=None, password=None,
     # a first connection in it, or just resolve DNS. So let's keep it
     # coroutine for forward compatibility
     conn = AutoConnector(address,
-                         db=db, password=password,
+                         db=db, password=password, ssl=ssl,
                          encoding=encoding, loop=loop)
     return commands_factory(conn)
 
diff --git a/aioredis/commands/server.py b/aioredis/commands/server.py
index 25eaf86..76e68f5 100644
--- a/aioredis/commands/server.py
+++ b/aioredis/commands/server.py
@@ -1,6 +1,7 @@
 from collections import namedtuple
 
 from aioredis.util import wait_ok, wait_convert, wait_make_dict, _NOTSET
+from aioredis.log import logger
 
 
 class ServerCommandsMixin:
@@ -30,7 +31,10 @@ class ServerCommandsMixin:
         raise NotImplementedError
 
     def client_list(self):
-        """Get the list of client connections."""
+        """Get the list of client connections.
+
+        Returns list of ClientInfo named tuples.
+        """
         fut = self._conn.execute(b'CLIENT', b'LIST', encoding='utf-8')
         return wait_convert(fut, to_tuples)
 
@@ -56,11 +60,17 @@ class ServerCommandsMixin:
         fut = self._conn.execute(b'CLIENT', b'SETNAME', name)
         return wait_ok(fut)
 
-    def config_get(self, parameter):
-        """Get the value of a configuration parameter."""
+    def config_get(self, parameter='*'):
+        """Get the value of a configuration parameter(s).
+
+        If called without argument will return all parameters.
+
+        :raises TypeError: if parameter is not string
+        """
         if not isinstance(parameter, str):
             raise TypeError("parameter must be str")
-        fut = self._conn.execute(b'CONFIG', b'GET', parameter)
+        fut = self._conn.execute(b'CONFIG', b'GET', parameter,
+                                 encoding='utf-8')
         return wait_make_dict(fut)
 
     def config_rewrite(self):
@@ -122,8 +132,13 @@ class ServerCommandsMixin:
         raise NotImplementedError
 
     def role(self):
-        """Return the role of the instance in the context of replication."""
-        return self._conn.execute(b'ROLE')
+        """Return the role of the server instance.
+
+        Returns named tuples describing role of the instance.
+        For fields information see http://redis.io/commands/role#output-format
+        """
+        fut = self._conn.execute(b'ROLE', encoding='utf-8')
+        return wait_convert(fut, parse_role)
 
     def save(self):
         """Synchronously save the dataset to disk."""
@@ -140,12 +155,21 @@ class ServerCommandsMixin:
         else:
             return self._conn.execute(b'SHUTDOWN')
 
-    def slaveof(self, host=None, port=None):
+    def slaveof(self, host=_NOTSET, port=None):
         """Make the server a slave of another instance,
         or promote it as master.
 
-        Calling slaveof without arguments will send ``SLAVEOF NO ONE``.
+        Calling ``slaveof(None)`` will send ``SLAVEOF NO ONE``.
+
+        .. versionchanged:: v0.2.6
+           ``slaveof()`` form deprecated
+           in favour of explicit ``slaveof(None)``.
         """
+        if host is _NOTSET:
+            logger.warning("slaveof() form is deprecated!"
+                           " Use slaveof(None) to turn redis into a MASTER.")
+            host = None
+            # TODO: drop in 0.3.0
         if host is None and port is None:
             return self._conn.execute(b'SLAVEOF', b'NO', b'ONE')
         return self._conn.execute(b'SLAVEOF', host, port)
@@ -187,6 +211,7 @@ def to_tuples(value):
     line = next(lines)
     line = list(map(_split, line.split(' ')))
     ClientInfo = namedtuple('ClientInfo', ' '.join(k for k, v in line))
+    # TODO: parse flags and other known fields
     result = [ClientInfo(**dict(line))]
     for line in lines:
         result.append(ClientInfo(**dict(map(_split, line.split(' ')))))
@@ -205,3 +230,27 @@ def parse_info(info):
                 value = dict(map(lambda i: i.split('='), value.split(',')))
             tmp[key] = value
     return res
+
+
+# XXX: may change in future
+#      (may be hard to maintain for new/old redis versions)
+MasterInfo = namedtuple('MasterInfo', 'role replication_offset slaves')
+MasterSlaveInfo = namedtuple('MasterSlaveInfo', 'ip port ack_offset')
+
+SlaveInfo = namedtuple('SlaveInfo',
+                       'role master_ip master_port state received')
+
+SentinelInfo = namedtuple('SentinelInfo', 'masters')
+
+
+def parse_role(role):
+    type_ = role[0]
+    if type_ == 'master':
+        slaves = [MasterSlaveInfo(s[0], int(s[1]), int(s[2]))
+                  for s in role[2]]
+        return MasterInfo(role[0], int(role[1]), slaves)
+    elif type_ == 'slave':
+        return SlaveInfo(role[0], role[1], int(role[2]), role[3], int(role[4]))
+    elif type_ == 'sentinel':
+        return SentinelInfo(*role)
+    return role
diff --git a/aioredis/commands/transaction.py b/aioredis/commands/transaction.py
index 505b36b..f177401 100644
--- a/aioredis/commands/transaction.py
+++ b/aioredis/commands/transaction.py
@@ -199,10 +199,7 @@ class Pipeline:
         elif fut.exception():
             waiter.set_exception(fut.exception())
         else:
-            self._set_result(fut, waiter)
-
-    def _set_result(self, fut, waiter):
-        waiter.set_result(fut.result())
+            waiter.set_result(fut.result())
 
 
 class MultiExec(Pipeline):
@@ -249,15 +246,19 @@ class MultiExec(Pipeline):
         multi = conn.execute('MULTI')
         coros = list(self._send_pipeline(conn))
         exec_ = conn.execute('EXEC')
+        gather = asyncio.gather(multi, *coros, loop=self._loop,
+                                return_exceptions=True)
         try:
-            yield from asyncio.gather(multi, *coros,
-                                      loop=self._loop)
+            yield from asyncio.shield(gather, loop=self._loop)
         except asyncio.CancelledError:
-            pass
+            yield from gather
         finally:
-            if self._conn.closed:
+            if conn.closed:
                 for fut in waiters:
                     fut.cancel()
+                for fut in self._results:
+                    if not fut.done():
+                        fut.cancel()
             else:
                 try:
                     results = yield from exec_
@@ -265,10 +266,10 @@ class MultiExec(Pipeline):
                     for fut in waiters:
                         fut.set_exception(err)
                 else:
-                    assert len(results) == len(waiters), (results, waiters)
+                    assert len(results) == len(waiters), (
+                        "Results does not match waiters", results, waiters)
                     self._resolve_waiters(results, return_exceptions)
-                    return (yield from self._gather_result(
-                        return_exceptions))
+            return (yield from self._gather_result(return_exceptions))
 
     def _resolve_waiters(self, results, return_exceptions):
         errors = []
@@ -281,15 +282,13 @@ class MultiExec(Pipeline):
         if errors and not return_exceptions:
             raise MultiExecError(errors)
 
-    def _set_result(self, fut, waiter):
-        # fut is done and must be 'QUEUED'
-        if fut in self._waiters:
-            self._waiters.remove(fut)
-            waiter.set_result(fut.result())
-        elif fut.result() not in {b'QUEUED', 'QUEUED'}:
-            waiter.set_result(fut.result())
-        else:
-            fut = asyncio.Future(loop=self._loop)
-            self._waiters.append(fut)
-            fut.add_done_callback(
-                functools.partial(self._check_result, waiter=waiter))
+    def _check_result(self, fut, waiter):
+        assert waiter not in self._waiters, (fut, waiter, self._waiters)
+        assert not waiter.done(), waiter
+        if fut.cancelled():     # yield from gather was cancelled
+            waiter.cancel()
+        elif fut.exception():   # server replied with error
+            waiter.set_exception(fut.exception())
+        elif fut.result() in {b'QUEUED', 'QUEUED'}:
+            # got result, it should be QUEUED
+            self._waiters.append(waiter)
diff --git a/aioredis/connection.py b/aioredis/connection.py
index 05bc266..d5abd29 100644
--- a/aioredis/connection.py
+++ b/aioredis/connection.py
@@ -7,7 +7,10 @@ from collections import deque
 
 from .util import (
     encode_command,
-    wait_ok, _NOTSET,
+    wait_ok,
+    _NOTSET,
+    _set_result,
+    _set_exception,
     coerced_keys_dict,
     Channel,
     decode,
@@ -35,7 +38,7 @@ _PUBSUB_COMMANDS = (
 
 
 @asyncio.coroutine
-def create_connection(address, *, db=None, password=None,
+def create_connection(address, *, db=None, password=None, ssl=None,
                       encoding=None, loop=None):
     """Creates redis connection.
 
@@ -45,6 +48,9 @@ def create_connection(address, *, db=None, password=None,
     * when address is a str it represents unix domain socket path.
     (no other address formats supported)
 
+    SSL argument is passed through to asyncio.create_connection.
+    By default SSL/TLS is not used.
+
     Encoding argument can be used to decode byte-replies to strings.
     By default no decoding is done.
 
@@ -58,14 +64,14 @@ def create_connection(address, *, db=None, password=None,
         host, port = address
         logger.debug("Creating tcp connection to %r", address)
         reader, writer = yield from asyncio.open_connection(
-            host, port, loop=loop)
+            host, port, ssl=ssl, loop=loop)
         sock = writer.transport.get_extra_info('socket')
         if sock is not None:
             sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
     else:
         logger.debug("Creating unix connection to %r", address)
         reader, writer = yield from asyncio.open_unix_connection(
-            address, loop=loop)
+            address, ssl=ssl, loop=loop)
     conn = RedisConnection(reader, writer, encoding=encoding, loop=loop)
 
     try:
@@ -146,13 +152,8 @@ class RedisConnection:
     def _process_data(self, obj):
         """Processes command results."""
         waiter, encoding, cb = self._waiters.popleft()
-        if waiter.done():
-            logger.debug("Waiter future is already done %r", waiter)
-            assert waiter.cancelled(), (
-                "waiting future is in wrong state", waiter, obj)
-            return
         if isinstance(obj, RedisError):
-            waiter.set_exception(obj)
+            _set_exception(waiter, obj)
             if self._in_transaction is not None:
                 self._transaction_error = obj
         else:
@@ -160,25 +161,24 @@ class RedisConnection:
                 try:
                     obj = decode(obj, encoding)
                 except Exception as exc:
-                    waiter.set_exception(exc)
+                    _set_exception(waiter, exc)
                     return
             if cb is not None:
                 try:
                     obj = cb(obj)
                 except Exception as exc:
-                    waiter.set_exception(exc)
+                    _set_exception(waiter, exc)
                     return
-            waiter.set_result(obj)
+            _set_result(waiter, obj)
             if self._in_transaction is not None:
                 self._in_transaction.append((encoding, cb))
 
     def _process_pubsub(self, obj, *, _process_waiters=True):
         """Processes pubsub messages."""
         kind, *pattern, chan, data = obj
-        if _process_waiters and self._in_pubsub and self._waiters:
-            self._process_data(obj)
-
         if kind in (b'subscribe', b'unsubscribe'):
+            if _process_waiters and self._in_pubsub and self._waiters:
+                self._process_data(obj)
             if kind == b'subscribe' and chan not in self._pubsub_channels:
                 self._pubsub_channels[chan] = Channel(chan, is_pattern=False,
                                                       loop=self._loop)
@@ -188,6 +188,8 @@ class RedisConnection:
                     ch.close()
             self._in_pubsub = data
         elif kind in (b'psubscribe', b'punsubscribe'):
+            if _process_waiters and self._in_pubsub and self._waiters:
+                self._process_data(obj)
             if kind == b'psubscribe' and chan not in self._pubsub_patterns:
                 self._pubsub_patterns[chan] = Channel(chan, is_pattern=True,
                                                       loop=self._loop)
@@ -253,6 +255,8 @@ class RedisConnection:
         command = command.upper().strip()
         assert command in _PUBSUB_COMMANDS, (
             "Pub/Sub command expected", command)
+        if self._reader is None or self._reader.at_eof():
+            raise ConnectionClosedError("Connection closed or corrupted")
         if None in set(channels):
             raise TypeError("args must not contain None")
         if not len(channels):
@@ -330,24 +334,27 @@ class RedisConnection:
         return wait_ok(fut)
 
     def _set_db(self, ok, args):
-        assert ok in {b'OK', 'OK'}, ok
+        assert ok in {b'OK', 'OK'}, ("Unexpected result of SELECT", ok)
         self._db = args[0]
         return ok
 
     def _start_transaction(self, ok):
-        assert self._in_transaction is None
+        assert self._in_transaction is None, (
+            "Connection is already in transaction", self._in_transaction)
         self._in_transaction = deque()
         self._transaction_error = None
         return ok
 
     def _end_transaction(self, obj, discard):
-        assert self._in_transaction is not None
+        assert self._in_transaction is not None, (
+            "Connection is not in transaction", obj)
         self._transaction_error = None
         recall, self._in_transaction = self._in_transaction, None
         recall.popleft()  # ignore first (its _start_transaction)
         if discard:
             return obj
-        assert len(obj) == len(recall), (obj, recall)
+        assert len(obj) == len(recall), (
+            "Wrong number of result items in mutli-exec", obj, recall)
         res = []
         for o, (encoding, cb) in zip(obj, recall):
             if not isinstance(o, RedisError):
diff --git a/aioredis/pool.py b/aioredis/pool.py
index 75315f0..59ec14f 100644
--- a/aioredis/pool.py
+++ b/aioredis/pool.py
@@ -11,7 +11,7 @@ PY_35 = sys.version_info >= (3, 5)
 
 
 @asyncio.coroutine
-def create_pool(address, *, db=0, password=None, encoding=None,
+def create_pool(address, *, db=0, password=None, ssl=None, encoding=None,
                 minsize=10, maxsize=10, commands_factory=Redis, loop=None):
     """Creates Redis Pool.
 
@@ -27,7 +27,7 @@ def create_pool(address, *, db=0, password=None, encoding=None,
     pool = RedisPool(address, db, password, encoding,
                      minsize=minsize, maxsize=maxsize,
                      commands_factory=commands_factory,
-                     loop=loop)
+                     ssl=ssl, loop=loop)
     yield from pool._fill_free(override_min=False)
     return pool
 
@@ -37,12 +37,13 @@ class RedisPool:
     """
 
     def __init__(self, address, db=0, password=None, encoding=None,
-                 *, minsize, maxsize, commands_factory, loop=None):
+                 *, minsize, maxsize, commands_factory, ssl=None, loop=None):
         if loop is None:
             loop = asyncio.get_event_loop()
         self._address = address
         self._db = db
         self._password = password
+        self._ssl = ssl
         self._encoding = encoding
         self._minsize = minsize
         self._factory = commands_factory
@@ -193,6 +194,7 @@ class RedisPool:
         return create_redis(self._address,
                             db=self._db,
                             password=self._password,
+                            ssl=self._ssl,
                             encoding=self._encoding,
                             commands_factory=self._factory,
                             loop=self._loop)
diff --git a/aioredis/util.py b/aioredis/util.py
index 308affc..0de1407 100644
--- a/aioredis/util.py
+++ b/aioredis/util.py
@@ -3,11 +3,13 @@ import json
 import sys
 
 from .errors import ChannelClosedError
+from .log import logger
 
 PY_35 = sys.version_info >= (3, 5)
 
 _NOTSET = object()
 
+
 # NOTE: never put here anything else;
 #       just this basic types
 _converters = {
@@ -283,6 +285,24 @@ if PY_35:
             return msg
 
 
+def _set_result(fut, result):
+    if fut.done():
+        logger.debug("Waiter future is already done %r", fut)
+        assert fut.cancelled(), (
+            "waiting future is in wrong state", fut, result)
+    else:
+        fut.set_result(result)
+
+
+def _set_exception(fut, exception):
+    if fut.done():
+        logger.debug("Waiter future is already done %r", fut)
+        assert fut.cancelled(), (
+            "waiting future is in wrong state", fut, exception)
+    else:
+        fut.set_exception(exception)
+
+
 if hasattr(asyncio, 'ensure_future'):
     async_task = asyncio.ensure_future
 else:
diff --git a/setup.cfg b/setup.cfg
index 6bc2ff3..861a9f5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [egg_info]
-tag_date = 0
 tag_build = 
+tag_date = 0
 tag_svn_revision = 0
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/aioredis.git



More information about the Python-modules-commits mailing list