Hello community, here is the log from the commit of package python-thriftpy2 for openSUSE:Factory checked in at 2020-03-26 23:34:27 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-thriftpy2 (Old) and /work/SRC/openSUSE:Factory/.python-thriftpy2.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-thriftpy2" Thu Mar 26 23:34:27 2020 rev:5 rq:788511 version:0.4.11 Changes: -------- --- /work/SRC/openSUSE:Factory/python-thriftpy2/python-thriftpy2.changes 2020-01-14 21:12:37.446911167 +0100 +++ /work/SRC/openSUSE:Factory/.python-thriftpy2.new.3160/python-thriftpy2.changes 2020-03-26 23:35:09.850815987 +0100 @@ -1,0 +2,8 @@ +Thu Mar 26 11:07:36 UTC 2020 - pgaj...@suse.com + +- version update to 0.4.11 + - Support Cython in HTTP and fix TCyBufferedTransport early flush issue, via `2-#129`_. + - Fix exception handling in TProcessor, via `2-#128`_. + - Rename socket_timeout to timeout for compatibility, via `2-#115`_. + +------------------------------------------------------------------- Old: ---- v0.4.10.tar.gz New: ---- v0.4.11.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-thriftpy2.spec ++++++ --- /var/tmp/diff_new_pack.3REXwc/_old 2020-03-26 23:35:11.186816470 +0100 +++ /var/tmp/diff_new_pack.3REXwc/_new 2020-03-26 23:35:11.190816471 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-thriftpy2 -Version: 0.4.10 +Version: 0.4.11 Release: 0 Summary: Pure python implementation of Apache Thrift License: MIT ++++++ v0.4.10.tar.gz -> v0.4.11.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/CHANGES.rst new/thriftpy2-0.4.11/CHANGES.rst --- old/thriftpy2-0.4.10/CHANGES.rst 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/CHANGES.rst 2020-03-17 04:48:19.000000000 +0100 @@ -3,14 +3,28 @@ 0.4.x ~~~~~ -Version 0.4.9 +Version 0.4.11 +------------- + +Released on Mar 17, 2020. + +- Support Cython in HTTP and fix TCyBufferedTransport early flush issue, via `2-#129`_. +- Fix exception handling in TProcessor, via `2-#128`_. +- Rename socket_timeout to timeout for compatibility, via `2-#115`_. + +.. _2-#115: https://github.com/Thriftpy/thriftpy2/pull/115 +.. _2-#128: https://github.com/Thriftpy/thriftpy2/pull/128 +.. _2-#129: https://github.com/Thriftpy/thriftpy2/pull/129 + + +Version 0.4.10 ------------- Released on Jan 1, 2020. - Add TAsyncCompactProtocol and TAsyncFramedTransport, via `2-#103`_. - Add TAsyncProtocolBase and TAsyncTransportBase, via `2-#108`_. -- Add __str__ on TProtocolException, , via `2-#109`_. +- Add __str__ on TProtocolException, via `2-#109`_. - Support passing socket_family in make_client, via `2-#110`_. .. _2-#103: https://github.com/Thriftpy/thriftpy2/pull/103 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/MANIFEST.in new/thriftpy2-0.4.11/MANIFEST.in --- old/thriftpy2-0.4.10/MANIFEST.in 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/MANIFEST.in 2020-03-17 04:48:19.000000000 +0100 @@ -2,3 +2,4 @@ recursive-include thriftpy2/protocol/cybin *.pyx *.c *.h recursive-include thriftpy2/transport *.pyx *.pxd *.c include thriftpy2/contrib/tracking/tracking.thrift +recursive-include tests/ * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/tests/compatible/version_2/tracking.py new/thriftpy2-0.4.11/tests/compatible/version_2/tracking.py --- old/thriftpy2-0.4.10/tests/compatible/version_2/tracking.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/tests/compatible/version_2/tracking.py 2020-03-17 04:48:19.000000000 +0100 @@ -192,7 +192,8 @@ result.success = call() except Exception as e: # raise if api don't have throws - self.handle_exception(e, result) + if not self.handle_exception(e, result): + raise if not result.oneway: self.send_result(oprot, api, result, seqid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/tests/test_aio.py new/thriftpy2-0.4.11/tests/test_aio.py --- old/thriftpy2-0.4.10/tests/test_aio.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/tests/test_aio.py 2020-03-17 04:48:19.000000000 +0100 @@ -4,6 +4,7 @@ # import uvloop import threading import random +from unittest.mock import patch # asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) @@ -49,6 +50,9 @@ @asyncio.coroutine def remove(self, name): + if not name: + # undeclared exception + raise ValueError('name cannot be empty') try: self.ab.people.pop(name) return True @@ -151,7 +155,7 @@ addressbook.AddressBookService, trans_factory=self.TRANSPORT_FACTORY, proto_factory=self.PROTOCOL_FACTORY, - socket_timeout=timeout, + timeout=timeout, **self.client_kwargs(), ) @@ -210,6 +214,13 @@ c.close() @pytest.mark.asyncio + async def test_undeclared_exception(self): + c = await self.client() + with pytest.raises(TTransportException): + await c.remove('') + c.close() + + @pytest.mark.asyncio async def test_client_socket_timeout(self): c = await self.client(timeout=500) with pytest.raises(asyncio.TimeoutError): @@ -246,7 +257,7 @@ addressbook.AddressBookService, trans_factory=self.TRANSPORT_FACTORY, proto_factory=self.PROTOCOL_FACTORY, - socket_timeout=timeout, + timeout=timeout, **kw, ) @@ -304,3 +315,57 @@ connect_timeout=1000 ) await c.hello('test') + + +class TestDeprecatedTimeoutKwarg: + """ + Replace TAsyncSocket with a Mock object that raises a RuntimeError + when called. This allows us to check that timeout vs. socket_timeout + arguments are properly handled without actually creating the client. + + This class should be removed when the socket_timeout argument is removed. + """ + def setup(self): + # Create and apply a fresh patch for each test. + self.async_sock = patch( + 'thriftpy2.contrib.aio.rpc.TAsyncSocket', + side_effect=RuntimeError, + ).__enter__() + + def teardown_(self): + self.async_sock.__exit__() # Clean up patch + + @pytest.mark.asyncio + async def test_no_timeout_given(self): + await self._make_client() + assert self._given_timeout() == 3000 # Default value + + @pytest.mark.asyncio + async def test_timeout_given(self): + await self._make_client(timeout=1234) + assert self._given_timeout() == 1234 + + @pytest.mark.asyncio + async def test_socket_timeout_given(self): + await self._make_client(warning=DeprecationWarning, socket_timeout=555) + assert self._given_timeout() == 555 + + @staticmethod + async def _make_client(warning=None, **kwargs): + """ + Helper method to create the client and check that the proper warning + is emitted (if any) and that the patch is properly applied by + consuming the RuntimeError. + """ + with pytest.warns(warning),\ + pytest.raises(RuntimeError): # Consume error + await make_aio_client(addressbook.AddressBookService, **kwargs) + + def _given_timeout(self): + """Get the timeout provided to TAsyncSocket.""" + try: + self.async_sock.assert_called_once() + except AttributeError: # Python 3.5 + assert self.async_sock.call_count == 1 + _args, kwargs = self.async_sock.call_args + return kwargs['socket_timeout'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/tests/test_tornado.py new/thriftpy2-0.4.11/tests/test_tornado.py --- old/thriftpy2-0.4.10/tests/test_tornado.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/tests/test_tornado.py 2020-03-17 04:48:19.000000000 +0100 @@ -13,6 +13,7 @@ import thriftpy2 from thriftpy2.tornado import make_client from thriftpy2.tornado import make_server +from thriftpy2.transport import TTransportException logging.basicConfig(level=logging.INFO) @@ -39,6 +40,9 @@ """ Person get(1: string name) throws (1: PersonNotExistsError not_exists); """ + if not name: + # undeclared exception + raise ValueError('name cannot be empty') if name not in self.registry: raise addressbook.PersonNotExistsError( 'Person "{}" does not exist!'.format(name)) @@ -51,6 +55,9 @@ """ # delay action for later yield gen.Task(self.io_loop.add_callback) + if not name: + # undeclared exception + raise ValueError('name cannot be empty') if name not in self.registry: raise addressbook.PersonNotExistsError( 'Person "{}" does not exist!'.format(name)) @@ -128,6 +135,17 @@ @testing.gen_test @pytest.mark.skipif(sys.version_info[:2] == (2, 6), reason="not support") + def test_synchronous_undeclared_exception(self): + exc = None + try: + yield self.client.get('') + except Exception as e: + exc = e + + assert isinstance(exc, TTransportException) + + @testing.gen_test + @pytest.mark.skipif(sys.version_info[:2] == (2, 6), reason="not support") def test_asynchronous_result(self): dennis = addressbook.Person(name='Dennis Ritchie') yield self.client.add(dennis) @@ -143,3 +161,13 @@ except Exception as e: exc = e assert isinstance(exc, addressbook.PersonNotExistsError) + + @testing.gen_test + @pytest.mark.skipif(sys.version_info[:2] == (2, 6), reason="not support") + def test_asynchronous_undeclared_exception(self): + exc = None + try: + yield self.client.remove('') + except Exception as e: + exc = e + assert isinstance(exc, TTransportException) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/tests/test_tracking.py new/thriftpy2-0.4.11/tests/test_tracking.py --- old/thriftpy2-0.4.10/tests/test_tracking.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/tests/test_tracking.py 2020-03-17 04:48:19.000000000 +0100 @@ -50,6 +50,13 @@ TrackerBase as TrackerBaseV2, ) +try: + from pytest_cov.embed import cleanup_on_sigterm +except ImportError: + pass +else: + cleanup_on_sigterm() + addressbook = thriftpy2.load(os.path.join(os.path.dirname(__file__), "addressbook.thrift")) _, db_file = tempfile.mkstemp() @@ -135,6 +142,9 @@ return True def get(self, name): + if not name: + # undeclared exception + raise ValueError('name cannot be empty') raise addressbook.PersonNotExistsError() @@ -161,9 +171,9 @@ pass except Exception: raise - - itrans.close() - otrans.close() + finally: + itrans.close() + otrans.close() def gen_server(port, tracker=tracker, processor=TTrackedProcessor): @@ -188,6 +198,7 @@ def fin(): if ps.is_alive(): ps.terminate() + ps.join() request.addfinalizer(fin) return ser @@ -201,6 +212,7 @@ def fin(): if ps.is_alive(): ps.terminate() + ps.join() request.addfinalizer(fin) return ser @@ -214,6 +226,7 @@ def fin(): if ps.is_alive(): ps.terminate() + ps.join() request.addfinalizer(fin) return ser @@ -227,6 +240,7 @@ def fin(): if ps.is_alive(): ps.terminate() + ps.join() request.addfinalizer(fin) return ser @@ -241,6 +255,7 @@ def fin(): if ps.is_alive(): ps.terminate() + ps.join() request.addfinalizer(fin) return ser @@ -368,6 +383,12 @@ assert header["status"] is False +def test_undeclared_exception(server, dbm_db, tracker_ctx): + with pytest.raises(TTransportException): + with client() as c: + c.get('') + + def test_request_id_func(): ctx.__dict__.clear() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/__init__.py new/thriftpy2-0.4.11/thriftpy2/__init__.py --- old/thriftpy2-0.4.10/thriftpy2/__init__.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/__init__.py 2020-03-17 04:48:19.000000000 +0100 @@ -5,7 +5,7 @@ from .hook import install_import_hook, remove_import_hook from .parser import load, load_module, load_fp -__version__ = '0.4.10' +__version__ = '0.4.11' __python__ = sys.version_info __all__ = ["install_import_hook", "remove_import_hook", "load", "load_module", "load_fp"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/contrib/aio/processor.py new/thriftpy2-0.4.11/thriftpy2/contrib/aio/processor.py --- old/thriftpy2-0.4.10/thriftpy2/contrib/aio/processor.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/contrib/aio/processor.py 2020-03-17 04:48:19.000000000 +0100 @@ -54,9 +54,8 @@ _, exc_name, exc_cls, _ = result.thrift_spec[k] if isinstance(e, exc_cls): setattr(result, exc_name, e) - break - else: - raise + return True + return False @asyncio.coroutine def process(self, iprot, oprot): @@ -69,7 +68,8 @@ result.success = yield from call() except Exception as e: # raise if api don't have throws - self.handle_exception(e, result) + if not self.handle_exception(e, result): + raise if not result.oneway: yield from self.send_result(oprot, api, result, seqid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/contrib/aio/rpc.py new/thriftpy2-0.4.11/thriftpy2/contrib/aio/rpc.py --- old/thriftpy2-0.4.10/thriftpy2/contrib/aio/rpc.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/contrib/aio/rpc.py 2020-03-17 04:48:19.000000000 +0100 @@ -18,15 +18,22 @@ from .server import TAsyncServer - @asyncio.coroutine def make_client(service, host='localhost', port=9090, unix_socket=None, proto_factory=TAsyncBinaryProtocolFactory(), trans_factory=TAsyncBufferedTransportFactory(), - socket_timeout=3000, connect_timeout=None, + timeout=3000, connect_timeout=None, cafile=None, ssl_context=None, certfile=None, keyfile=None, - validate=True, url=''): + validate=True, url='', + socket_timeout=None): + if socket_timeout is not None: + warnings.warn( + "The 'socket_timeout' argument is deprecated. " + "Please use 'timeout' instead.", + DeprecationWarning, + ) + timeout = socket_timeout if url: parsed_url = urllib.parse.urlparse(url) host = parsed_url.hostname or host @@ -34,15 +41,15 @@ if unix_socket: socket = TAsyncSocket(unix_socket=unix_socket, connect_timeout=connect_timeout, - socket_timeout=socket_timeout) + socket_timeout=timeout) if certfile: warnings.warn("SSL only works with host:port, not unix_socket.") elif host and port: - socket = TAsyncSocket( - host, port, - socket_timeout=socket_timeout, connect_timeout=connect_timeout, - cafile=cafile, ssl_context=ssl_context, - certfile=certfile, keyfile=keyfile, validate=validate) + socket = TAsyncSocket( + host, port, + socket_timeout=timeout, connect_timeout=connect_timeout, + cafile=cafile, ssl_context=ssl_context, + certfile=certfile, keyfile=keyfile, validate=validate) else: raise ValueError("Either host/port or unix_socket or url must be provided.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/contrib/tracking/__init__.py new/thriftpy2-0.4.11/thriftpy2/contrib/tracking/__init__.py --- old/thriftpy2-0.4.10/thriftpy2/contrib/tracking/__init__.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/contrib/tracking/__init__.py 2020-03-17 04:48:19.000000000 +0100 @@ -211,7 +211,8 @@ result.success = call() except Exception as e: # raise if api don't have throws - self.handle_exception(e, result) + if not self.handle_exception(e, result): + raise if not result.oneway: if self.check_version( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/http.py new/thriftpy2-0.4.11/thriftpy2/http.py --- old/thriftpy2-0.4.10/thriftpy2/http.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/http.py 2020-03-17 04:48:19.000000000 +0100 @@ -54,23 +54,10 @@ from thriftpy2.thrift import TProcessor, TClient from thriftpy2.server import TServer -from thriftpy2.transport import ( - TTransportBase, - TMemoryBuffer -) -# Explicitly use Python version instead of Cython version for libraries below -# to address some mystery issues for now. -# -# Avoid TypeError: Cannot convert TBufferedTransport to -# thriftpy2.transport.cybase.CyTransportBase. -from thriftpy2.protocol.binary import TBinaryProtocolFactory -# Avoid raised error of too small buffer allocated by TCyBufferedTransport. -# Also, using TCyBufferedTransportFactory will let THttpClient write a broken -# string to server, which making server freezed in transport.readall() method. -from thriftpy2.transport.buffered import ( - TBufferedTransport, - TBufferedTransportFactory, -) +from thriftpy2.transport import TTransportBase, TMemoryBuffer + +from thriftpy2.protocol import TBinaryProtocolFactory +from thriftpy2.transport import TBufferedTransportFactory HTTP_URI = '{scheme}://{host}:{port}{path}' @@ -120,6 +107,7 @@ def __init__(self, processor, server_address, + itrans_factory, iprot_factory, server_class=http_server.HTTPServer): """Set up protocol factories and HTTP server. @@ -127,7 +115,8 @@ See TServer for protocol factories. """ TServer.__init__(self, processor, trans=None, - itrans_factory=None, iprot_factory=iprot_factory, + itrans_factory=itrans_factory, + iprot_factory=iprot_factory, otrans_factory=None, oprot_factory=None) thttpserver = self @@ -137,12 +126,18 @@ def do_POST(self): # Don't care about the request path. - itrans = TFileObjectTransport(self.rfile) - otrans = TFileObjectTransport(self.wfile) - itrans = TBufferedTransport( - itrans, int(self.headers['Content-Length'])) - otrans = TMemoryBuffer() + # Pre-read all of the data into a BytesIO. Buffered transport + # was previously configured to read everything on the first + # consumption, but that was a hack relying on the internal + # mechanism and prevents other transports from working, so + # replicate that properly to prevent timeout issues + content_len = int(self.headers['Content-Length']) + buf = BytesIO(self.rfile.read(content_len)) + itrans = TFileObjectTransport(buf) + itrans = thttpserver.itrans_factory.get_transport(itrans) iprot = thttpserver.iprot_factory.get_protocol(itrans) + + otrans = TMemoryBuffer() oprot = thttpserver.oprot_factory.get_protocol(otrans) try: thttpserver.processor.process(iprot, oprot) @@ -222,13 +217,16 @@ self.__wbuf.write(buf) def flush(self): - if self.isOpen(): - self.close() - self.open() - # Pull data out of buffer + # Do this before opening a new connection in case there isn't data data = self.__wbuf.getvalue() self.__wbuf = BytesIO() + if not data: # No data to flush, ignore + return + + if self.isOpen(): + self.close() + self.open() # HTTP request self.__http.putrequest('POST', self.path, skip_host=True) @@ -323,8 +321,10 @@ def make_server(service, handler, host, port, - proto_factory=TBinaryProtocolFactory()): + proto_factory=TBinaryProtocolFactory(), + trans_factory=TBufferedTransportFactory()): processor = TProcessor(service, handler) server = THttpServer(processor, (host, port), + itrans_factory=trans_factory, iprot_factory=proto_factory) return server diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/protocol/cybin/cybin.pyx new/thriftpy2-0.4.11/thriftpy2/protocol/cybin/cybin.pyx --- old/thriftpy2-0.4.10/thriftpy2/protocol/cybin/cybin.pyx 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/protocol/cybin/cybin.pyx 2020-03-17 04:48:19.000000000 +0100 @@ -460,7 +460,7 @@ write_i32(self.trans, seqid) def write_message_end(self): - self.trans.c_flush() + pass def read_struct(self, obj): try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/tornado.py new/thriftpy2-0.4.11/thriftpy2/tornado.py --- old/thriftpy2-0.4.10/thriftpy2/tornado.py 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/tornado.py 2020-03-17 04:48:19.000000000 +0100 @@ -211,7 +211,8 @@ result.success = yield gen.maybe_future(call()) except Exception as e: # raise if api don't have throws - self._processor.handle_exception(e, result) + if not self._processor.handle_exception(e, result): + raise self._processor.send_result(oprot, api, result, seqid) except Exception: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/thriftpy2-0.4.10/thriftpy2/transport/buffered/cybuffered.pyx new/thriftpy2-0.4.11/thriftpy2/transport/buffered/cybuffered.pyx --- old/thriftpy2-0.4.10/thriftpy2/transport/buffered/cybuffered.pyx 2020-01-01 06:31:05.000000000 +0100 +++ new/thriftpy2-0.4.11/thriftpy2/transport/buffered/cybuffered.pyx 2020-03-17 04:48:19.000000000 +0100 @@ -52,7 +52,7 @@ int r if cap < sz: - self.c_flush() + self.c_dump_wbuf() r = self.wbuf.write(sz, data) if r == -1: @@ -74,11 +74,14 @@ raise MemoryError("grow read buffer fail") cdef c_flush(self): + self.c_dump_wbuf() + self.trans.flush() + + cdef c_dump_wbuf(self): cdef bytes data if self.wbuf.data_size > 0: data = self.wbuf.buf[:self.wbuf.data_size] self.trans.write(data) - self.trans.flush() self.wbuf.clean() def getvalue(self):