Hello community, here is the log from the commit of package python-txaio for openSUSE:Leap:15.2 checked in at 2020-03-02 13:24:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/python-txaio (Old) and /work/SRC/openSUSE:Leap:15.2/.python-txaio.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-txaio" Mon Mar 2 13:24:19 2020 rev:11 rq:777241 version:20.1.1 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/python-txaio/python-txaio.changes 2020-01-15 15:53:56.779615201 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.python-txaio.new.26092/python-txaio.changes 2020-03-02 13:24:20.134515060 +0100 @@ -1,0 +2,41 @@ +Wed Feb 5 13:11:01 UTC 2020 - Ondřej Súkup <[email protected]> + +- update to 20.1.1 +- drop pytest4.patch + * new: moved time_ns and perf_counter_ns helper functions here + * drop support for python 3.4 and older + +------------------------------------------------------------------- +Fri Sep 13 11:40:25 UTC 2019 - Tomáš Chvátal <[email protected]> + +- Add patch to build with newer pytest releases: + * pytest4.patch + +------------------------------------------------------------------- +Thu Sep 5 13:40:10 UTC 2019 - Todd R <[email protected]> + +- Set pytest maximum version. + +------------------------------------------------------------------- +Tue Mar 19 12:35:11 UTC 2019 - John Vandenberg <[email protected]> + +- Fix invocation of test suite, previously silently not running +- Add missing runtime dependencies +- Update to v18.8.1 + * add API to support cancellation; this means passing a 1-argument + callable to ``create_future`` and ``txaio.cancel`` to actually + cancel a future + * support Python 3.7 (CI / testing added) +- from v18.7.1 + * move to calver + * deprecate Python 3.3 support and CI testing +- from v2.10.0 + * the asyncio version of ``make_logger`` now deduces a proper + namespace instead of using the root + +------------------------------------------------------------------- +Tue Dec 4 12:55:27 UTC 2018 - Matej Cepl <[email protected]> + +- Remove superfluous devel dependency for noarch package + +------------------------------------------------------------------- Old: ---- txaio-2.9.0.tar.gz New: ---- txaio-20.1.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-txaio.spec ++++++ --- /var/tmp/diff_new_pack.u5yAfR/_old 2020-03-02 13:24:20.482515752 +0100 +++ /var/tmp/diff_new_pack.u5yAfR/_new 2020-03-02 13:24:20.482515752 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-txaio # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,29 +12,34 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# +%define skip_python2 1 %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-txaio -Version: 2.9.0 +Version: 20.1.1 Release: 0 -License: MIT Summary: WebSocket and WAMP in Python for Twisted and asyncio -Url: http://crossbar.io/autobahn +License: MIT Group: Development/Languages/Python +URL: https://github.com/crossbario/txaio Source: https://files.pythonhosted.org/packages/source/t/txaio/txaio-%{version}.tar.gz -BuildRequires: python-rpm-macros -BuildRequires: %{python_module devel} BuildRequires: %{python_module setuptools} BuildRequires: fdupes +BuildRequires: python-rpm-macros +BuildRequires: python3-testsuite +Requires: python-six +Recommends: python-Twisted >= 12.1.0 +Recommends: python-zope.interface >= 3.6 +BuildArch: noarch # SECTION test requirements -BuildRequires: %{python_module Twisted} +BuildRequires: %{python_module Twisted >= 12.1.0} +BuildRequires: %{python_module mock} +BuildRequires: %{python_module pytest} BuildRequires: %{python_module six} # /SECTION -Requires: python-six -BuildArch: noarch - %python_subpackages %description @@ -52,10 +57,10 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -%python_exec setup.py test +%pytest -k 'not test_sdist' %files %{python_files} -%doc LICENSE +%license LICENSE %{python_sitelib}/* %changelog ++++++ txaio-2.9.0.tar.gz -> txaio-20.1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/PKG-INFO new/txaio-20.1.1/PKG-INFO --- old/txaio-2.9.0/PKG-INFO 2018-03-02 08:47:02.000000000 +0100 +++ new/txaio-20.1.1/PKG-INFO 2020-01-21 10:09:51.737460900 +0100 @@ -1,12 +1,11 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: txaio -Version: 2.9.0 +Version: 20.1.1 Summary: Compatibility API between asyncio/Twisted/Trollius Home-page: https://github.com/crossbario/txaio Author: Crossbar.io Technologies GmbH Author-email: [email protected] License: MIT License -Description-Content-Type: UNKNOWN Description: txaio ===== @@ -31,20 +30,12 @@ Platform support ---------------- - **txaio** runs on CPython 2.7/3.3+ and PyPy 2/3, on top of Twisted or asyncio. Specifically, **txaio** is tested on the following platforms: + **txaio** runs on CPython 3.5+ and PyPy 3, on top of *Twisted* or *asyncio*. Specifically, **txaio** is tested on the following platforms: - **Python 2:** + * CPython 3.5, 3.7 and 3.8 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) + * PyPy 3 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) - * CPython 2.7 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 - * PyPy 2 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 - - **Python 3:** - - * CPython 3.3 on Twisted 15.4, 16.5, trunk and on Trollius 2.0 - * CPython 3.4 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) - * CPython 3.5 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) - * CPython 3.6 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) - * PyPy 3 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) + > Note: txaio up to version 18.8.1 also supported Python 2.7 and Python 3.4. Beginning with release v20.1.1, txaio only supports Python 3.5+. How it works @@ -99,14 +90,17 @@ Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.5 +Provides-Extra: twisted +Provides-Extra: all +Provides-Extra: dev +Provides-Extra: asyncio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/README.rst new/txaio-20.1.1/README.rst --- old/txaio-2.9.0/README.rst 2017-09-23 21:50:59.000000000 +0200 +++ new/txaio-20.1.1/README.rst 2020-01-21 10:06:33.000000000 +0100 @@ -22,20 +22,12 @@ Platform support ---------------- -**txaio** runs on CPython 2.7/3.3+ and PyPy 2/3, on top of Twisted or asyncio. Specifically, **txaio** is tested on the following platforms: +**txaio** runs on CPython 3.5+ and PyPy 3, on top of *Twisted* or *asyncio*. Specifically, **txaio** is tested on the following platforms: -**Python 2:** +* CPython 3.5, 3.7 and 3.8 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) +* PyPy 3 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) -* CPython 2.7 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 -* PyPy 2 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 - -**Python 3:** - -* CPython 3.3 on Twisted 15.4, 16.5, trunk and on Trollius 2.0 -* CPython 3.4 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) -* CPython 3.5 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) -* CPython 3.6 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) -* PyPy 3 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) +> Note: txaio up to version 18.8.1 also supported Python 2.7 and Python 3.4. Beginning with release v20.1.1, txaio only supports Python 3.5+. How it works diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/docs/api.rst new/txaio-20.1.1/docs/api.rst --- old/txaio-2.9.0/docs/api.rst 2016-11-06 20:03:50.000000000 +0100 +++ new/txaio-20.1.1/docs/api.rst 2020-01-21 00:10:08.000000000 +0100 @@ -71,19 +71,23 @@ Select the Twisted framework (will fail if Twisted is not installed). -.. py:function:: create_future(value=None, error=None) +.. py:function:: create_future(result=None, error=None, canceller=None) Create and return a new framework-specific future object. On asyncio this returns a `Future`_, on Twisted it returns a `Deferred`_. - :param value: if not ``None``, the future is already fulfilled, + :param result: if not ``None``, the future is already fulfilled, with the given result. :param error: if not ``None`` then the future is already failed, with the given error. :type error: class:`IFailedFuture` or Exception + :param canceller: a single-argument callable which is invoked if + this future is cancelled (the single argument is the future + object which has been cancelled) + :raises ValueError: if both ``value`` and ``error`` are provided. :return: under Twisted a `Deferred`_, under asyncio a `Future`_ @@ -129,6 +133,16 @@ :type error: :class:`IFailedFuture` or :class:`Exception` +.. py:function:: cancel(future) + + Cancel the given future. If a ``canceller`` was registered, it is + invoked now. It is invalid to ``resolve`` or ``reject`` the future + after cancelling it. + + :param future: an unresolved `Deferred`_/`Future`_ as returned by + :meth:`create_future` + + .. py:function:: resolve(future, value) Resolve the given future with the provided value. This triggers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/docs/index.rst new/txaio-20.1.1/docs/index.rst --- old/txaio-2.9.0/docs/index.rst 2017-09-23 21:50:59.000000000 +0200 +++ new/txaio-20.1.1/docs/index.rst 2020-01-21 10:06:33.000000000 +0100 @@ -22,20 +22,12 @@ Platform support ---------------- -**txaio** runs on CPython 2.7/3.3+ and PyPy 2/3, on top of Twisted or asyncio. Specifically, **txaio** is tested on the following platforms: +**txaio** runs on CPython 3.5+ and PyPy 3, on top of *Twisted* or *asyncio*. Specifically, **txaio** is tested on the following platforms: -**Python 2:** +* CPython 3.5, 3.7 and 3.8 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) +* PyPy 3 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) -* CPython 2.7 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 -* PyPy 2 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 - -**Python 3:** - -* CPython 3.3 on Twisted 15.4, 16.5, trunk and on Trollius 2.0 -* CPython 3.4 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) -* CPython 3.5 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) -* CPython 3.6 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) -* PyPy 3 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) +> Note: txaio up to version 18.8.1 also supported Python 2.7 and Python 3.4. Beginning with release v20.1.1, txaio only supports Python 3.5+. How it works diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/docs/releases.rst new/txaio-20.1.1/docs/releases.rst --- old/txaio-2.9.0/docs/releases.rst 2018-03-02 08:07:17.000000000 +0100 +++ new/txaio-20.1.1/docs/releases.rst 2020-01-21 10:06:33.000000000 +0100 @@ -1,6 +1,37 @@ txio releases ============= +20.1.1 +------ + +- IMPORTANT: beginning release v20.1.1, we only support Python 3.5 or later +- new: moved ``time_ns`` and ``perf_counter_ns`` helper functions here + +18.8.1 +------ + +* IMPORTANT: release v18.8.1 is the last release supporting Python 2. We will support Python 3.5 and later beginning with release v20.1.1. +- add API to support cancellation; this means passing a 1-argument + callable to ``create_future`` and ``txaio.cancel`` to actually + cancel a future +- support Python 3.7 (CI / testing added) + + +18.7.1 +------ + +- move to calver +- deprecate Python 3.3 support and CI testing + + +2.10.0 +------ + +- the asyncio version of ``make_logger`` now deduces a proper + namespace instead of using the root (thanks `spr0cketeer + <https://github.com/spr0cketeer>`_) + + 2.9.0 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/setup.py new/txaio-20.1.1/setup.py --- old/txaio-2.9.0/setup.py 2017-09-04 14:14:03.000000000 +0200 +++ new/txaio-20.1.1/setup.py 2020-01-21 10:06:33.000000000 +0100 @@ -48,27 +48,14 @@ 'twisted>=12.1.0', # MIT ] -# asyncio dependencies +# asyncio dependencies: Python 3.5+ has asyncio builtin # -if PY3: - if PY33: - # "Tulip" - extras_require_asyncio = [ - "asyncio>=3.4.3" # Apache 2.0 - ] - else: - # Python 3.4+ has asyncio builtin - extras_require_asyncio = [] -else: - # backport of asyncio for Python 2 - extras_require_asyncio = [ - "trollius>=2.0", # Apache 2.0 - "futures>=3.0.3" # BSD license - ] +extras_require_asyncio = [] # development dependencies # extras_require_dev = [ + 'wheel', # MIT 'pytest>=2.6.4', # MIT 'pytest-cov>=1.8.1', # MIT 'pep8>=1.6.2', # MIT @@ -96,6 +83,7 @@ author_email='[email protected]', url='https://github.com/crossbario/txaio', platforms=('Any'), + python_requires='>=3.5', install_requires=[ 'six' ], @@ -128,13 +116,11 @@ "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/test/_asyncio_test_utils.py new/txaio-20.1.1/test/_asyncio_test_utils.py --- old/txaio-2.9.0/test/_asyncio_test_utils.py 1970-01-01 01:00:00.000000000 +0100 +++ new/txaio-20.1.1/test/_asyncio_test_utils.py 2020-01-21 00:10:08.000000000 +0100 @@ -0,0 +1,568 @@ +"""Utilities shared by tests.""" + +import collections +import contextlib +import io +import logging +import os +import re +import selectors +import socket +import socketserver +import sys +import tempfile +import threading +import time +import unittest +import weakref + +from unittest import mock + +from http.server import HTTPServer +from wsgiref.simple_server import WSGIRequestHandler, WSGIServer + +try: + import ssl +except ImportError: # pragma: no cover + ssl = None + +from asyncio import base_events +from asyncio import events +from asyncio import format_helpers +from asyncio import futures +from asyncio import tasks +from asyncio.log import logger +from test import support + + +def data_file(filename): + if hasattr(support, 'TEST_HOME_DIR'): + fullname = os.path.join(support.TEST_HOME_DIR, filename) + if os.path.isfile(fullname): + return fullname + fullname = os.path.join(os.path.dirname(__file__), filename) + if os.path.isfile(fullname): + return fullname + raise FileNotFoundError(filename) + + +ONLYCERT = data_file('ssl_cert.pem') +ONLYKEY = data_file('ssl_key.pem') +SIGNED_CERTFILE = data_file('keycert3.pem') +SIGNING_CA = data_file('pycacert.pem') +PEERCERT = { + 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), + 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',), + 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',), + 'issuer': ((('countryName', 'XY'),), + (('organizationName', 'Python Software Foundation CA'),), + (('commonName', 'our-ca-server'),)), + 'notAfter': 'Jul 7 14:23:16 2028 GMT', + 'notBefore': 'Aug 29 14:23:16 2018 GMT', + 'serialNumber': 'CB2D80995A69525C', + 'subject': ((('countryName', 'XY'),), + (('localityName', 'Castle Anthrax'),), + (('organizationName', 'Python Software Foundation'),), + (('commonName', 'localhost'),)), + 'subjectAltName': (('DNS', 'localhost'),), + 'version': 3 +} + + +def simple_server_sslcontext(): + server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + server_context.load_cert_chain(ONLYCERT, ONLYKEY) + server_context.check_hostname = False + server_context.verify_mode = ssl.CERT_NONE + return server_context + + +def simple_client_sslcontext(*, disable_verify=True): + client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_context.check_hostname = False + if disable_verify: + client_context.verify_mode = ssl.CERT_NONE + return client_context + + +def dummy_ssl_context(): + if ssl is None: + return None + else: + return ssl.SSLContext(ssl.PROTOCOL_TLS) + + +def run_briefly(loop): + async def once(): + pass + gen = once() + t = loop.create_task(gen) + # Don't log a warning if the task is not done after run_until_complete(). + # It occurs if the loop is stopped or if a task raises a BaseException. + t._log_destroy_pending = False + try: + loop.run_until_complete(t) + finally: + gen.close() + + +def run_until(loop, pred, timeout=30): + deadline = time.time() + timeout + while not pred(): + if timeout is not None: + timeout = deadline - time.time() + if timeout <= 0: + raise futures.TimeoutError() + loop.run_until_complete(tasks.sleep(0.001, loop=loop)) + + +def run_once(loop): + """Legacy API to run once through the event loop. + + This is the recommended pattern for test code. It will poll the + selector once and run all callbacks scheduled in response to I/O + events. + """ + loop.call_soon(loop.stop) + loop.run_forever() + + +class SilentWSGIRequestHandler(WSGIRequestHandler): + + def get_stderr(self): + return io.StringIO() + + def log_message(self, format, *args): + pass + + +class SilentWSGIServer(WSGIServer): + + request_timeout = 2 + + def get_request(self): + request, client_addr = super().get_request() + request.settimeout(self.request_timeout) + return request, client_addr + + def handle_error(self, request, client_address): + pass + + +class SSLWSGIServerMixin: + + def finish_request(self, request, client_address): + # The relative location of our test directory (which + # contains the ssl key and certificate files) differs + # between the stdlib and stand-alone asyncio. + # Prefer our own if we can find it. + here = os.path.join(os.path.dirname(__file__), '..', 'tests') + if not os.path.isdir(here): + here = os.path.join(os.path.dirname(os.__file__), + 'test', 'test_asyncio') + keyfile = os.path.join(here, 'ssl_key.pem') + certfile = os.path.join(here, 'ssl_cert.pem') + context = ssl.SSLContext() + context.load_cert_chain(certfile, keyfile) + + ssock = context.wrap_socket(request, server_side=True) + try: + self.RequestHandlerClass(ssock, client_address, self) + ssock.close() + except OSError: + # maybe socket has been closed by peer + pass + + +class SSLWSGIServer(SSLWSGIServerMixin, SilentWSGIServer): + pass + + +def _run_test_server(*, address, use_ssl=False, server_cls, server_ssl_cls): + + def app(environ, start_response): + status = '200 OK' + headers = [('Content-type', 'text/plain')] + start_response(status, headers) + return [b'Test message'] + + # Run the test WSGI server in a separate thread in order not to + # interfere with event handling in the main thread + server_class = server_ssl_cls if use_ssl else server_cls + httpd = server_class(address, SilentWSGIRequestHandler) + httpd.set_app(app) + httpd.address = httpd.server_address + server_thread = threading.Thread( + target=lambda: httpd.serve_forever(poll_interval=0.05)) + server_thread.start() + try: + yield httpd + finally: + httpd.shutdown() + httpd.server_close() + server_thread.join() + + +if hasattr(socket, 'AF_UNIX'): + + class UnixHTTPServer(socketserver.UnixStreamServer, HTTPServer): + + def server_bind(self): + socketserver.UnixStreamServer.server_bind(self) + self.server_name = '127.0.0.1' + self.server_port = 80 + + + class UnixWSGIServer(UnixHTTPServer, WSGIServer): + + request_timeout = 2 + + def server_bind(self): + UnixHTTPServer.server_bind(self) + self.setup_environ() + + def get_request(self): + request, client_addr = super().get_request() + request.settimeout(self.request_timeout) + # Code in the stdlib expects that get_request + # will return a socket and a tuple (host, port). + # However, this isn't true for UNIX sockets, + # as the second return value will be a path; + # hence we return some fake data sufficient + # to get the tests going + return request, ('127.0.0.1', '') + + + class SilentUnixWSGIServer(UnixWSGIServer): + + def handle_error(self, request, client_address): + pass + + + class UnixSSLWSGIServer(SSLWSGIServerMixin, SilentUnixWSGIServer): + pass + + + def gen_unix_socket_path(): + with tempfile.NamedTemporaryFile() as file: + return file.name + + + @contextlib.contextmanager + def unix_socket_path(): + path = gen_unix_socket_path() + try: + yield path + finally: + try: + os.unlink(path) + except OSError: + pass + + + @contextlib.contextmanager + def run_test_unix_server(*, use_ssl=False): + with unix_socket_path() as path: + yield from _run_test_server(address=path, use_ssl=use_ssl, + server_cls=SilentUnixWSGIServer, + server_ssl_cls=UnixSSLWSGIServer) + + [email protected] +def run_test_server(*, host='127.0.0.1', port=0, use_ssl=False): + yield from _run_test_server(address=(host, port), use_ssl=use_ssl, + server_cls=SilentWSGIServer, + server_ssl_cls=SSLWSGIServer) + + +def make_test_protocol(base): + dct = {} + for name in dir(base): + if name.startswith('__') and name.endswith('__'): + # skip magic names + continue + dct[name] = MockCallback(return_value=None) + return type('TestProtocol', (base,) + base.__bases__, dct)() + + +class TestSelector(selectors.BaseSelector): + + def __init__(self): + self.keys = {} + + def register(self, fileobj, events, data=None): + key = selectors.SelectorKey(fileobj, 0, events, data) + self.keys[fileobj] = key + return key + + def unregister(self, fileobj): + return self.keys.pop(fileobj) + + def select(self, timeout): + return [] + + def get_map(self): + return self.keys + + +class TestLoop(base_events.BaseEventLoop): + """Loop for unittests. + + It manages self time directly. + If something scheduled to be executed later then + on next loop iteration after all ready handlers done + generator passed to __init__ is calling. + + Generator should be like this: + + def gen(): + ... + when = yield ... + ... = yield time_advance + + Value returned by yield is absolute time of next scheduled handler. + Value passed to yield is time advance to move loop's time forward. + """ + + def __init__(self, gen=None): + super().__init__() + + if gen is None: + def gen(): + yield + self._check_on_close = False + else: + self._check_on_close = True + + self._gen = gen() + next(self._gen) + self._time = 0 + self._clock_resolution = 1e-9 + self._timers = [] + self._selector = TestSelector() + + self.readers = {} + self.writers = {} + self.reset_counters() + + self._transports = weakref.WeakValueDictionary() + + def time(self): + return self._time + + def advance_time(self, advance): + """Move test time forward.""" + if advance: + self._time += advance + + def close(self): + super().close() + if self._check_on_close: + try: + self._gen.send(0) + except StopIteration: + pass + else: # pragma: no cover + raise AssertionError("Time generator is not finished") + + def _add_reader(self, fd, callback, *args): + self.readers[fd] = events.Handle(callback, args, self, None) + + def _remove_reader(self, fd): + self.remove_reader_count[fd] += 1 + if fd in self.readers: + del self.readers[fd] + return True + else: + return False + + def assert_reader(self, fd, callback, *args): + if fd not in self.readers: + raise AssertionError(f'fd {fd} is not registered') + handle = self.readers[fd] + if handle._callback != callback: + raise AssertionError( + f'unexpected callback: {handle._callback} != {callback}') + if handle._args != args: + raise AssertionError( + f'unexpected callback args: {handle._args} != {args}') + + def assert_no_reader(self, fd): + if fd in self.readers: + raise AssertionError(f'fd {fd} is registered') + + def _add_writer(self, fd, callback, *args): + self.writers[fd] = events.Handle(callback, args, self, None) + + def _remove_writer(self, fd): + self.remove_writer_count[fd] += 1 + if fd in self.writers: + del self.writers[fd] + return True + else: + return False + + def assert_writer(self, fd, callback, *args): + assert fd in self.writers, 'fd {} is not registered'.format(fd) + handle = self.writers[fd] + assert handle._callback == callback, '{!r} != {!r}'.format( + handle._callback, callback) + assert handle._args == args, '{!r} != {!r}'.format( + handle._args, args) + + def _ensure_fd_no_transport(self, fd): + if not isinstance(fd, int): + try: + fd = int(fd.fileno()) + except (AttributeError, TypeError, ValueError): + # This code matches selectors._fileobj_to_fd function. + raise ValueError("Invalid file object: " + "{!r}".format(fd)) from None + try: + transport = self._transports[fd] + except KeyError: + pass + else: + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + + def reset_counters(self): + self.remove_reader_count = collections.defaultdict(int) + self.remove_writer_count = collections.defaultdict(int) + + def _run_once(self): + super()._run_once() + for when in self._timers: + advance = self._gen.send(when) + self.advance_time(advance) + self._timers = [] + + def call_at(self, when, callback, *args, context=None): + self._timers.append(when) + return super().call_at(when, callback, *args, context=context) + + def _process_events(self, event_list): + return + + def _write_to_self(self): + pass + + +def MockCallback(**kwargs): + return mock.Mock(spec=['__call__'], **kwargs) + + +class MockPattern(str): + """A regex based str with a fuzzy __eq__. + + Use this helper with 'mock.assert_called_with', or anywhere + where a regex comparison between strings is needed. + + For instance: + mock_call.assert_called_with(MockPattern('spam.*ham')) + """ + def __eq__(self, other): + return bool(re.search(str(self), other, re.S)) + + +class MockInstanceOf: + def __init__(self, type): + self._type = type + + def __eq__(self, other): + return isinstance(other, self._type) + + +def get_function_source(func): + source = format_helpers._get_function_source(func) + if source is None: + raise ValueError("unable to get the source of %r" % (func,)) + return source + + +class TestCase(unittest.TestCase): + @staticmethod + def close_loop(loop): + executor = loop._default_executor + if executor is not None: + executor.shutdown(wait=True) + loop.close() + + def set_event_loop(self, loop, *, cleanup=True): + assert loop is not None + # ensure that the event loop is passed explicitly in asyncio + events.set_event_loop(None) + if cleanup: + self.addCleanup(self.close_loop, loop) + + def new_test_loop(self, gen=None): + loop = TestLoop(gen) + self.set_event_loop(loop) + return loop + + def unpatch_get_running_loop(self): + events._get_running_loop = self._get_running_loop + + def setUp(self): + self._get_running_loop = events._get_running_loop + events._get_running_loop = lambda: None + self._thread_cleanup = support.threading_setup() + + def tearDown(self): + self.unpatch_get_running_loop() + + events.set_event_loop(None) + + # Detect CPython bug #23353: ensure that yield/yield-from is not used + # in an except block of a generator + self.assertEqual(sys.exc_info(), (None, None, None)) + + self.doCleanups() + support.threading_cleanup(*self._thread_cleanup) + support.reap_children() + + [email protected] +def disable_logger(): + """Context manager to disable asyncio logger. + + For example, it can be used to ignore warnings in debug mode. + """ + old_level = logger.level + try: + logger.setLevel(logging.CRITICAL+1) + yield + finally: + logger.setLevel(old_level) + + +def mock_nonblocking_socket(proto=socket.IPPROTO_TCP, type=socket.SOCK_STREAM, + family=socket.AF_INET): + """Create a mock of a non-blocking socket.""" + sock = mock.MagicMock(socket.socket) + sock.proto = proto + sock.type = type + sock.family = family + sock.gettimeout.return_value = 0.0 + return sock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/test/conftest.py new/txaio-20.1.1/test/conftest.py --- old/txaio-2.9.0/test/conftest.py 2016-11-06 20:03:51.000000000 +0100 +++ new/txaio-20.1.1/test/conftest.py 2020-01-21 00:10:08.000000000 +0100 @@ -25,9 +25,9 @@ try: if request.param == 'twisted': - return framework_tx() + return _notfixture_framework_tx() elif request.param == 'asyncio': - return framework_aio() + return _notfixture_framework_aio() except ImportError: pytest.skip() @@ -43,6 +43,10 @@ @pytest.fixture def framework_tx(): + return _notfixture_framework_tx() + + +def _notfixture_framework_tx(): try: import txaio from txaio import tx @@ -56,6 +60,10 @@ @pytest.fixture def framework_aio(): + return _notfixture_framework_aio() + + +def _notfixture_framework_aio(): try: import txaio from txaio import aio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/test/test_cancel.py new/txaio-20.1.1/test/test_cancel.py --- old/txaio-2.9.0/test/test_cancel.py 1970-01-01 01:00:00.000000000 +0100 +++ new/txaio-20.1.1/test/test_cancel.py 2020-01-21 00:10:08.000000000 +0100 @@ -0,0 +1,52 @@ +############################################################################### +# +# The MIT License (MIT) +# +# Copyright (c) Crossbar.io Technologies GmbH +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +############################################################################### + +import txaio + +from util import run_once + + +def test_cancel(framework): + cancels = [] + + def it_died(f): + cancels.append(f) + + f = txaio.create_future(canceller=it_died) + # both Future and Deferred have .cancel() methods .. but seemed + # more "symmetric"/expected to make a method? But could just stick + # with "f.cancel()" here ... + txaio.cancel(f) + + # at least for Twisted, we have to "handle" the "CancelledError" + # -- in practice, dropping a future on the floor with no + # error-handler is A Bad Thing anyway + txaio.add_callbacks(f, None, lambda _: None) + + run_once() + run_once() + + assert cancels == [f] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/test/test_gather.py new/txaio-20.1.1/test/test_gather.py --- old/txaio-2.9.0/test/test_gather.py 2018-03-02 08:04:45.000000000 +0100 +++ new/txaio-20.1.1/test/test_gather.py 2020-01-21 00:10:08.000000000 +0100 @@ -26,7 +26,7 @@ import txaio -from util import await +from util import _await def test_gather_two(framework): @@ -61,7 +61,7 @@ txaio.add_callbacks(f2, done, error) for f in [f0, f1, f2]: - await(f) + _await(f) assert len(results) == 1 assert len(errors) == 0 @@ -99,7 +99,7 @@ # out of "run_until_complete()" as well; fix util.py? for f in [f0, f1, f2]: try: - await(f) + _await(f) except Exception: pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/test/test_util.py new/txaio-20.1.1/test/test_util.py --- old/txaio-2.9.0/test/test_util.py 1970-01-01 01:00:00.000000000 +0100 +++ new/txaio-20.1.1/test/test_util.py 2020-01-21 10:06:33.000000000 +0100 @@ -0,0 +1,37 @@ +############################################################################### +# +# The MIT License (MIT) +# +# Copyright (c) Crossbar.io Technologies GmbH +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +############################################################################### + +import txaio + + +def test_time_ns(framework): + now = txaio.time_ns() + assert now > 0 + + +def test_perf_counter_ns(framework): + now = txaio.perf_counter_ns() + assert now > 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/test/util.py new/txaio-20.1.1/test/util.py --- old/txaio-2.9.0/test/util.py 2017-04-15 16:17:17.000000000 +0200 +++ new/txaio-20.1.1/test/util.py 2020-01-21 00:10:08.000000000 +0100 @@ -24,6 +24,8 @@ # ############################################################################### +import sys + def run_once(): ''' @@ -38,7 +40,11 @@ try: import asyncio - from asyncio.test_utils import run_once as _run_once + if sys.version_info >= (3, 7): + # https://github.com/crossbario/txaio/issues/139 + from _asyncio_test_utils import run_once as _run_once + else: + from asyncio.test_utils import run_once as _run_once return _run_once(txaio.config.loop or asyncio.get_event_loop()) except ImportError: @@ -57,7 +63,7 @@ asyncio.gather(*asyncio.Task.all_tasks()) -def await(future): +def _await(future): ''' Essentially just a way to call "run_until_complete" that becomes a no-op if we're using Twisted. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/tox.ini new/txaio-20.1.1/tox.ini --- old/txaio-2.9.0/tox.ini 2018-03-02 08:04:45.000000000 +0100 +++ new/txaio-20.1.1/tox.ini 2020-01-21 10:06:33.000000000 +0100 @@ -1,35 +1,27 @@ [tox] envlist = flake8 - py27-{tw121,tw132,tw154,tw165,twtrunk,asyncio} - pypy-{tw121,tw132,tw154,tw165,twtrunk,asyncio} - pypy3-{tw154,tw165,twtrunk,asyncio} - py33-{tw154,tw165,asyncio} - py34-{tw154,tw165,twtrunk,asyncio} - py35-{tw154,tw165,twtrunk,asyncio} - py36-{tw154,tw165,twtrunk,asyncio} + + # CPython + py35-{tw187,tw1910,twtrunk,asyncio} + py37-{tw165,tw187,tw1910,twtrunk,asyncio} + py38-{tw165,tw187,tw1910,twtrunk,asyncio} + + # PyPy + pypy3-{tw187,tw1910,twtrunk,asyncio} [testenv] deps = six mock - pytest - coverage==4.0 + pytest==4.6.9 + coverage==4.5.4 ; twisted dependencies - tw121: twisted==12.1.0 - tw132: twisted==13.2.0 - tw154: twisted==15.4.0 - tw165: twisted==16.5.0 + tw187: twisted==18.7.0 + tw1910: twisted==19.10.0 twtrunk: https://github.com/twisted/twisted/archive/trunk.zip - {tw121,tw132,tw154,tw165,twtrunk}: pytest-twisted - - ; asyncio dependencies - py26-asyncio: trollius>=2.0 - py26-asyncio: ordereddict - py27-asyncio: trollius>=2.0 - pypy-asyncio: trollius>=2.0 - py33-asyncio: asyncio>=3.4.3 + {tw187,tw1910,twtrunk}: pytest-twisted==1.10 changedir=test @@ -42,7 +34,6 @@ # -s: show output immediately # -v: one line per test, instead of one dot - [testenv:flake8] deps = flake8 @@ -50,4 +41,4 @@ changedir=. commands = - flake8 --max-line-length=119 txaio/ test/ + flake8 --max-line-length=119 txaio/ test/ --exclude=test/_asyncio_test_utils.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio/__init__.py new/txaio-20.1.1/txaio/__init__.py --- old/txaio-2.9.0/txaio/__init__.py 2017-04-15 16:17:17.000000000 +0200 +++ new/txaio-20.1.1/txaio/__init__.py 2020-01-21 10:06:33.000000000 +0100 @@ -74,6 +74,7 @@ 'is_future', # True for Deferreds in tx and Futures, @coroutines in asyncio 'reject', # errback a Future 'resolve', # callback a Future + 'cancel', # cancel a Future 'add_callbacks', # add callback and/or errback 'gather', # return a Future waiting for several other Futures 'is_called', # True if the Future has a result @@ -96,6 +97,8 @@ 'ILogger', # API for logging 'sleep', # little helper for inline sleeping + 'time_ns', # helper: current time (UTC) in ns + 'perf_counter_ns', # helper: current performance counter in ns ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio/_unframework.py new/txaio-20.1.1/txaio/_unframework.py --- old/txaio-2.9.0/txaio/_unframework.py 2017-04-15 16:17:17.000000000 +0200 +++ new/txaio-20.1.1/txaio/_unframework.py 2020-01-21 10:06:33.000000000 +0100 @@ -54,6 +54,7 @@ as_future = _throw_usage_error is_future = _throw_usage_error reject = _throw_usage_error +cancel = _throw_usage_error resolve = _throw_usage_error add_callbacks = _throw_usage_error gather = _throw_usage_error @@ -78,3 +79,5 @@ ILogger = _throw_usage_error sleep = _throw_usage_error +time_ns = _throw_usage_error +perf_counter_ns = _throw_usage_error diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio/_util.py new/txaio-20.1.1/txaio/_util.py --- old/txaio-2.9.0/txaio/_util.py 1970-01-01 01:00:00.000000000 +0100 +++ new/txaio-20.1.1/txaio/_util.py 2020-01-21 10:06:33.000000000 +0100 @@ -0,0 +1,48 @@ +############################################################################### +# +# The MIT License (MIT) +# +# Copyright (c) Crossbar.io Technologies GmbH +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +############################################################################### + +import sys +import time + + +if sys.version_info >= (3, 7): + + time_ns = time.time_ns + perf_counter_ns = time.perf_counter_ns + +else: + + def time_ns(): + """ + Shim for standard library time.time_ns for Python < 3.7. + """ + return int(time.time() * 1000000000.) + + def perf_counter_ns(): + """ + Shim for standard library time.perf_counter for Python < 3.7. + """ + return int(time.perf_counter() * 1000000000.) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio/_version.py new/txaio-20.1.1/txaio/_version.py --- old/txaio-2.9.0/txaio/_version.py 2018-03-02 08:06:14.000000000 +0100 +++ new/txaio-20.1.1/txaio/_version.py 2020-01-21 10:06:33.000000000 +0100 @@ -1 +1 @@ -__version__ = u'2.9.0' +__version__ = u'20.1.1' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio/aio.py new/txaio-20.1.1/txaio/aio.py --- old/txaio-2.9.0/txaio/aio.py 2018-03-02 08:04:45.000000000 +0100 +++ new/txaio-20.1.1/txaio/aio.py 2020-01-21 10:06:33.000000000 +0100 @@ -33,12 +33,14 @@ import functools import traceback import logging +import inspect from datetime import datetime from txaio.interfaces import IFailedFuture, ILogger, log_levels from txaio._iotype import guess_stream_needs_encoding from txaio._common import _BatchedTimer +from txaio import _util from txaio import _Config import six @@ -258,7 +260,21 @@ def make_logger(): - logger = _TxaioLogWrapper(logging.getLogger()) + # we want the namespace to be the calling context of "make_logger" + # otherwise the root logger will be returned + cf = inspect.currentframe().f_back + if "self" in cf.f_locals: + # We're probably in a class init or method + cls = cf.f_locals["self"].__class__ + namespace = '{0}.{1}'.format(cls.__module__, cls.__name__) + else: + namespace = cf.f_globals["__name__"] + if cf.f_code.co_name != "<module>": + # If it's not the module, and not in a class instance, add the code + # object's name. + namespace = namespace + "." + cf.f_code.co_name + + logger = _TxaioLogWrapper(logging.getLogger(name=namespace)) # remember this so we can set their levels properly once # start_logging is actually called _loggers.add(logger) @@ -374,7 +390,7 @@ except Exception: return u"Failed to format failure traceback for '{0}'".format(fail) - def create_future(self, result=_unspecified, error=_unspecified): + def create_future(self, result=_unspecified, error=_unspecified, canceller=_unspecified): if result is not _unspecified and error is not _unspecified: raise ValueError("Cannot have both result and error.") @@ -383,6 +399,19 @@ resolve(f, result) elif error is not _unspecified: reject(f, error) + + # Twisted's only API for cancelling is to pass a + # single-argument callable to the Deferred constructor, so + # txaio apes that here for asyncio. The argument is the Future + # that has been cancelled. + if canceller is not _unspecified: + def done(f): + try: + f.exception() + except asyncio.CancelledError: + canceller(f) + f.add_done_callback(done) + return f def create_future_success(self, result): @@ -461,6 +490,9 @@ raise RuntimeError("reject requires an IFailedFuture or Exception") future.set_exception(error.value) + def cancel(self, future): + future.cancel() + def create_failure(self, exception=None): """ This returns an object implementing IFailedFuture. @@ -535,7 +567,10 @@ is_called = _default_api.is_called resolve = _default_api.resolve reject = _default_api.reject +cancel = _default_api.cancel create_failure = _default_api.create_failure add_callbacks = _default_api.add_callbacks gather = _default_api.gather sleep = _default_api.sleep +time_ns = _util.time_ns +perf_counter_ns = _util.perf_counter_ns diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio/tx.py new/txaio-20.1.1/txaio/tx.py --- old/txaio-2.9.0/txaio/tx.py 2017-04-15 16:42:18.000000000 +0200 +++ new/txaio-20.1.1/txaio/tx.py 2020-01-21 10:06:33.000000000 +0100 @@ -44,9 +44,19 @@ from txaio._iotype import guess_stream_needs_encoding from txaio import _Config from txaio._common import _BatchedTimer +from txaio import _util import six +PY3_CORO = False +if six.PY3: + try: + from twisted.internet.defer import ensureDeferred + from asyncio import iscoroutinefunction + PY3_CORO = True + except ImportError: + pass + using_twisted = True using_asyncio = False @@ -396,11 +406,11 @@ except Exception: return u"Failed to format failure traceback for '{0}'".format(fail) - def create_future(self, result=_unspecified, error=_unspecified): + def create_future(self, result=_unspecified, error=_unspecified, canceller=None): if result is not _unspecified and error is not _unspecified: raise ValueError("Cannot have both result and error.") - f = Deferred() + f = Deferred(canceller=canceller) if result is not _unspecified: resolve(f, result) elif error is not _unspecified: @@ -414,6 +424,9 @@ return fail(create_failure(error)) def as_future(self, fun, *args, **kwargs): + # Twisted doesn't automagically deal with coroutines on Py3 + if PY3_CORO and iscoroutinefunction(fun): + return ensureDeferred(fun(*args, **kwargs)) return maybeDeferred(fun, *args, **kwargs) def is_future(self, obj): @@ -465,6 +478,9 @@ raise RuntimeError("reject requires a Failure or Exception") future.errback(error) + def cancel(self, future): + future.cancel() + def create_failure(self, exception=None): """ Create a Failure instance. @@ -567,7 +583,10 @@ is_called = _default_api.is_called resolve = _default_api.resolve reject = _default_api.reject +cancel = _default_api.cancel create_failure = _default_api.create_failure add_callbacks = _default_api.add_callbacks gather = _default_api.gather sleep = _default_api.sleep +time_ns = _util.time_ns +perf_counter_ns = _util.perf_counter_ns diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio.egg-info/PKG-INFO new/txaio-20.1.1/txaio.egg-info/PKG-INFO --- old/txaio-2.9.0/txaio.egg-info/PKG-INFO 2018-03-02 08:47:02.000000000 +0100 +++ new/txaio-20.1.1/txaio.egg-info/PKG-INFO 2020-01-21 10:09:51.000000000 +0100 @@ -1,12 +1,11 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: txaio -Version: 2.9.0 +Version: 20.1.1 Summary: Compatibility API between asyncio/Twisted/Trollius Home-page: https://github.com/crossbario/txaio Author: Crossbar.io Technologies GmbH Author-email: [email protected] License: MIT License -Description-Content-Type: UNKNOWN Description: txaio ===== @@ -31,20 +30,12 @@ Platform support ---------------- - **txaio** runs on CPython 2.7/3.3+ and PyPy 2/3, on top of Twisted or asyncio. Specifically, **txaio** is tested on the following platforms: + **txaio** runs on CPython 3.5+ and PyPy 3, on top of *Twisted* or *asyncio*. Specifically, **txaio** is tested on the following platforms: - **Python 2:** + * CPython 3.5, 3.7 and 3.8 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) + * PyPy 3 on Twisted 18.7, 19.10, trunk and on asyncio (stdlib) - * CPython 2.7 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 - * PyPy 2 on Twisted 12.1, 13.2, 15.4, 16.5, trunk and on Trollius 2.0 - - **Python 3:** - - * CPython 3.3 on Twisted 15.4, 16.5, trunk and on Trollius 2.0 - * CPython 3.4 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) - * CPython 3.5 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) - * CPython 3.6 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) - * PyPy 3 on Twisted 15.4, 16.5, trunk and on asyncio (stdlib) + > Note: txaio up to version 18.8.1 also supported Python 2.7 and Python 3.4. Beginning with release v20.1.1, txaio only supports Python 3.5+. How it works @@ -99,14 +90,17 @@ Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.5 +Provides-Extra: twisted +Provides-Extra: all +Provides-Extra: dev +Provides-Extra: asyncio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio.egg-info/SOURCES.txt new/txaio-20.1.1/txaio.egg-info/SOURCES.txt --- old/txaio-2.9.0/txaio.egg-info/SOURCES.txt 2018-03-02 08:47:02.000000000 +0100 +++ new/txaio-20.1.1/txaio.egg-info/SOURCES.txt 2020-01-21 10:09:51.000000000 +0100 @@ -17,12 +17,14 @@ examples/log_interop_stdlib.py examples/log_interop_twisted.py examples/multiloop.py +test/_asyncio_test_utils.py test/conftest.py test/test_as_future.py test/test_batched_timers_aio.py test/test_batched_timers_tx.py test/test_call_later.py test/test_callback.py +test/test_cancel.py test/test_create.py test/test_errback.py test/test_gather.py @@ -31,11 +33,13 @@ test/test_legacy_logging.py test/test_logging.py test/test_packaging.py +test/test_util.py test/util.py txaio/__init__.py txaio/_common.py txaio/_iotype.py txaio/_unframework.py +txaio/_util.py txaio/_version.py txaio/aio.py txaio/interfaces.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/txaio-2.9.0/txaio.egg-info/requires.txt new/txaio-20.1.1/txaio.egg-info/requires.txt --- old/txaio-2.9.0/txaio.egg-info/requires.txt 2018-03-02 08:47:02.000000000 +0100 +++ new/txaio-20.1.1/txaio.egg-info/requires.txt 2020-01-21 10:09:51.000000000 +0100 @@ -7,6 +7,7 @@ [asyncio] [dev] +wheel pytest>=2.6.4 pytest-cov>=1.8.1 pep8>=1.6.2
