Hello community, here is the log from the commit of package python-amqp for openSUSE:Factory checked in at 2019-09-23 12:08:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-amqp (Old) and /work/SRC/openSUSE:Factory/.python-amqp.new.7948 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-amqp" Mon Sep 23 12:08:20 2019 rev:30 rq:730145 version:2.5.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-amqp/python-amqp.changes 2019-07-30 13:02:37.882423650 +0200 +++ /work/SRC/openSUSE:Factory/.python-amqp.new.7948/python-amqp.changes 2019-09-23 12:08:20.701896110 +0200 @@ -1,0 +2,9 @@ +Wed Sep 11 13:18:08 UTC 2019 - Tomáš Chvátal <tchva...@suse.com> + +- Update to 2.5.1: + - Ignore all methods except Close and Close-OK when channel/connection is closing + - Fix faulty ssl sni intiation parameters (#283) + - Undeprecate auto_delete flag for exchanges. (#287) + - Improved tests and testing environments + +------------------------------------------------------------------- Old: ---- amqp-2.5.0.tar.gz New: ---- amqp-2.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-amqp.spec ++++++ --- /var/tmp/diff_new_pack.UpkmsL/_old 2019-09-23 12:08:21.641895955 +0200 +++ /var/tmp/diff_new_pack.UpkmsL/_new 2019-09-23 12:08:21.641895955 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-amqp -Version: 2.5.0 +Version: 2.5.1 Release: 0 Summary: Low-level AMQP client for Python (fork of amqplib) License: LGPL-2.1-or-later ++++++ amqp-2.5.0.tar.gz -> amqp-2.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/Changelog new/amqp-2.5.1/Changelog --- old/amqp-2.5.0/Changelog 2019-05-30 13:07:00.000000000 +0200 +++ new/amqp-2.5.1/Changelog 2019-08-14 17:48:25.000000000 +0200 @@ -5,6 +5,19 @@ The previous amqplib changelog is here: http://code.google.com/p/py-amqplib/source/browse/CHANGES +.. _version-2.5.1: + +2.5.1 +===== +:release-date: 2019-08-14 22.00 P.M UTC+6:00 +:release-by: Asif Saif Uddin + +- Ignore all methods except Close and Close-OK when channel/connection is closing +- Fix faulty ssl sni intiation parameters (#283) +- Undeprecate auto_delete flag for exchanges. (#287) +- Improved tests and testing environments + + .. _version-2.5.0: 2.5.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/PKG-INFO new/amqp-2.5.1/PKG-INFO --- old/amqp-2.5.0/PKG-INFO 2019-05-30 13:08:20.000000000 +0200 +++ new/amqp-2.5.1/PKG-INFO 2019-08-14 17:50:13.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: amqp -Version: 2.5.0 +Version: 2.5.1 Summary: Low-level AMQP client for Python (fork of amqplib). Home-page: http://github.com/celery/py-amqp Author: Barry Pederson @@ -13,7 +13,7 @@ |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| - :Version: 2.4.2 + :Version: 2.5.1 :Web: https://amqp.readthedocs.io/ :Download: https://pypi.org/project/amqp/ :Source: http://github.com/celery/py-amqp/ @@ -145,11 +145,10 @@ Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 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: License :: OSI Approved :: BSD License Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/README.rst new/amqp-2.5.1/README.rst --- old/amqp-2.5.0/README.rst 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/README.rst 2019-08-14 17:48:25.000000000 +0200 @@ -4,7 +4,7 @@ |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| -:Version: 2.4.2 +:Version: 2.5.1 :Web: https://amqp.readthedocs.io/ :Download: https://pypi.org/project/amqp/ :Source: http://github.com/celery/py-amqp/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/amqp/__init__.py new/amqp-2.5.1/amqp/__init__.py --- old/amqp-2.5.0/amqp/__init__.py 2019-05-30 13:05:09.000000000 +0200 +++ new/amqp-2.5.1/amqp/__init__.py 2019-08-14 17:49:02.000000000 +0200 @@ -6,7 +6,7 @@ from collections import namedtuple -__version__ = '2.5.0' +__version__ = '2.5.1' __author__ = 'Barry Pederson' __maintainer__ = 'Asif Saif Uddin, Omer Katz' __contact__ = 'pya...@celeryproject.org' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/amqp/abstract_channel.py new/amqp-2.5.1/amqp/abstract_channel.py --- old/amqp-2.5.0/amqp/abstract_channel.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/amqp/abstract_channel.py 2019-07-12 07:25:19.000000000 +0200 @@ -2,6 +2,8 @@ # Copyright (C) 2007-2008 Barry Pederson <b...@barryp.org>) from __future__ import absolute_import, unicode_literals +import logging + from vine import ensure_promise, promise from .exceptions import AMQPNotImplementedError, RecoverableConnectionError @@ -10,6 +12,12 @@ __all__ = ['AbstractChannel'] +AMQP_LOGGER = logging.getLogger('amqp') + +IGNORED_METHOD_DURING_CHANNEL_CLOSE = """\ +Received method %s during closing channel %s. This method will be ignored\ +""" + class AbstractChannel(object): """Superclass for Connection and Channel. @@ -91,6 +99,17 @@ pending.pop(m, None) def dispatch_method(self, method_sig, payload, content): + if self.is_closing and method_sig not in ( + self._ALLOWED_METHODS_WHEN_CLOSING + ): + # When channel.close() was called we must ignore all methods except + # Channel.close and Channel.CloseOk + AMQP_LOGGER.warning( + IGNORED_METHOD_DURING_CHANNEL_CLOSE, + method_sig, self.channel_id + ) + return + if content and \ self.auto_decode and \ hasattr(content, 'content_encoding'): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/amqp/channel.py new/amqp-2.5.1/amqp/channel.py --- old/amqp-2.5.0/amqp/channel.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/amqp/channel.py 2019-08-14 17:32:29.000000000 +0200 @@ -5,7 +5,6 @@ import logging import socket from collections import defaultdict -from warnings import warn from vine import ensure_promise @@ -21,11 +20,6 @@ AMQP_LOGGER = logging.getLogger('amqp') -EXCHANGE_AUTODELETE_DEPRECATED = """\ -The auto_delete flag for exchanges has been deprecated and will be removed -from py-amqp v1.5.0.\ -""" - REJECTED_MESSAGE_WITHOUT_CALLBACK = """\ Rejecting message with delivery tag %r for reason of having no callbacks. consumer_tag=%r exchange=%r routing_key=%r.\ @@ -97,6 +91,10 @@ } _METHODS = {m.method_sig: m for m in _METHODS} + _ALLOWED_METHODS_WHEN_CLOSING = ( + spec.Channel.Close, spec.Channel.CloseOk + ) + def __init__(self, connection, channel_id=None, auto_decode=True, on_open=None): if channel_id: @@ -609,9 +607,6 @@ implementation. This field is ignored if passive is True. """ - if auto_delete: - warn(VDeprecationWarning(EXCHANGE_AUTODELETE_DEPRECATED)) - self.send_method( spec.Exchange.Declare, argsig, (0, exchange, type, passive, durable, auto_delete, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/amqp/connection.py new/amqp-2.5.1/amqp/connection.py --- old/amqp-2.5.0/amqp/connection.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/amqp/connection.py 2019-07-12 07:25:19.000000000 +0200 @@ -162,6 +162,10 @@ } _METHODS = {m.method_sig: m for m in _METHODS} + _ALLOWED_METHODS_WHEN_CLOSING = ( + spec.Connection.Close, spec.Connection.CloseOk + ) + connection_errors = ( ConnectionError, socket.error, @@ -576,10 +580,11 @@ wait=spec.Connection.CloseOk, ) except (OSError, IOError, SSLError): - self.is_closing = False # close connection self.collect() raise + finally: + self.is_closing = False def _on_close(self, reply_code, reply_text, class_id, method_id): """Request a connection close. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/amqp/transport.py new/amqp-2.5.1/amqp/transport.py --- old/amqp-2.5.0/amqp/transport.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/amqp/transport.py 2019-08-14 17:32:29.000000000 +0200 @@ -317,7 +317,7 @@ def _wrap_socket_sni(self, sock, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, - ca_certs=None, do_handshake_on_connect=True, + ca_certs=None, do_handshake_on_connect=False, suppress_ragged_eofs=True, server_hostname=None, ciphers=None, ssl_version=None): """Socket wrap with SNI headers. @@ -357,8 +357,10 @@ hasattr(ssl, 'SSLContext')): context = ssl.SSLContext(opts['ssl_version']) context.verify_mode = cert_reqs - context.check_hostname = True - context.load_cert_chain(certfile, keyfile) + if cert_reqs != ssl.CERT_NONE: + context.check_hostname = True + if (certfile is not None) and (keyfile is not None): + context.load_cert_chain(certfile, keyfile) sock = context.wrap_socket(sock, server_hostname=server_hostname) return sock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/amqp.egg-info/PKG-INFO new/amqp-2.5.1/amqp.egg-info/PKG-INFO --- old/amqp-2.5.0/amqp.egg-info/PKG-INFO 2019-05-30 13:08:18.000000000 +0200 +++ new/amqp-2.5.1/amqp.egg-info/PKG-INFO 2019-08-14 17:50:13.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: amqp -Version: 2.5.0 +Version: 2.5.1 Summary: Low-level AMQP client for Python (fork of amqplib). Home-page: http://github.com/celery/py-amqp Author: Barry Pederson @@ -13,7 +13,7 @@ |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| - :Version: 2.4.2 + :Version: 2.5.1 :Web: https://amqp.readthedocs.io/ :Download: https://pypi.org/project/amqp/ :Source: http://github.com/celery/py-amqp/ @@ -145,11 +145,10 @@ Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 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: License :: OSI Approved :: BSD License Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/requirements/docs.txt new/amqp-2.5.1/requirements/docs.txt --- old/amqp-2.5.0/requirements/docs.txt 2018-09-20 07:39:45.000000000 +0200 +++ new/amqp-2.5.1/requirements/docs.txt 2019-07-12 07:25:19.000000000 +0200 @@ -1 +1 @@ -git+https://github.com/celery/sphinx_celery.git +sphinx_celery==1.4.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/setup.py new/amqp-2.5.1/setup.py --- old/amqp-2.5.0/setup.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/setup.py 2019-08-14 17:48:25.000000000 +0200 @@ -22,7 +22,6 @@ Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 @@ -46,6 +45,7 @@ def add_doc(m): return (('doc', m.groups()[0]),) + pats = {re_meta: add_default, re_doc: add_doc} here = os.path.abspath(os.path.dirname(__file__)) @@ -102,6 +102,7 @@ pytest_args = self.pytest_args.split(' ') sys.exit(pytest.main(pytest_args)) + setuptools.setup( name=NAME, packages=setuptools.find_packages(exclude=['ez_setup', 't', 't.*']), @@ -116,7 +117,7 @@ platforms=['any'], license='BSD', classifiers=classifiers, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", + python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", install_requires=reqs('default.txt'), tests_require=reqs('test.txt'), cmdclass={'test': pytest}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/t/integration/test_integration.py new/amqp-2.5.1/t/integration/test_integration.py --- old/amqp-2.5.0/t/integration/test_integration.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/t/integration/test_integration.py 2019-07-12 07:25:19.000000000 +0200 @@ -366,6 +366,34 @@ ) t.close.assert_called_once_with() + @patch('amqp.Connection._on_blocked') + def test_connecion_ignore_methods_during_close(self, on_blocked_mock): + # Test checking that py-amqp will discard any received methods + # except Close and Close-OK after sending Connecion.Close method + # to server. + frame_writer_cls_mock = Mock() + frame_writer_mock = frame_writer_cls_mock() + conn = Connection(frame_writer=frame_writer_cls_mock) + with patch.object(conn, 'Transport') as transport_mock: + handshake(conn, transport_mock) + frame_writer_mock.reset_mock() + # Inject CloseOk response from broker + transport_mock().read_frame.side_effect = [ + build_frame_type_1( + spec.Connection.Blocked, channel=0 + ), + build_frame_type_1( + spec.Connection.CloseOk + ) + ] + t = conn.transport + conn.close() + on_blocked_mock.assert_not_called() + frame_writer_mock.assert_called_once_with( + 1, 0, spec.Connection.Close, dumps('BsBB', (0, '', 0, 0)), None + ) + t.close.assert_called_once_with() + def test_connection_closed_by_broker(self): # Test that library response correctly CloseOk when # close method is received and _on_close_ok() method is called. @@ -413,6 +441,74 @@ conn.drain_events(0) callback_mock.assert_called_once() + def test_channel_ignore_methods_during_close(self): + # Test checking that py-amqp will discard any received methods + # except Close and Close-OK after sending Channel.Close method + # to server. + frame_writer_cls_mock = Mock() + conn = Connection(frame_writer=frame_writer_cls_mock) + consumer_tag = 'amq.ctag-PCmzXGkhCw_v0Zq7jXyvkg' + with patch.object(conn, 'Transport') as transport_mock: + handshake(conn, transport_mock) + + channel_id = 1 + transport_mock().read_frame.side_effect = [ + # Inject Open Handshake + build_frame_type_1( + spec.Channel.OpenOk, + channel=channel_id, + args=(1, False), + arg_format='Lb' + ), + # Inject basic-deliver response + build_frame_type_1( + spec.Basic.Deliver, + channel=1, + arg_format='sLbss', + args=( + # consumer-tag, delivery-tag, redelivered, + consumer_tag, 1, False, + # exchange-name, routing-key + 'foo_exchange', 'routing-key' + ) + ), + build_frame_type_2( + channel=1, + body_len=12, + properties=b'0\x00\x00\x00\x00\x00\x01' + ), + build_frame_type_3( + channel=1, + body=b'Hello World!' + ), + # Inject close method + build_frame_type_1( + spec.Channel.CloseOk, + channel=channel_id + ), + ] + + frame_writer_mock = frame_writer_cls_mock() + frame_writer_mock.reset_mock() + + with patch('amqp.Channel._on_basic_deliver') as on_deliver_mock: + ch = conn.channel(channel_id=channel_id) + ch.close() + on_deliver_mock.assert_not_called() + frame_writer_mock.assert_has_calls( + [ + call( + 1, 1, spec.Channel.Open, dumps('s', ('',)), + None + ), + call( + 1, 1, spec.Channel.Close, dumps('BsBB', (0, '', 0, 0)), + None + ) + ] + ) + assert ch.is_open is False + def test_channel_open_close(self): # Test checking opening and closing channel frame_writer_cls_mock = Mock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/t/integration/test_rmq.py new/amqp-2.5.1/t/integration/test_rmq.py --- old/amqp-2.5.0/t/integration/test_rmq.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/t/integration/test_rmq.py 2019-07-12 07:25:19.000000000 +0200 @@ -10,7 +10,10 @@ @pytest.fixture def connection(request): - host = 'localhost:%s' % os.environ.get('RABBITMQ_5672_TCP', '5672') + host = '%s:%s' % ( + os.environ.get('RABBITMQ_HOST', 'localhost'), + os.environ.get('RABBITMQ_5672_TCP', '5672') + ) vhost = getattr(request.config, "slaveinput", {}).get("slaveid", None) return amqp.Connection(host=host, vhost=vhost) @@ -31,6 +34,7 @@ self.connection.connect() self.channel = self.connection.channel() yield + self.channel.close() self.connection.close() @pytest.mark.parametrize( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/t/unit/test_abstract_channel.py new/amqp-2.5.1/t/unit/test_abstract_channel.py --- old/amqp-2.5.0/t/unit/test_abstract_channel.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/t/unit/test_abstract_channel.py 2019-07-12 07:25:19.000000000 +0200 @@ -3,10 +3,13 @@ import pytest from vine import promise -from amqp.abstract_channel import AbstractChannel +from amqp import spec +from amqp.abstract_channel import ( + AbstractChannel, IGNORED_METHOD_DURING_CHANNEL_CLOSE +) from amqp.exceptions import AMQPNotImplementedError, RecoverableConnectionError from amqp.serialization import dumps -from case import Mock, patch +from case import Mock, patch, sentinel class test_AbstractChannel: @@ -124,3 +127,33 @@ p2.assert_called_with((50, 61), 1, 2, 3, self.content) assert not self.c._pending assert self.c._callbacks[(50, 61)] + + @pytest.mark.parametrize( + "method", + ( + spec.Channel.Close, + spec.Channel.CloseOk, + spec.Basic.Deliver + ) + ) + def test_dispatch_method__closing_connection(self, method, caplog): + self.c._ALLOWED_METHODS_WHEN_CLOSING = ( + spec.Channel.Close, spec.Channel.CloseOk + ) + self.c.is_closing = True + with patch.object(self.c, '_METHODS'), \ + patch.object(self.c, '_callbacks'): + self.c.dispatch_method( + method, sentinel.PAYLOAD, sentinel.CONTENT + ) + if method in (spec.Channel.Close, spec.Channel.CloseOk): + self.c._METHODS.__getitem__.assert_called_once_with(method) + self.c._callbacks[method].assert_called_once() + else: + self.c._METHODS.__getitem__.assert_not_called() + self.c._callbacks[method].assert_not_called() + assert caplog.records[0].msg == \ + IGNORED_METHOD_DURING_CHANNEL_CLOSE + assert caplog.records[0].args[0] == method + assert caplog.records[0].args[1] == self.channel_id + assert caplog.records[0].levelname == 'WARNING' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/t/unit/test_channel.py new/amqp-2.5.1/t/unit/test_channel.py --- old/amqp-2.5.0/t/unit/test_channel.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/t/unit/test_channel.py 2019-08-14 17:32:29.000000000 +0200 @@ -88,6 +88,7 @@ (30, 'text', spec.Queue.Declare[0], spec.Queue.Declare[1]), wait=spec.Channel.CloseOk, ) + assert self.c.is_closing is False assert self.c.connection is None def test_on_close(self): @@ -147,12 +148,10 @@ ) def test_exchange_declare__auto_delete(self): - with patch('amqp.channel.warn') as warn: - self.c.exchange_declare( - 'foo', 'direct', False, True, - auto_delete=True, nowait=False, arguments={'x': 1}, - ) - warn.assert_called() + self.c.exchange_declare( + 'foo', 'direct', False, True, + auto_delete=True, nowait=False, arguments={'x': 1}, + ) def test_exchange_delete(self): self.c.exchange_delete('foo') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-2.5.0/t/unit/test_transport.py new/amqp-2.5.1/t/unit/test_transport.py --- old/amqp-2.5.0/t/unit/test_transport.py 2019-05-30 13:04:06.000000000 +0200 +++ new/amqp-2.5.1/t/unit/test_transport.py 2019-08-14 17:32:29.000000000 +0200 @@ -631,7 +631,7 @@ ca_certs=None, server_side=False, ciphers=None, ssl_version=2, suppress_ragged_eofs=True, - do_handshake_on_connect=True) + do_handshake_on_connect=False) def test_shutdown_transport(self): self.t.sock = None