Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-thriftpy2 for 
openSUSE:Factory checked in at 2024-03-13 22:18:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-thriftpy2 (Old)
 and      /work/SRC/openSUSE:Factory/.python-thriftpy2.new.1770 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-thriftpy2"

Wed Mar 13 22:18:02 2024 rev:9 rq:1157069 version:0.4.20

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-thriftpy2/python-thriftpy2.changes        
2023-08-14 22:35:27.084298510 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-thriftpy2.new.1770/python-thriftpy2.changes  
    2024-03-13 22:18:56.985092187 +0100
@@ -1,0 +2,15 @@
+Tue Mar 12 01:03:03 UTC 2024 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Update to 0.4.20:
+  * Fix another compatibility issue with legacy Python.
+  * Fix a compatibility issue with legacy Python.
+  * Make the import hook compatible with Python3.12.
+  * Added a ``strict_decode`` option to all protocols to force all
+    strings in the response to be decoded to ``str``.
+  * Allow annotations in the ``Union`` type.
+  * Fixed the ``message_type`` in oneway request.
+  * Fix Cython build error in latest Python3 version
+- Drop restriction on Cython.
+- Switch to pyproject macros.
+
+-------------------------------------------------------------------

Old:
----
  v0.4.16.tar.gz

New:
----
  v0.4.20.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-thriftpy2.spec ++++++
--- /var/tmp/diff_new_pack.ZFjEUC/_old  2024-03-13 22:18:58.161135541 +0100
+++ /var/tmp/diff_new_pack.ZFjEUC/_new  2024-03-13 22:18:58.165135688 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-thriftpy2
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,23 +17,24 @@
 
 
 Name:           python-thriftpy2
-Version:        0.4.16
+Version:        0.4.20
 Release:        0
 Summary:        Pure python implementation of Apache Thrift
 License:        MIT
-Group:          Development/Languages/Python
 URL:            https://github.com/Thriftpy/thriftpy2
 Source0:        
https://github.com/Thriftpy/thriftpy2/archive/v%{version}.tar.gz
 Source1:        new_certs.tar.xz
-BuildRequires:  %{python_module Cython >= 0.28.4 with %python-Cython < 3}
+BuildRequires:  %{python_module Cython}
 BuildRequires:  %{python_module dbm}
 BuildRequires:  %{python_module devel}
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module ply >= 3.4}
 BuildRequires:  %{python_module pytest >= 2.8}
 BuildRequires:  %{python_module pytest-asyncio}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module six}
 BuildRequires:  %{python_module tornado >= 5.0}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 BuildRequires:  python3-pytest-asyncio
@@ -54,10 +55,10 @@
 
 %build
 export CFLAGS="%{optflags}"
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitearch}
 %{python_expand # remove devel files
 find %{buildroot}%{$python_sitearch} -name '*.h' -exec rm {} \;
@@ -74,5 +75,5 @@
 %license LICENSE
 %doc CHANGES.rst README.rst
 %{python_sitearch}/thriftpy2
-%{python_sitearch}/thriftpy2-%{version}*-info
+%{python_sitearch}/thriftpy2-%{version}.dist-info
 

++++++ v0.4.16.tar.gz -> v0.4.20.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/thriftpy2-0.4.16/.github/workflows/python-package.yml 
new/thriftpy2-0.4.20/.github/workflows/python-package.yml
--- old/thriftpy2-0.4.16/.github/workflows/python-package.yml   2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/.github/workflows/python-package.yml   2024-02-28 
11:00:33.000000000 +0100
@@ -12,11 +12,11 @@
 jobs:
   build:
 
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
+        python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
 
     steps:
     - uses: actions/checkout@v3
@@ -27,7 +27,7 @@
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        python -m pip install flake8 pytest pytest-asyncio
+        python -m pip install flake8 pytest pytest-asyncio cython
         if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
     - name: Lint with flake8
       run: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/.gitignore 
new/thriftpy2-0.4.20/.gitignore
--- old/thriftpy2-0.4.16/.gitignore     2022-11-15 10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/.gitignore     2024-02-28 11:00:33.000000000 +0100
@@ -49,3 +49,5 @@
 
 pyvenv.cfg
 share/*
+
+venv
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/CHANGES.rst 
new/thriftpy2-0.4.20/CHANGES.rst
--- old/thriftpy2-0.4.16/CHANGES.rst    2022-11-15 10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/CHANGES.rst    2024-02-28 11:00:33.000000000 +0100
@@ -3,15 +3,41 @@
 
 0.4.x
 ~~~~~
+
+Version 0.4.20
+--------------
+
+- Fix another compatibility issue with legacy Python.
+
+Version 0.4.19
+--------------
+
+- Fix a compatibility issue with legacy Python.
+
+Version 0.4.18
+--------------
+
+- Make the import hook compatible with Python3.12.
+- Added a ``strict_decode`` option to all protocols to force all strings in 
the response to be decoded to ``str``.
+- Allow annotations in the ``Union`` type.
+- Fixed the ``message_type`` in oneway request.
+
+Version 0.4.17
+--------------
+
+Released on Sep 27, 2023.
+
+- Fix Cython build error in latest Python3 version
+
 Version 0.4.16
--------------
+--------------
 
 Released on Nov 15, 2022.
 
 - Fix unexpected binary type id in TBinaryTransport serialization
 
 Version 0.4.15
--------------
+--------------
 
 Released on Nov 8, 2021.
 
@@ -20,7 +46,7 @@
 - Fix some socket leaking cases in aio support
 
 Version 0.4.14
--------------
+--------------
 
 Released on Jan 21, 2021.
 
@@ -29,7 +55,7 @@
 .. _2-#157: https://github.com/Thriftpy/thriftpy2/pull/157
 
 Version 0.4.13
--------------
+--------------
 
 Released on Jan 19, 2021.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/pyproject.toml 
new/thriftpy2-0.4.20/pyproject.toml
--- old/thriftpy2-0.4.16/pyproject.toml 1970-01-01 01:00:00.000000000 +0100
+++ new/thriftpy2-0.4.20/pyproject.toml 2024-02-28 11:00:33.000000000 +0100
@@ -0,0 +1,2 @@
+[build-system]
+requires = ["setuptools", "cython>=0.28.4,<4"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/setup.py 
new/thriftpy2-0.4.20/setup.py
--- old/thriftpy2-0.4.16/setup.py       2022-11-15 10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/setup.py       2024-02-28 11:00:33.000000000 +0100
@@ -19,7 +19,8 @@
 ]
 
 tornado_requires = [
-    "tornado>=4.0,<6.0",
+    "tornado>=4.0,<7.0; python_version>='3.12'",
+    "tornado>=4.0,<6.0; python_version<'3.12'",
 ]
 
 try:
@@ -31,7 +32,6 @@
     pass
 
 dev_requires = [
-    "cython>=0.28.4",
     "flake8>=2.5",
     "pytest>=2.8",
     "sphinx-rtd-theme>=0.1.9",
@@ -40,13 +40,6 @@
 ] + tornado_requires
 
 
-# cython detection
-try:
-    from Cython.Build import cythonize
-    CYTHON = True
-except ImportError:
-    CYTHON = False
-
 cmdclass = {}
 ext_modules = []
 
@@ -56,11 +49,10 @@
 
 # only build ext in CPython with UNIX platform
 if UNIX and not PYPY:
-    # rebuild .c files if cython available
-    if CYTHON:
-        cythonize("thriftpy2/transport/cybase.pyx")
-        cythonize("thriftpy2/transport/**/*.pyx")
-        cythonize("thriftpy2/protocol/cybin/cybin.pyx")
+    from Cython.Build import cythonize
+    cythonize("thriftpy2/transport/cybase.pyx")
+    cythonize("thriftpy2/transport/**/*.pyx")
+    cythonize("thriftpy2/protocol/cybin/cybin.pyx")
 
     ext_modules.append(Extension("thriftpy2.transport.cybase",
                                  ["thriftpy2/transport/cybase.c"]))
@@ -106,7 +98,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",
@@ -114,6 +105,7 @@
           "Programming Language :: Python :: 3.9",
           "Programming Language :: Python :: 3.10",
           "Programming Language :: Python :: 3.11",
+          "Programming Language :: Python :: 3.12",
           "Programming Language :: Python :: Implementation :: CPython",
           "Programming Language :: Python :: Implementation :: PyPy",
       ])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/oneway.thrift 
new/thriftpy2-0.4.20/tests/oneway.thrift
--- old/thriftpy2-0.4.16/tests/oneway.thrift    1970-01-01 01:00:00.000000000 
+0100
+++ new/thriftpy2-0.4.20/tests/oneway.thrift    2024-02-28 11:00:33.000000000 
+0100
@@ -0,0 +1,3 @@
+service echo {
+    oneway void Test(1: string req)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/thriftpy2-0.4.16/tests/parser-cases/annotations.thrift 
new/thriftpy2-0.4.20/tests/parser-cases/annotations.thrift
--- old/thriftpy2-0.4.16/tests/parser-cases/annotations.thrift  2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/tests/parser-cases/annotations.thrift  2024-02-28 
11:00:33.000000000 +0100
@@ -19,6 +19,8 @@
 
 typedef list<i32> ( cpp.template = "std::list" ) int_linked_list
 
+const string id = "id" (name="LANG_ID");
+
 struct foo {
   1: i32 bar ( presence = "required" );
   2: i32 baz ( presence = "manual", cpp.use_pointer = "", );
@@ -53,3 +55,7 @@
   void foo() ( foo = "bar" )
 } (a.b="c")
 
+union foo_union {
+   1: optional bool abc
+   2: optional i32 xyz
+}  (a.b="c")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_aio.py 
new/thriftpy2-0.4.20/tests/test_aio.py
--- old/thriftpy2-0.4.16/tests/test_aio.py      2022-11-15 10:41:16.000000000 
+0100
+++ new/thriftpy2-0.4.20/tests/test_aio.py      2024-02-28 11:00:33.000000000 
+0100
@@ -316,14 +316,14 @@
 
     This class should be removed when the socket_timeout argument is removed.
     """
-    def setup(self):
+    def setup_method(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):
+    def teardown_method(self):
         self.async_sock.__exit__()  # Clean up patch
 
     @pytest.mark.asyncio
@@ -348,9 +348,13 @@
         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)
+        if warning:
+            with pytest.warns(warning),\
+                    pytest.raises(RuntimeError):  # Consume error
+                await make_aio_client(addressbook.AddressBookService, **kwargs)
+        else:
+            with pytest.raises(RuntimeError):  # Consume error
+                await make_aio_client(addressbook.AddressBookService, **kwargs)
 
     def _given_timeout(self):
         """Get the timeout provided to TAsyncSocket."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_aio_protocol_binary.py 
new/thriftpy2-0.4.20/tests/test_aio_protocol_binary.py
--- old/thriftpy2-0.4.16/tests/test_aio_protocol_binary.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/thriftpy2-0.4.20/tests/test_aio_protocol_binary.py      2024-02-28 
11:00:33.000000000 +0100
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+
+from io import BytesIO
+
+import pytest
+
+from thriftpy2.thrift import TType, TPayload
+from thriftpy2.contrib.aio.protocol import binary as proto
+
+
+class TItem(TPayload):
+    thrift_spec = {
+        1: (TType.I32, "id", False),
+        2: (TType.LIST, "phones", (TType.STRING), False),
+    }
+    default_spec = [("id", None), ("phones", None)]
+
+
+class AsyncBytesIO:
+    def __init__(self, b):
+        self.b = b
+
+    async def read(self, *args, **kwargs):
+        return self.b.read(*args, **kwargs)
+
+
+@pytest.mark.asyncio
+async def test_strict_decode():
+    bs = AsyncBytesIO(BytesIO(b"\x00\x00\x00\x0c\x00"  # there is a redundant 
'\x00'
+                      b"\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c"))
+    with pytest.raises(UnicodeDecodeError):
+        await proto.read_val(bs, TType.STRING, decode_response=True,
+                             strict_decode=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_aio_protocol_compact.py 
new/thriftpy2-0.4.20/tests/test_aio_protocol_compact.py
--- old/thriftpy2-0.4.16/tests/test_aio_protocol_compact.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/thriftpy2-0.4.20/tests/test_aio_protocol_compact.py     2024-02-28 
11:00:33.000000000 +0100
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+
+from io import BytesIO
+
+import pytest
+
+from thriftpy2.thrift import TType, TPayload
+from thriftpy2.contrib.aio.protocol import compact
+from test_aio_protocol_binary import AsyncBytesIO
+
+
+class TItem(TPayload):
+    thrift_spec = {
+        1: (TType.I32, "id", False),
+        2: (TType.LIST, "phones", (TType.STRING), False),
+    }
+    default_spec = [("id", None), ("phones", None)]
+
+
+def gen_proto(bytearray=b''):
+    b = AsyncBytesIO(BytesIO(bytearray))
+    proto = compact.TAsyncCompactProtocol(b)
+    return (b, proto)
+
+
+@pytest.mark.asyncio
+async def test_strict_decode():
+    b, proto = gen_proto(b'\x0c\xe4\xbd\xa0\xe5\xa5\x00'
+                         b'\xbd\xe4\xb8\x96\xe7\x95\x8c')
+    proto.strict_decode = True
+
+    with pytest.raises(UnicodeDecodeError):
+        await proto._read_val(TType.STRING)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_oneway.py 
new/thriftpy2-0.4.20/tests/test_oneway.py
--- old/thriftpy2-0.4.16/tests/test_oneway.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/thriftpy2-0.4.20/tests/test_oneway.py   2024-02-28 11:00:33.000000000 
+0100
@@ -0,0 +1,32 @@
+import multiprocessing
+import thriftpy2
+import time
+from thriftpy2.rpc import make_client, make_server
+
+
+class Dispatcher(object):
+    def Test(self, req):
+        print("Get req msg: %s" % req)
+
+        assert req == "Hello!"
+
+
+class TestOneway(object):
+
+    oneway_thrift = thriftpy2.load("oneway.thrift")
+
+    def setup_class(self):
+        ctx = multiprocessing.get_context("fork")
+        server = make_server(self.oneway_thrift.echo, Dispatcher(), 
'127.0.0.1', 6000)
+        self.p = ctx.Process(target=server.serve)
+        self.p.start()
+        time.sleep(1)  # Wait a second for server to start.
+
+    def teardown_class(self):
+        self.p.terminate()
+
+    def test_echo(self):
+        req = "Hello!"
+        client = make_client(self.oneway_thrift.echo, '127.0.0.1', 6000)
+
+        assert client.Test(req) == None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_parser.py 
new/thriftpy2-0.4.20/tests/test_parser.py
--- old/thriftpy2-0.4.16/tests/test_parser.py   2022-11-15 10:41:16.000000000 
+0100
+++ new/thriftpy2-0.4.20/tests/test_parser.py   2024-02-28 11:00:33.000000000 
+0100
@@ -207,7 +207,7 @@
 def test_e_grammer_error_at_eof():
     with pytest.raises(ThriftGrammerError) as excinfo:
         load('parser-cases/e_grammer_error_at_eof.thrift')
-    assert str(excinfo.value) == 'Grammer error at EOF'
+    assert str(excinfo.value) == 'Grammar error at EOF'
 
 
 def test_e_use_thrift_reserved_keywords():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_protocol_binary.py 
new/thriftpy2-0.4.20/tests/test_protocol_binary.py
--- old/thriftpy2-0.4.16/tests/test_protocol_binary.py  2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/tests/test_protocol_binary.py  2024-02-28 
11:00:33.000000000 +0100
@@ -2,6 +2,8 @@
 
 from io import BytesIO
 
+import pytest
+
 from thriftpy2._compat import u
 from thriftpy2.thrift import TType, TPayload
 from thriftpy2.utils import hexlify
@@ -98,6 +100,14 @@
         bs, TType.STRING, decode_response=False)
 
 
+def test_strict_decode():
+    bs = BytesIO(b"\x00\x00\x00\x0c\x00"  # there is a redundant '\x00'
+                 b"\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c")
+    with pytest.raises(UnicodeDecodeError):
+        proto.read_val(bs, TType.STRING, decode_response=True,
+                       strict_decode=True)
+
+
 def test_write_message_begin():
     b = BytesIO()
     proto.TBinaryProtocol(b).write_message_begin("test", TType.STRING, 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_protocol_compact.py 
new/thriftpy2-0.4.20/tests/test_protocol_compact.py
--- old/thriftpy2-0.4.16/tests/test_protocol_compact.py 2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/tests/test_protocol_compact.py 2024-02-28 
11:00:33.000000000 +0100
@@ -2,6 +2,8 @@
 
 from io import BytesIO
 
+import pytest
+
 from thriftpy2._compat import u
 from thriftpy2.thrift import TType, TPayload
 from thriftpy2.utils import hexlify
@@ -115,6 +117,15 @@
     assert u('你好世界').encode("utf-8") == proto._read_val(TType.STRING)
 
 
+def test_strict_decode():
+    b, proto = gen_proto(b'\x0c\xe4\xbd\xa0\xe5\xa5\x00'
+                         b'\xbd\xe4\xb8\x96\xe7\x95\x8c')
+    proto.strict_decode = True
+
+    with pytest.raises(UnicodeDecodeError):
+        proto._read_val(TType.STRING)
+
+
 def test_pack_bool():
     b, proto = gen_proto()
     proto._write_bool(True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_protocol_cybinary.py 
new/thriftpy2-0.4.20/tests/test_protocol_cybinary.py
--- old/thriftpy2-0.4.16/tests/test_protocol_cybinary.py        2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/tests/test_protocol_cybinary.py        2024-02-28 
11:00:33.000000000 +0100
@@ -147,6 +147,14 @@
         b, TType.STRING, decode_response=False)
 
 
+def test_strict_decode():
+    bs = TCyMemoryBuffer(b"\x00\x00\x00\x0c\x00"  # there is a redundant '\x00'
+                         b"\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c")
+    with pytest.raises(UnicodeDecodeError):
+        proto.read_val(bs, TType.STRING, decode_response=True,
+                       strict_decode=True)
+
+
 def test_write_message_begin():
     trans = TCyMemoryBuffer()
     b = proto.TCyBinaryProtocol(trans)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/tests/test_rpc.py 
new/thriftpy2-0.4.20/tests/test_rpc.py
--- old/thriftpy2-0.4.16/tests/test_rpc.py      2022-11-15 10:41:16.000000000 
+0100
+++ new/thriftpy2-0.4.20/tests/test_rpc.py      2024-02-28 11:00:33.000000000 
+0100
@@ -250,9 +250,8 @@
 
 def test_client_timeout():
     with pytest.raises(socket.timeout):
-        with pytest.warns(UserWarning):  # Deprecated
-            with client(timeout=500) as c:
-                c.sleep(1000)
+        with client(timeout=500) as c:
+            c.sleep(1000)
 
 
 def test_client_socket_timeout():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/__init__.py 
new/thriftpy2-0.4.20/thriftpy2/__init__.py
--- old/thriftpy2-0.4.16/thriftpy2/__init__.py  2022-11-15 10:41:16.000000000 
+0100
+++ new/thriftpy2-0.4.20/thriftpy2/__init__.py  2024-02-28 11:00:33.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.16'
+__version__ = '0.4.20'
 __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.16/thriftpy2/contrib/aio/client.py 
new/thriftpy2-0.4.20/thriftpy2/contrib/aio/client.py
--- old/thriftpy2-0.4.16/thriftpy2/contrib/aio/client.py        2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/contrib/aio/client.py        2024-02-28 
11:00:33.000000000 +0100
@@ -40,7 +40,9 @@
             return await self._recv(_api)
 
     async def _send(self, _api, **kwargs):
-        self._oprot.write_message_begin(_api, TMessageType.CALL, self._seqid)
+        oneway = getattr(getattr(self._service, _api + "_result"), "oneway")
+        msg_type = TMessageType.ONEWAY if oneway else TMessageType.CALL
+        self._oprot.write_message_begin(_api, msg_type, self._seqid)
         args = getattr(self._service, _api + "_args")()
         for k, v in kwargs.items():
             setattr(args, k, v)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/thriftpy2-0.4.16/thriftpy2/contrib/aio/protocol/binary.py 
new/thriftpy2-0.4.20/thriftpy2/contrib/aio/protocol/binary.py
--- old/thriftpy2-0.4.16/thriftpy2/contrib/aio/protocol/binary.py       
2022-11-15 10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/contrib/aio/protocol/binary.py       
2024-02-28 11:00:33.000000000 +0100
@@ -70,7 +70,8 @@
     return k_type, v_type, sz
 
 
-async def read_val(inbuf, ttype, spec=None, decode_response=True):
+async def read_val(inbuf, ttype, spec=None, decode_response=True,
+                   strict_decode=False):
     if ttype == TType.BOOL:
         return bool(unpack_i8(await inbuf.read(1)))
 
@@ -103,7 +104,8 @@
             try:
                 return byte_payload.decode('utf-8')
             except UnicodeDecodeError:
-                pass
+                if strict_decode:
+                    raise
         return byte_payload
 
     elif ttype == TType.SET or ttype == TType.LIST:
@@ -123,7 +125,8 @@
 
         for i in range(sz):
             result.append(
-                await read_val(inbuf, v_type, v_spec, decode_response)
+                await read_val(inbuf, v_type, v_spec, decode_response,
+                               strict_decode)
             )
         return result
 
@@ -153,19 +156,21 @@
             return {}
 
         for i in range(sz):
-            k_val = await read_val(inbuf, k_type, k_spec, decode_response)
-            v_val = await read_val(inbuf, v_type, v_spec, decode_response)
+            k_val = await read_val(inbuf, k_type, k_spec, decode_response,
+                                   strict_decode)
+            v_val = await read_val(inbuf, v_type, v_spec, decode_response,
+                                   strict_decode)
             result[k_val] = v_val
 
         return result
 
     elif ttype == TType.STRUCT:
         obj = spec()
-        await read_struct(inbuf, obj, decode_response)
+        await read_struct(inbuf, obj, decode_response, strict_decode)
         return obj
 
 
-async def read_struct(inbuf, obj, decode_response=True):
+async def read_struct(inbuf, obj, decode_response=True, strict_decode=False):
     while True:
         f_type, fid = await read_field_begin(inbuf)
         if f_type == TType.STOP:
@@ -191,7 +196,7 @@
                 continue
 
         _buf = await read_val(
-            inbuf, f_type, f_container_spec, decode_response)
+            inbuf, f_type, f_container_spec, decode_response, strict_decode)
         setattr(obj, f_name, _buf)
 
 
@@ -239,11 +244,12 @@
 
     def __init__(self, trans,
                  strict_read=True, strict_write=True,
-                 decode_response=True):
+                 decode_response=True, strict_decode=False):
         TAsyncProtocolBase.__init__(self, trans)
         self.strict_read = strict_read
         self.strict_write = strict_write
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     async def skip(self, ttype):
         await skip(self.trans, ttype)
@@ -266,7 +272,8 @@
         pass
 
     async def read_struct(self, obj):
-        return await read_struct(self.trans, obj, self.decode_response)
+        return await read_struct(self.trans, obj, self.decode_response,
+                                 self.strict_decode)
 
     def write_struct(self, obj):
         write_val(self.trans, TType.STRUCT, obj)
@@ -274,15 +281,17 @@
 
 class TAsyncBinaryProtocolFactory(object):
     def __init__(self, strict_read=True, strict_write=True,
-                 decode_response=True):
+                 decode_response=True, strict_decode=False):
         self.strict_read = strict_read
         self.strict_write = strict_write
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def get_protocol(self, trans):
         return TAsyncBinaryProtocol(
             trans,
             self.strict_read,
             self.strict_write,
-            self.decode_response
+            self.decode_response,
+            self.strict_decode,
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/thriftpy2-0.4.16/thriftpy2/contrib/aio/protocol/compact.py 
new/thriftpy2-0.4.20/thriftpy2/contrib/aio/protocol/compact.py
--- old/thriftpy2-0.4.16/thriftpy2/contrib/aio/protocol/compact.py      
2022-11-15 10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/contrib/aio/protocol/compact.py      
2024-02-28 11:00:33.000000000 +0100
@@ -145,7 +145,8 @@
             try:
                 byte_payload = byte_payload.decode('utf-8')
             except UnicodeDecodeError:
-                pass
+                if self.strict_decode:
+                    raise
         return byte_payload
 
     async def _read_bool(self):
@@ -305,11 +306,13 @@
 
 
 class TAsyncCompactProtocolFactory(object):
-    def __init__(self, decode_response=True):
+    def __init__(self, decode_response=True, strict_decode=False):
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def get_protocol(self, trans):
         return TAsyncCompactProtocol(
             trans,
             decode_response=self.decode_response,
+            strict_decode=self.strict_decode,
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/contrib/aio/socket.py 
new/thriftpy2-0.4.20/thriftpy2/contrib/aio/socket.py
--- old/thriftpy2-0.4.16/thriftpy2/contrib/aio/socket.py        2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/contrib/aio/socket.py        2024-02-28 
11:00:33.000000000 +0100
@@ -292,15 +292,25 @@
 
     async def accept(self, callback):
         server = await self.sock_factory(
-            lambda reader, writer: asyncio.wait_for(
-                callback(StreamHandler(reader, writer)),
-                self.client_timeout
-            ),
+            self._create_client_connected_cb(callback),
             sock=self.raw_sock,
             ssl=self.ssl_context
         )
         return server
 
+    def _create_client_connected_cb(self, callback):
+
+        async def client_connected_cb(reader, writer):
+            try:
+                await asyncio.wait_for(
+                    callback(StreamHandler(reader, writer)),
+                    self.client_timeout
+                )
+            except asyncio.exceptions.TimeoutError:
+                writer.close()
+
+        return client_connected_cb
+
     def close(self):
         if not self.raw_sock:
             return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/hook.py 
new/thriftpy2-0.4.20/thriftpy2/hook.py
--- old/thriftpy2-0.4.16/thriftpy2/hook.py      2022-11-15 10:41:16.000000000 
+0100
+++ new/thriftpy2-0.4.20/thriftpy2/hook.py      2024-02-28 11:00:33.000000000 
+0100
@@ -7,21 +7,44 @@
 from .parser import load_module
 
 
-class ThriftImporter(object):
-    def __init__(self, extension="_thrift"):
-        self.extension = extension
-
-    def __eq__(self, other):
-        return self.__class__.__module__ == other.__class__.__module__ and \
-            self.__class__.__name__ == other.__class__.__name__ and \
-            self.extension == other.extension
-
-    def find_module(self, fullname, path=None):
-        if fullname.endswith(self.extension):
-            return self
+# TODO: The load process does not compatible with Python standard, e.g., if the
+# specified thrift file does not exists, it raises FileNotFoundError, and 
skiped
+# the other meta finders in the sys.meta_path.
+if sys.version_info >= (3, 4):
+    import importlib.abc
+    import importlib.util
+
+    class ThriftImporter(importlib.abc.MetaPathFinder):
+        def __init__(self, extension="_thrift"):
+            self.extension = extension
+
+        def find_spec(self, fullname, path, target=None):
+            if not fullname.endswith(self.extension):
+                return None
+            return importlib.util.spec_from_loader(fullname,
+                                                   ThriftLoader(fullname))
+
+
+    class ThriftLoader(importlib.abc.Loader):
+        def __init__(self, fullname):
+            self.fullname = fullname
+
+        def create_module(self, spec):
+            return load_module(self.fullname)
+
+        def exec_module(self, module):
+            pass
+else:
+    class ThriftImporter(object):
+        def __init__(self, extension="_thrift"):
+            self.extension = extension
+
+        def find_module(self, fullname, path=None):
+            if fullname.endswith(self.extension):
+                return self
 
-    def load_module(self, fullname):
-        return load_module(fullname)
+        def load_module(self, fullname):
+            return load_module(fullname)
 
 
 _imp = ThriftImporter()
@@ -29,9 +52,9 @@
 
 def install_import_hook():
     global _imp
-    sys.meta_path[:] = [x for x in sys.meta_path if _imp != x] + [_imp]
+    sys.meta_path[:] = [x for x in sys.meta_path if _imp is not x] + [_imp]
 
 
 def remove_import_hook():
     global _imp
-    sys.meta_path[:] = [x for x in sys.meta_path if _imp != x]
+    sys.meta_path[:] = [x for x in sys.meta_path if _imp is not x]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/parser/__init__.py 
new/thriftpy2-0.4.20/thriftpy2/parser/__init__.py
--- old/thriftpy2-0.4.16/thriftpy2/parser/__init__.py   2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/parser/__init__.py   2024-02-28 
11:00:33.000000000 +0100
@@ -34,7 +34,7 @@
     """
     real_module = bool(module_name)
     thrift = parse(path, module_name, include_dirs=include_dirs,
-                   include_dir=include_dir)
+                   include_dir=include_dir, encoding=encoding)
     if incomplete_type:
         fill_incomplete_ttype(thrift, thrift)
     if real_module:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/parser/exc.py 
new/thriftpy2-0.4.20/thriftpy2/parser/exc.py
--- old/thriftpy2-0.4.16/thriftpy2/parser/exc.py        2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/parser/exc.py        2024-02-28 
11:00:33.000000000 +0100
@@ -2,6 +2,9 @@
 
 from __future__ import absolute_import
 
+import sys
+from warnings import warn
+
 
 class ThriftParserError(Exception):
     pass
@@ -11,5 +14,16 @@
     pass
 
 
-class ThriftGrammerError(ThriftParserError):
+class ThriftGrammarError(ThriftParserError):
     pass
+
+
+if sys.version_info >= (3, 7):
+    def __getattr__(name):
+        if name == "ThriftGrammerError":
+            warn("'ThriftGrammerError' is a typo of 'ThriftGrammarError'", 
DeprecationWarning)
+            return ThriftGrammarError
+
+        raise AttributeError("module %r has no attribute %r" % (__name__, 
name))
+else:
+    ThriftGrammerError = ThriftGrammarError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/parser/parser.py 
new/thriftpy2-0.4.20/thriftpy2/parser/parser.py
--- old/thriftpy2-0.4.16/thriftpy2/parser/parser.py     2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/parser/parser.py     2024-02-28 
11:00:33.000000000 +0100
@@ -13,15 +13,18 @@
 import types
 from ply import lex, yacc
 from .lexer import *  # noqa
-from .exc import ThriftParserError, ThriftGrammerError
+from .exc import ThriftParserError, ThriftGrammarError
 from thriftpy2._compat import urlopen, urlparse, PY3
 from ..thrift import gen_init, TType, TPayload, TException
 
+if not PY3:
+    from io import open
+
 
 def p_error(p):
     if p is None:
-        raise ThriftGrammerError('Grammer error at EOF')
-    raise ThriftGrammerError('Grammer error %r at line %d' %
+        raise ThriftGrammarError('Grammar error at EOF')
+    raise ThriftGrammarError('Grammar error %r at line %d' %
                              (p.value, p.lineno))
 
 
@@ -104,8 +107,8 @@
 
 
 def p_const(p):
-    '''const : CONST field_type IDENTIFIER '=' const_value
-             | CONST field_type IDENTIFIER '=' const_value sep'''
+    '''const : CONST field_type IDENTIFIER '=' const_value type_annotations
+             | CONST field_type IDENTIFIER '=' const_value type_annotations 
sep'''
 
     try:
         val = _cast(p[2], p.lineno(3))(p[5])
@@ -226,7 +229,7 @@
 
 
 def p_union(p):
-    '''union : seen_union '{' field_seq '}' '''
+    '''union : seen_union '{' field_seq '}' type_annotations'''
     val = _fill_in_struct(p[1], p[3])
     _add_thrift_meta('unions', val)
 
@@ -573,7 +576,7 @@
         with open(urlparse(path).netloc + urlparse(path).path) as fh:
             data = fh.read()
     elif len(url_scheme) <= 1:
-        with open(path) as fh:
+        with open(path, encoding=encoding) as fh:
             data = fh.read()
     elif url_scheme in ('http', 'https'):
         data = urlopen(path).read()
@@ -582,8 +585,11 @@
                                 'with path in protocol \'{}\''.format(
                                     url_scheme))
 
-    if PY3 and isinstance(data, bytes):
-        data = data.decode(encoding)
+    if PY3:
+        if isinstance(data, bytes):
+            data = data.decode(encoding)
+    else:
+        data = data.encode(encoding)
 
     if module_name is not None and not module_name.endswith('_thrift'):
         raise ThriftParserError('thriftpy2 can only generate module with '
@@ -661,7 +667,7 @@
         meta = getattr(thrift, '__thrift_meta__')
 
     if key != 'consts' and val.__name__ in [x.__name__ for x in meta[key]]:
-        raise ThriftGrammerError(('\'%s\' type is already defined in '
+        raise ThriftGrammarError(('\'%s\' type is already defined in '
                                   '\'%s\'') % (val.__name__, key))
 
     meta[key].append(val)
@@ -863,7 +869,7 @@
 
     for field in fields:
         if field[0] in thrift_spec or field[3] in _tspec:
-            raise ThriftGrammerError(('\'%d:%s\' field identifier/name has '
+            raise ThriftGrammarError(('\'%d:%s\' field identifier/name has '
                                       'already been used') % (field[0],
                                                               field[3]))
         ttype = field[2]
@@ -895,7 +901,7 @@
     for func in funcs:
         func_name = func[2]
         if func_name in thrift_services:
-            raise ThriftGrammerError(('\'%s\' function is already defined in '
+            raise ThriftGrammarError(('\'%s\' function is already defined in '
                                       'service \'%s\'') % (func_name,
                                                            name))
         # args payload cls
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/protocol/binary.py 
new/thriftpy2-0.4.20/thriftpy2/protocol/binary.py
--- old/thriftpy2-0.4.16/thriftpy2/protocol/binary.py   2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/protocol/binary.py   2024-02-28 
11:00:33.000000000 +0100
@@ -215,7 +215,8 @@
     return k_type, v_type, sz
 
 
-def read_val(inbuf, ttype, spec=None, decode_response=True):
+def read_val(inbuf, ttype, spec=None, decode_response=True,
+             strict_decode=False):
     if ttype == TType.BOOL:
         return bool(unpack_i8(inbuf.read(1)))
 
@@ -248,7 +249,8 @@
             try:
                 return byte_payload.decode('utf-8')
             except UnicodeDecodeError:
-                pass
+                if strict_decode:
+                    raise
         return byte_payload
 
     elif ttype == TType.SET or ttype == TType.LIST:
@@ -267,7 +269,8 @@
             return []
 
         for i in range(sz):
-            result.append(read_val(inbuf, v_type, v_spec, decode_response))
+            result.append(read_val(inbuf, v_type, v_spec, decode_response,
+                                   strict_decode))
         return result
 
     elif ttype == TType.MAP:
@@ -296,19 +299,21 @@
             return {}
 
         for i in range(sz):
-            k_val = read_val(inbuf, k_type, k_spec, decode_response)
-            v_val = read_val(inbuf, v_type, v_spec, decode_response)
+            k_val = read_val(inbuf, k_type, k_spec, decode_response,
+                             strict_decode)
+            v_val = read_val(inbuf, v_type, v_spec, decode_response,
+                             strict_decode)
             result[k_val] = v_val
 
         return result
 
     elif ttype == TType.STRUCT:
         obj = spec()
-        read_struct(inbuf, obj, decode_response)
+        read_struct(inbuf, obj, decode_response, strict_decode)
         return obj
 
 
-def read_struct(inbuf, obj, decode_response=True):
+def read_struct(inbuf, obj, decode_response=True, strict_decode=False):
     while True:
         f_type, fid = read_field_begin(inbuf)
         if f_type == TType.STOP:
@@ -334,7 +339,8 @@
                 continue
 
         setattr(obj, f_name,
-                read_val(inbuf, f_type, f_container_spec, decode_response))
+                read_val(inbuf, f_type, f_container_spec, decode_response,
+                         strict_decode))
 
 
 def skip(inbuf, ftype):
@@ -380,11 +386,12 @@
 
     def __init__(self, trans,
                  strict_read=True, strict_write=True,
-                 decode_response=True):
+                 decode_response=True, strict_decode=False):
         TProtocolBase.__init__(self, trans)
         self.strict_read = strict_read
         self.strict_write = strict_write
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def skip(self, ttype):
         skip(self.trans, ttype)
@@ -405,7 +412,8 @@
         pass
 
     def read_struct(self, obj):
-        return read_struct(self.trans, obj, self.decode_response)
+        return read_struct(self.trans, obj, self.decode_response,
+                           self.strict_decode)
 
     def write_struct(self, obj):
         write_val(self.trans, TType.STRUCT, obj)
@@ -413,12 +421,13 @@
 
 class TBinaryProtocolFactory(object):
     def __init__(self, strict_read=True, strict_write=True,
-                 decode_response=True):
+                 decode_response=True, strict_decode=False):
         self.strict_read = strict_read
         self.strict_write = strict_write
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def get_protocol(self, trans):
         return TBinaryProtocol(trans,
                                self.strict_read, self.strict_write,
-                               self.decode_response)
+                               self.decode_response, self.strict_decode)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/protocol/compact.py 
new/thriftpy2-0.4.20/thriftpy2/protocol/compact.py
--- old/thriftpy2-0.4.16/thriftpy2/protocol/compact.py  2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/protocol/compact.py  2024-02-28 
11:00:33.000000000 +0100
@@ -129,13 +129,14 @@
     TYPE_BITS = 0x07
     TYPE_SHIFT_AMOUNT = 5
 
-    def __init__(self, trans, decode_response=True):
+    def __init__(self, trans, decode_response=True, strict_decode=False):
         TProtocolBase.__init__(self, trans)
         self._last_fid = 0
         self._bool_fid = None
         self._bool_value = None
         self._structs = []
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def _get_ttype(self, byte):
         return TTYPES[byte & 0x0f]
@@ -245,7 +246,8 @@
             try:
                 byte_payload = byte_payload.decode('utf-8')
             except UnicodeDecodeError:
-                pass
+                if self.strict_decode:
+                    raise
         return byte_payload
 
     def _read_bool(self):
@@ -586,8 +588,10 @@
 
 
 class TCompactProtocolFactory(object):
-    def __init__(self, decode_response=True):
+    def __init__(self, decode_response=True, strict_decode=False):
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def get_protocol(self, trans):
-        return TCompactProtocol(trans, decode_response=self.decode_response)
+        return TCompactProtocol(trans, decode_response=self.decode_response,
+                                strict_decode=self.strict_decode)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/protocol/cybin/cybin.pyx 
new/thriftpy2-0.4.20/thriftpy2/protocol/cybin/cybin.pyx
--- old/thriftpy2-0.4.16/thriftpy2/protocol/cybin/cybin.pyx     2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/protocol/cybin/cybin.pyx     2024-02-28 
11:00:33.000000000 +0100
@@ -170,7 +170,8 @@
         c_write_val(buf, v_type, v, v_spec)
 
 
-cdef inline read_struct(CyTransportBase buf, obj, decode_response=True):
+cdef inline read_struct(CyTransportBase buf, obj, decode_response=True,
+                        strict_decode=False):
     cdef dict field_specs = obj.thrift_spec
     cdef int fid
     cdef TType field_type, ttype
@@ -199,7 +200,8 @@
         else:
             spec = field_spec[2]
 
-        setattr(obj, name, c_read_val(buf, ttype, spec, decode_response))
+        setattr(obj, name, c_read_val(buf, ttype, spec, decode_response,
+                                      strict_decode))
 
     return obj
 
@@ -251,16 +253,19 @@
     return py_data
 
 
-cdef inline c_read_string(CyTransportBase buf, int32_t size):
+cdef inline c_read_string(CyTransportBase buf, int32_t size,
+                          strict_decode=False):
     py_data = c_read_binary(buf, size)
     try:
         return (<char *>py_data)[:size].decode("utf-8")
     except:  # noqa
+        if strict_decode:
+            raise
         return py_data
 
 
 cdef c_read_val(CyTransportBase buf, TType ttype, spec=None,
-                decode_response=True):
+                decode_response=True, strict_decode=False):
     cdef int size
     cdef int64_t n
     cdef TType v_type, k_type, orig_type, orig_key_type
@@ -291,7 +296,7 @@
     elif ttype == T_STRING:
         size = read_i32(buf)
         if decode_response:
-            return c_read_string(buf, size)
+            return c_read_string(buf, size, strict_decode)
         else:
             return c_read_binary(buf, size)
 
@@ -311,7 +316,7 @@
                 skip(buf, orig_type)
             return []
 
-        return [c_read_val(buf, v_type, v_spec, decode_response)
+        return [c_read_val(buf, v_type, v_spec, decode_response, strict_decode)
                 for _ in range(size)]
 
     elif ttype == T_MAP:
@@ -345,13 +350,13 @@
             return {}
 
         return {
-            c_read_val(buf, k_type, k_spec, decode_response):
-                c_read_val(buf, v_type, v_spec, decode_response)
+            c_read_val(buf, k_type, k_spec, decode_response, strict_decode):
+                c_read_val(buf, v_type, v_spec, decode_response, strict_decode)
             for _ in range(size)
         }
 
     elif ttype == T_STRUCT:
-        return read_struct(buf, spec(), decode_response)
+        return read_struct(buf, spec(), decode_response, strict_decode)
 
 
 cdef c_write_val(CyTransportBase buf, TType ttype, val, spec=None):
@@ -432,8 +437,9 @@
             skip(buf, f_type)
 
 
-def read_val(CyTransportBase buf, TType ttype, decode_response=True):
-    return c_read_val(buf, ttype, None, decode_response)
+def read_val(CyTransportBase buf, TType ttype, decode_response=True,
+             strict_decode=False):
+    return c_read_val(buf, ttype, None, decode_response, strict_decode)
 
 
 def write_val(CyTransportBase buf, TType ttype, val, spec=None):
@@ -445,13 +451,15 @@
     cdef public bool strict_read
     cdef public bool strict_write
     cdef public bool decode_response
+    cdef public bool strict_decode
 
     def __init__(self, trans, strict_read=True, strict_write=True,
-                 decode_response=True):
+                 decode_response=True, strict_decode=False):
         self.trans = trans
         self.strict_read = strict_read
         self.strict_write = strict_write
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def skip(self, ttype):
         skip(self.trans, <TType>(ttype))
@@ -498,7 +506,8 @@
 
     def read_struct(self, obj):
         try:
-            return read_struct(self.trans, obj, self.decode_response)
+            return read_struct(self.trans, obj, self.decode_response,
+                               self.strict_decode)
         except Exception:
             self.trans.clean()
             raise
@@ -513,11 +522,13 @@
 
 class TCyBinaryProtocolFactory(object):
     def __init__(self, strict_read=True, strict_write=True,
-                 decode_response=True):
+                 decode_response=True, strict_decode=False):
         self.strict_read = strict_read
         self.strict_write = strict_write
         self.decode_response = decode_response
+        self.strict_decode = strict_decode
 
     def get_protocol(self, trans):
         return TCyBinaryProtocol(
-            trans, self.strict_read, self.strict_write, self.decode_response)
+            trans, self.strict_read, self.strict_write, self.decode_response,
+            self.strict_decode)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/thrift.py 
new/thriftpy2-0.4.20/thriftpy2/thrift.py
--- old/thriftpy2-0.4.16/thriftpy2/thrift.py    2022-11-15 10:41:16.000000000 
+0100
+++ new/thriftpy2-0.4.20/thriftpy2/thrift.py    2024-02-28 11:00:33.000000000 
+0100
@@ -219,7 +219,9 @@
             return self._recv(_api)
 
     def _send(self, _api, **kwargs):
-        self._oprot.write_message_begin(_api, TMessageType.CALL, self._seqid)
+        oneway = getattr(getattr(self._service, _api + "_result"), "oneway")
+        msg_type = TMessageType.ONEWAY if oneway else TMessageType.CALL
+        self._oprot.write_message_begin(_api, msg_type, self._seqid)
         args = getattr(self._service, _api + "_args")()
         for k, v in kwargs.items():
             setattr(args, k, v)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/thriftpy2-0.4.16/thriftpy2/transport/cybase.pyx 
new/thriftpy2-0.4.20/thriftpy2/transport/cybase.pyx
--- old/thriftpy2-0.4.16/thriftpy2/transport/cybase.pyx 2022-11-15 
10:41:16.000000000 +0100
+++ new/thriftpy2-0.4.20/thriftpy2/transport/cybase.pyx 2024-02-28 
11:00:33.000000000 +0100
@@ -87,7 +87,7 @@
         if min_size <= self.buf_size:
             return 0
 
-        cdef int multiples = min_size / self.buf_size
+        cdef int multiples = min_size // self.buf_size
         if min_size % self.buf_size != 0:
             multiples += 1
 

Reply via email to