From 655dafb77690041f9b8b221dc6b1d30b3017c27c Mon Sep 17 00:00:00 2001 From: Gregg Donovan Date: Sun, 4 Jan 2026 19:33:06 +0000 Subject: [PATCH] Fix Python 3.12 build issues in thrift Python - Add pyproject.toml with setuptools build requirement for PEP 517 compliance - Replace distutils imports with setuptools equivalents - Use setuptools error names directly (CompileError, ExecError, PlatformError) - Fix macOS header collision with ntohll/htonll macros in endian.h - Add a matrix of MacOS versions (macos-15-intel, macos-14, macos-15, macos-26) - Add a matrix of non-EOL Python versions for testing - Remove MSVC2015 from the test matrix (very old). - Support MSVC2022, the latest in AppVeyor. - Upgrade tornado, twisted, and zope.interface versions to the first that support Python 3.12. - Try to make the test_socket, RunClientServer, and TestServer tests less flaky. This fixes the ModuleNotFoundError: No module named 'distutils' error when building thrift with Python 3.12+. --- .github/workflows/build.yml | 101 +++++++++++- appveyor.yml | 73 ++++++--- build/appveyor/MSVC-appveyor-full.bat | 70 +++++---- build/appveyor/build-libevent.bat | 7 + build/cmake/BoostMacros.cmake | 6 + build/docker/ubuntu-focal/Dockerfile | 7 +- build/docker/ubuntu-jammy/Dockerfile | 17 +-- build/docker/ubuntu-noble/Dockerfile | 17 +-- contrib/fb303/py/setup.py | 6 +- lib/cpp/CMakeLists.txt | 3 + lib/nodejs/test/package-lock.json | 2 +- lib/py/pyproject.toml | 3 + lib/py/setup.py | 19 +-- lib/py/src/ext/endian.h | 4 + lib/py/test/test_socket.py | 7 +- package-lock.json | 212 ++++++++++++++++++++++++-- test/cpp/src/TestServer.cpp | 2 +- test/py.tornado/test_suite.py | 5 +- test/py/RunClientServer.py | 46 +++++- test/py/TestServer.py | 5 +- 20 files changed, 498 insertions(+), 114 deletions(-) create mode 100644 lib/py/pyproject.toml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2b605219f7f..156bb22ba66 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,6 +78,42 @@ jobs: path: compiler/cpp/thrift retention-days: 3 + compiler-macos: + strategy: + matrix: + os: &macos_versions [macos-15-intel, macos-14, macos-15, macos-26] + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6 + + - name: Install dependencies + run: | + brew install automake bison flex boost libevent openssl libtool pkg-config + echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH + + - name: Run bootstrap + run: ./bootstrap.sh + + - name: Run configure + run: ./configure --disable-debug --disable-tests --disable-libs + + - name: Run make + run: make -j$(sysctl -n hw.ncpu) + + - name: Run install + run: sudo make install + + - name: Run thrift version + run: /usr/local/bin/thrift -version + + - name: Archive built thrift compiler (macOS) + uses: actions/upload-artifact@v5 + with: + name: thrift-compiler-${{ matrix.os }} + path: compiler/cpp/thrift + retention-days: 3 + lib-php: needs: compiler runs-on: ubuntu-24.04 @@ -495,8 +531,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python-version: - - "3.13" # Pin to 3.13 for now -> see THRIFT-5900 + python-version: &python_versions ["3.10", "3.11", "3.12", "3.13", "3.14"] fail-fast: false steps: - uses: actions/checkout@v6 @@ -514,7 +549,7 @@ jobs: - name: Python setup run: | - python -m pip install --upgrade pip setuptools wheel flake8 tornado twisted zope.interface + python -m pip install --upgrade pip setuptools wheel flake8 "tornado>=6.3.0" "twisted>=24.3.0" "zope.interface>=6.1" python --version pip --version @@ -553,6 +588,65 @@ jobs: - name: Run make check for python code run: make -C test/py check + lib-python-macos: + needs: compiler-macos + strategy: + matrix: + os: *macos_versions + python-version: *python_versions + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6 + + - name: Install dependencies + run: | + brew install automake bison flex boost libevent openssl libtool pkg-config + echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Python setup + run: | + python -m pip install --upgrade pip setuptools wheel flake8 "tornado>=6.3.0" "twisted>=24.3.0" "zope.interface>=6.1" + python --version + pip --version + + - name: Run bootstrap + run: ./bootstrap.sh + + - name: Run configure + run: ./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-py3/with-py3/') + + - uses: actions/download-artifact@v6 + with: + name: thrift-compiler-${{ matrix.os }} + path: compiler/cpp + + - name: Run thrift-compiler + run: | + chmod a+x compiler/cpp/thrift + compiler/cpp/thrift -version + + - name: Run make for python + run: make -C lib/py + + - name: Run make install for python + run: | + sudo make -C lib/py install PY_PREFIX="$(python -c 'import sys; print(sys.prefix)')" + + - name: Run make for python libs + run: make -C lib/py + + - name: Run make check for python libs + run: make -C lib/py check + + - name: Run make check for python code + run: make -C test/py check + lib-nodejs: needs: compiler runs-on: ubuntu-24.04 @@ -756,4 +850,3 @@ jobs: name: cross-test-log_${{ matrix.server_lang }}-${{ matrix.client_lang }} path: test/log/ retention-days: 3 - diff --git a/appveyor.yml b/appveyor.yml index ff35d520e94..16859122adc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,31 +33,70 @@ branches: #matrix: # fast_finish: true +# See https://www.appveyor.com/docs/windows-images-software/ for available versions. + environment: matrix: - - PROFILE: MSVC2017 + # Python version test matrix (3.10-3.14) using MSVC2022 + - PROFILE: MSVC2022 + PROFILE_CLASS: MSVC + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + PLATFORM: x64 + CONFIGURATION: Release + BUILD_SHARED_LIBS: ON + BOOST_VERSION: 1.89.0 + LIBEVENT_VERSION: 2.1.12 + PYTHON_VERSION: "3.10" + QT_VERSION: 6.9.3 + ZLIB_VERSION: 1.3.1 + + - PROFILE: MSVC2022 PROFILE_CLASS: MSVC - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 PLATFORM: x64 CONFIGURATION: Release BUILD_SHARED_LIBS: ON - BOOST_VERSION: 1.67.0 - LIBEVENT_VERSION: 2.1.8 - PYTHON_VERSION: 3.6 - QT_VERSION: 5.10 - ZLIB_VERSION: 1.2.11 + BOOST_VERSION: 1.89.0 + LIBEVENT_VERSION: 2.1.12 + PYTHON_VERSION: "3.11" + QT_VERSION: 6.9.3 + ZLIB_VERSION: 1.3.1 - - PROFILE: MSVC2015 + - PROFILE: MSVC2022 PROFILE_CLASS: MSVC - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PLATFORM: x86 - CONFIGURATION: Debug - BUILD_SHARED_LIBS: OFF - BOOST_VERSION: 1.62.0 - LIBEVENT_VERSION: 2.0.22 - PYTHON_VERSION: 3.5 - QT_VERSION: 5.8 - ZLIB_VERSION: 1.2.8 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + PLATFORM: x64 + CONFIGURATION: Release + BUILD_SHARED_LIBS: ON + BOOST_VERSION: 1.89.0 + LIBEVENT_VERSION: 2.1.12 + PYTHON_VERSION: "3.12" + QT_VERSION: 6.9.3 + ZLIB_VERSION: 1.3.1 + + - PROFILE: MSVC2022 + PROFILE_CLASS: MSVC + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + PLATFORM: x64 + CONFIGURATION: Release + BUILD_SHARED_LIBS: ON + BOOST_VERSION: 1.89.0 + LIBEVENT_VERSION: 2.1.12 + PYTHON_VERSION: "3.13" + QT_VERSION: 6.9.3 + ZLIB_VERSION: 1.3.1 + + - PROFILE: MSVC2022 + PROFILE_CLASS: MSVC + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + PLATFORM: x64 + CONFIGURATION: Release + BUILD_SHARED_LIBS: ON + BOOST_VERSION: 1.89.0 + LIBEVENT_VERSION: 2.1.12 + PYTHON_VERSION: "3.14" + QT_VERSION: 6.9.3 + ZLIB_VERSION: 1.3.1 - PROFILE: MINGW PROFILE_CLASS: MINGW diff --git a/build/appveyor/MSVC-appveyor-full.bat b/build/appveyor/MSVC-appveyor-full.bat index 2e81fd571e0..d4d2896c651 100644 --- a/build/appveyor/MSVC-appveyor-full.bat +++ b/build/appveyor/MSVC-appveyor-full.bat @@ -31,14 +31,7 @@ SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\..\install\%PROFILE%\%PLATFORM% SET SRCDIR=%APPVEYOR_BUILD_FOLDER% -IF "%PROFILE%" == "MSVC2015" ( - IF "%PLATFORM%" == "x86" ( - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 || EXIT /B - ) ELSE ( - CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 || EXIT /B - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 || EXIT /B - ) -) ELSE IF "%PROFILE%" == "MSVC2017" ( +IF "%PROFILE%" == "MSVC2017" ( IF "%PLATFORM%" == "x86" ( CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" || EXIT /B ) ELSE ( @@ -50,6 +43,12 @@ IF "%PROFILE%" == "MSVC2015" ( ) ELSE ( CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" || EXIT /B ) +) ELSE IF "%PROFILE%" == "MSVC2022" ( + IF "%PLATFORM%" == "x86" ( + CALL "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars32.bat" || EXIT /B + ) ELSE ( + CALL "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" || EXIT /B + ) ) ELSE ( ECHO Unsupported PROFILE=%PROFILE% or PLATFORM=%PLATFORM% EXIT /B 1 @@ -59,16 +58,24 @@ IF "%PROFILE%" == "MSVC2015" ( @ECHO ON :: compiler and generator detection -IF /i "%PLATFORM%" == "x64" SET GENARCH= Win64 -IF "%PROFILE%" == "MSVC2015" ( - SET GENERATOR=Visual Studio 14 2015!GENARCH! - SET COMPILER=vc140 -) ELSE IF "%PROFILE%" == "MSVC2017" ( +:: VS2017 uses "Generator Win64" syntax, VS2019+ use "-A x64" flag +IF /i "%PLATFORM%" == "x64" ( + SET GENARCH= Win64 + SET CMAKE_ARCH_FLAG=-A x64 +) ELSE ( + SET GENARCH= + SET CMAKE_ARCH_FLAG=-A Win32 +) +IF "%PROFILE%" == "MSVC2017" ( SET GENERATOR=Visual Studio 15 2017!GENARCH! SET COMPILER=vc141 + SET CMAKE_ARCH_FLAG= ) ELSE IF "%PROFILE%" == "MSVC2019" ( - SET GENERATOR=Visual Studio 16 2019!GENARCH! + SET GENERATOR=Visual Studio 16 2019 SET COMPILER=vc142 +) ELSE IF "%PROFILE%" == "MSVC2022" ( + SET GENERATOR=Visual Studio 17 2022 + SET COMPILER=vc143 ) ELSE ( ECHO [error] unable to determine the CMake generator and compiler to use from MSVC profile %PROFILE% EXIT /B 1 @@ -96,7 +103,7 @@ IF "%PYTHON_VERSION%" == "" ( IF /i "%PLATFORM%" == "x64" (SET PTEXT=-x64) SET PYTHON_ROOT=C:\Python%PYTHON_VERSION:.=%!PTEXT! SET PATH=!PYTHON_ROOT!\scripts;!PYTHON_ROOT!;!PATH! - SET CMAKE_PYTHON_OPTS=-DPython3_FIND_STRATEGY=LOCATION -DPython3_ROOT=!PYTHON_ROOT! + SET CMAKE_PYTHON_OPTS=-DPython3_FIND_STRATEGY=LOCATION -DPython3_ROOT=!PYTHON_ROOT! -DPython3_EXECUTABLE=!PYTHON_ROOT!\python.exe ) IF "%CONFIGURATION%" == "Debug" (SET ZLIB_LIB_SUFFIX=d) @@ -115,15 +122,15 @@ choco feature enable -n allowGlobalConfirmation || EXIT /B :: Things to install when NOT running in appveyor: IF "%APPVEYOR_BUILD_ID%" == "" ( - cup -y chocolatey || EXIT /B - cinst -y curl || EXIT /B - cinst -y 7zip || EXIT /B - cinst -y python3 || EXIT /B - cinst -y openssl.light || EXIT /B + choco upgrade -y chocolatey || EXIT /B + choco install -y curl || EXIT /B + choco install -y 7zip || EXIT /B + choco install -y python3 || EXIT /B + choco install -y openssl.light || EXIT /B ) -cinst -y jdk8 || EXIT /B -cinst -y winflexbison3 || EXIT /B +choco install -y jdk8 || EXIT /B +choco install -y winflexbison3 || EXIT /B :: zlib - not available through chocolatey CD "%APPVEYOR_SCRIPTS%" || EXIT /B @@ -133,12 +140,17 @@ call build-zlib.bat || EXIT /B CD "%APPVEYOR_SCRIPTS%" || EXIT /B call build-libevent.bat || EXIT /B -:: python packages (correct path to pip set above) -pip.exe ^ - install backports.ssl_match_hostname ^ - ipaddress ^ - tornado ^ - twisted || EXIT /B +:: python packages (ensure we use the configured Python) +IF "%WITH_PYTHON%" == "ON" ( + "!PYTHON_ROOT!\python.exe" -m ensurepip --upgrade || EXIT /B + "!PYTHON_ROOT!\python.exe" -m pip install --upgrade pip setuptools wheel || EXIT /B + "!PYTHON_ROOT!\python.exe" -m pip ^ + install backports.ssl_match_hostname ^ + ipaddress ^ + tornado>=6.3.0 ^ + twisted>=24.3.0 ^ + zope.interface>=6.1 || EXIT /B +) :: Adobe Flex SDK 4.6 for ActionScript MKDIR "C:\Adobe\Flex\SDK\4.6" || EXIT /B @@ -171,7 +183,7 @@ CD "%BUILDDIR%" || EXIT /B :: DIR C:\Libraries\boost_1_60_0\lib* cmake.exe "%SRCDIR%" ^ - -G"%GENERATOR%" ^ + -G"%GENERATOR%" %CMAKE_ARCH_FLAG% ^ -DBISON_EXECUTABLE="C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_bison.exe" ^ -DBOOST_ROOT="%BOOST_ROOT%" ^ -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" ^ diff --git a/build/appveyor/build-libevent.bat b/build/appveyor/build-libevent.bat index 939daf5abde..a2268e28e28 100644 --- a/build/appveyor/build-libevent.bat +++ b/build/appveyor/build-libevent.bat @@ -26,6 +26,13 @@ IF "%APPVEYOR_BUILD_ID%" == "" ( ) 7z x "%URLFILE%" -so | 7z x -si -ttar > nul || EXIT /B CD "libevent-%LIBEVENT_VERSION%-stable" || EXIT /B +:: libevent's nmake config ships with EVENT__HAVE_STDINT_H commented out, +:: but MSVC needs stdint.h for UINT32_MAX in minheap-internal.h. +IF EXIST "WIN32-Code\nmake\event2\event-config.h" ( + powershell -NoProfile -Command "(Get-Content 'WIN32-Code\nmake\event2\event-config.h') -replace '/\* #define EVENT__HAVE_STDINT_H 1 \*/', '#define EVENT__HAVE_STDINT_H 1' | Set-Content 'WIN32-Code\nmake\event2\event-config.h'" +) ELSE IF EXIST "WIN32-Code\event2\event-config.h" ( + powershell -NoProfile -Command "(Get-Content 'WIN32-Code\event2\event-config.h') -replace '/\* #define EVENT__HAVE_STDINT_H 1 \*/', '#define EVENT__HAVE_STDINT_H 1' | Set-Content 'WIN32-Code\event2\event-config.h'" +) nmake -f Makefile.nmake static_libs || EXIT /B :: in libevent 2.0 there is no nmake subdirectory in WIN32-Code, but in 2.1 there is diff --git a/build/cmake/BoostMacros.cmake b/build/cmake/BoostMacros.cmake index 61fac0356bb..ed06760f25d 100644 --- a/build/cmake/BoostMacros.cmake +++ b/build/cmake/BoostMacros.cmake @@ -23,6 +23,12 @@ if(POLICY CMP0167) cmake_policy(SET CMP0167 OLD) endif() +# CMake 3.27+ warns and ignores upper-case _ROOT variables unless +# CMP0144 is set. We pass BOOST_ROOT on Windows builds, so enable NEW behavior. +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif() + # Force using FindBoost instead of Boost's own BoostConfig.cmake. # BoostConfig.cmake does not populate ${Boost_LIBRARIES} the same way, # which causes linking failures on Windows. diff --git a/build/docker/ubuntu-focal/Dockerfile b/build/docker/ubuntu-focal/Dockerfile index 18234bf395a..465c0f1e439 100644 --- a/build/docker/ubuntu-focal/Dockerfile +++ b/build/docker/ubuntu-focal/Dockerfile @@ -261,10 +261,9 @@ RUN apt-get install -y --no-install-recommends \ python3-all-dev \ python3-pip \ python3-setuptools \ - python3-tornado \ - python3-twisted \ - python3-wheel \ - python3-zope.interface + python3-wheel + +RUN python3 -m pip install --no-cache-dir --upgrade "tornado>=6.3.0" "twisted>=24.3.0" "zope.interface>=6.1" RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ diff --git a/build/docker/ubuntu-jammy/Dockerfile b/build/docker/ubuntu-jammy/Dockerfile index 5e83948316a..a2331ab695d 100644 --- a/build/docker/ubuntu-jammy/Dockerfile +++ b/build/docker/ubuntu-jammy/Dockerfile @@ -249,15 +249,14 @@ RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \ `# Python3 dependencies` \ - python3-all \ - python3-all-dbg \ - python3-all-dev \ - python3-pip \ - python3-setuptools \ - python3-tornado \ - python3-twisted \ - python3-wheel \ - python3-zope.interface + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-pip \ + python3-setuptools \ + python3-wheel + +RUN python3 -m pip install --no-cache-dir --upgrade "tornado>=6.3.0" "twisted>=24.3.0" "zope.interface>=6.1" RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ diff --git a/build/docker/ubuntu-noble/Dockerfile b/build/docker/ubuntu-noble/Dockerfile index 86617e009c1..a195fd460b5 100644 --- a/build/docker/ubuntu-noble/Dockerfile +++ b/build/docker/ubuntu-noble/Dockerfile @@ -248,15 +248,14 @@ RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \ `# Python3 dependencies` \ - python3-all \ - python3-all-dbg \ - python3-all-dev \ - python3-pip \ - python3-setuptools \ - python3-tornado \ - python3-twisted \ - python3-wheel \ - python3-zope.interface + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-pip \ + python3-setuptools \ + python3-wheel + +RUN python3 -m pip install --no-cache-dir --upgrade "tornado>=6.3.0" "twisted>=24.3.0" "zope.interface>=6.1" RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ diff --git a/contrib/fb303/py/setup.py b/contrib/fb303/py/setup.py index d27c2962f71..c07cf55ca0a 100644 --- a/contrib/fb303/py/setup.py +++ b/contrib/fb303/py/setup.py @@ -20,10 +20,8 @@ # import sys -try: - from setuptools import setup, Extension -except: - from distutils.core import setup, Extension, Command + +from setuptools import Extension, setup setup(name='thrift_fb303', version='1.0.0', diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt index 5980734f380..d1899227c14 100644 --- a/lib/cpp/CMakeLists.txt +++ b/lib/cpp/CMakeLists.txt @@ -178,6 +178,9 @@ if(WITH_LIBEVENT) else() target_link_libraries(thriftnb PUBLIC ${LIBEVENT_LIBRARIES}) endif() + if(WIN32) + target_link_libraries(thriftnb PUBLIC iphlpapi) + endif() ADD_PKGCONFIG_THRIFT(thrift-nb) endif() diff --git a/lib/nodejs/test/package-lock.json b/lib/nodejs/test/package-lock.json index e7f9543794f..6faee9d05b2 100644 --- a/lib/nodejs/test/package-lock.json +++ b/lib/nodejs/test/package-lock.json @@ -9,7 +9,7 @@ } }, "../../..": { - "version": "0.22.0", + "version": "0.23.0", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/lib/py/pyproject.toml b/lib/py/pyproject.toml new file mode 100644 index 00000000000..b61373e17bf --- /dev/null +++ b/lib/py/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/lib/py/setup.py b/lib/py/setup.py index a02cc4ff1f1..2dd2a77aa32 100644 --- a/lib/py/setup.py +++ b/lib/py/setup.py @@ -20,13 +20,10 @@ # import sys -try: - from setuptools import setup, Extension -except Exception: - from distutils.core import setup, Extension -from distutils.command.build_ext import build_ext -from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError +from setuptools import Extension, setup +from setuptools.command.build_ext import build_ext +from setuptools.errors import CompileError, ExecError, PlatformError # Fix to build sdist under vagrant import os @@ -39,9 +36,9 @@ include_dirs = ['src'] if sys.platform == 'win32': include_dirs.append('compat/win32') - ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOError) + ext_errors = (CompileError, ExecError, PlatformError, IOError) else: - ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError) + ext_errors = (CompileError, ExecError, PlatformError) class BuildFailed(Exception): @@ -52,7 +49,7 @@ class ve_build_ext(build_ext): def run(self): try: build_ext.run(self) - except DistutilsPlatformError: + except PlatformError: raise BuildFailed() def build_extension(self, ext): @@ -99,8 +96,8 @@ def run_setup(with_binary): ssl_deps = [] if sys.hexversion < 0x03050000: ssl_deps.append('backports.ssl_match_hostname>=3.5') - tornado_deps = ['tornado>=4.0'] - twisted_deps = ['twisted'] + tornado_deps = ['tornado>=6.3.0'] + twisted_deps = ['twisted>=24.3.0', 'zope.interface>=6.1'] setup(name='thrift', version='0.23.0', diff --git a/lib/py/src/ext/endian.h b/lib/py/src/ext/endian.h index 8f9e978c38a..bf21a4f105d 100644 --- a/lib/py/src/ext/endian.h +++ b/lib/py/src/ext/endian.h @@ -29,6 +29,7 @@ #else #include +#ifndef ntohll static inline unsigned long long ntohll(unsigned long long n) { union { unsigned long long f; @@ -43,8 +44,11 @@ static inline unsigned long long ntohll(unsigned long long n) { | static_cast(u.t[5]) << 16 | static_cast(u.t[6]) << 8 | static_cast(u.t[7]); } +#endif +#ifndef htonll #define htonll(n) ntohll(n) +#endif #endif // !_WIN32 diff --git a/lib/py/test/test_socket.py b/lib/py/test/test_socket.py index af09515fac3..5e25f1a90bf 100644 --- a/lib/py/test/test_socket.py +++ b/lib/py/test/test_socket.py @@ -18,6 +18,7 @@ # import errno +import time import unittest from test_sslsocket import ServerAcceptor @@ -98,7 +99,11 @@ def test_isOpen_checks_for_readability(self): acc.close() self.assertIsNotNone(sock.handle) - self.assertFalse(sock.isOpen()) + # Give the kernel a moment to propagate FIN before asserting. + deadline = time.monotonic() + 0.5 + while sock.isOpen() and time.monotonic() < deadline: + time.sleep(0.01) + self.assertFalse(sock.isOpen(), "socket still open after 0.5s") # after isOpen() returned False the socket should be closed (THRIFT-5813) self.assertIsNone(sock.handle) diff --git a/package-lock.json b/package-lock.json index d3ce1162f53..21caeb5c819 100644 --- a/package-lock.json +++ b/package-lock.json @@ -707,6 +707,7 @@ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", "dev": true, + "peer": true, "dependencies": { "@types/linkify-it": "*", "@types/mdurl": "*" @@ -747,6 +748,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -935,6 +937,20 @@ "node": ">=8" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1222,6 +1238,21 @@ "node": ">=0.4.0" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1278,6 +1309,55 @@ "node": ">= 0.4" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-to-primitive": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", @@ -1318,6 +1398,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -1377,6 +1458,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", "dev": true, + "peer": true, "bin": { "eslint-config-prettier": "build/bin/cli.js" }, @@ -1830,17 +1912,20 @@ } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" + "node": ">= 6" } }, "node_modules/fromentries": { @@ -1856,10 +1941,14 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gensync": { "version": "1.0.0-beta.1", @@ -1879,6 +1968,45 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -1929,6 +2057,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -1983,12 +2124,32 @@ } }, "node_modules/has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hasha": { @@ -2004,6 +2165,19 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/html-escaper": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", @@ -2693,6 +2867,16 @@ "node": ">= 12" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", @@ -3078,6 +3262,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -3170,7 +3355,7 @@ "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": ">=2.5.5", + "form-data": ">=2.5.5", "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", @@ -3817,6 +4002,7 @@ "version": "5.2.4", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.4.tgz", "integrity": "sha512-fFCejsuC8f9kOSu9FYaOw8CdO68O3h5v0lg4p74o8JqWpwTf9tniOD+nOB78aWoVSS6WptVUmDrp/KPsMVBWFQ==", + "peer": true, "dependencies": { "async-limiter": "~1.0.0" } diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp index dc95af6ba15..7bb40a04534 100644 --- a/test/cpp/src/TestServer.cpp +++ b/test/cpp/src/TestServer.cpp @@ -596,7 +596,7 @@ struct DomainSocketFd { memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; strcpy(sa.sun_path, path.c_str()); - int rv = bind(socket_fd, (struct sockaddr*)&sa, sizeof(sa)); + int rv = ::bind(socket_fd, (struct sockaddr*)&sa, sizeof(sa)); if (rv == -1) { std::ostringstream os; os << "Cannot bind domain socket: " << strerror(errno); diff --git a/test/py.tornado/test_suite.py b/test/py.tornado/test_suite.py index 0ee0a9b85a0..fef09f0b71a 100755 --- a/test/py.tornado/test_suite.py +++ b/test/py.tornado/test_suite.py @@ -37,7 +37,7 @@ sys.exit(0) from tornado import gen -from tornado.testing import AsyncTestCase, get_unused_port, gen_test +from tornado.testing import AsyncTestCase, bind_unused_port, gen_test from thrift import TTornado from thrift.Thrift import TApplicationException @@ -123,7 +123,8 @@ class ThriftTestCase(AsyncTestCase): def setUp(self): super(ThriftTestCase, self).setUp() - self.port = get_unused_port() + sock, self.port = bind_unused_port() + sock.close() # server self.handler = TestHandler(self) diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py index 278f06cc846..809c93bba02 100755 --- a/test/py/RunClientServer.py +++ b/test/py/RunClientServer.py @@ -102,6 +102,14 @@ def runScriptTest(libdir, genbase, genpydir, script): raise Exception("Script subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(script_args))) +def pick_unused_port(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('127.0.0.1', 0)) + port = sock.getsockname()[1] + sock.close() + return port + + def runServiceTest(libdir, genbase, genpydir, server_class, proto, port, use_zlib, use_ssl, verbose): env = setup_pypath(libdir, os.path.join(genbase, genpydir)) # Build command line arguments @@ -129,7 +137,14 @@ def runServiceTest(libdir, genbase, genpydir, server_class, proto, port, use_zli cli_args.append('--http=/') if verbose > 0: print('Testing server %s: %s' % (server_class, ' '.join(server_args))) - serverproc = subprocess.Popen(server_args, env=env) + popen_kwargs = {'env': env} + # Windows uses process groups; POSIX starts a new session so we can killpg(). + if platform.system() == 'Windows': + if hasattr(subprocess, 'CREATE_NEW_PROCESS_GROUP'): + popen_kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP + else: + popen_kwargs['start_new_session'] = True + serverproc = subprocess.Popen(server_args, **popen_kwargs) def ensureServerAlive(): if serverproc.poll() is not None: @@ -169,8 +184,12 @@ def ensureServerAlive(): print('PY_GEN: %s' % genpydir, file=sys.stderr) raise Exception("Client subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(cli_args))) finally: - # check that server didn't die - ensureServerAlive() + # check that server didn't die, but still attempt cleanup + cleanup_exc = None + try: + ensureServerAlive() + except Exception as exc: + cleanup_exc = exc extra_sleep = EXTRA_DELAY.get(server_class, 0) if extra_sleep > 0 and verbose > 0: print('Giving %s (proto=%s,zlib=%s,ssl=%s) an extra %d seconds for child' @@ -178,8 +197,17 @@ def ensureServerAlive(): % (server_class, proto, use_zlib, use_ssl, extra_sleep)) time.sleep(extra_sleep) sig = signal.SIGKILL if platform.system() != 'Windows' else signal.SIGABRT - os.kill(serverproc.pid, sig) + try: + if platform.system() == 'Windows': + os.kill(serverproc.pid, sig) + else: + # POSIX: kill the whole process group to reap forked children. + os.killpg(serverproc.pid, sig) + except OSError: + pass serverproc.wait() + if cleanup_exc: + raise cleanup_exc class TestCases(object): @@ -219,7 +247,8 @@ def run(self, conf, test_count): if self.verbose > 0: print('\nTest run #%d: (includes %s) Server=%s, Proto=%s, zlib=%s, SSL=%s' % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl)) - runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl, self.verbose) + port = self.port if self.port else pick_unused_port() + runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, port, with_zlib, with_ssl, self.verbose) if self.verbose > 0: print('OK: Finished (includes %s) %s / %s proto / zlib=%s / SSL=%s. %d combinations tested.' % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count)) @@ -255,7 +284,8 @@ def run_all_tests(self): if self.verbose > 0: print('\nTest run #%d: (includes %s) Server=%s, Proto=%s, zlib=%s, SSL=%s' % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl)) - runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl) + port = self.port if self.port else pick_unused_port() + runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, port, with_zlib, with_ssl, self.verbose) if self.verbose > 0: print('OK: Finished (includes %s) %s / %s proto / zlib=%s / SSL=%s. %d combinations tested.' % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count)) @@ -268,8 +298,8 @@ def main(): parser.add_option('--genpydirs', type='string', dest='genpydirs', default='default,slots,oldstyle,no_utf8strings,dynamic,dynamicslots,enum,type_hints', help='directory extensions for generated code, used as suffixes for \"gen-py-*\" added sys.path for individual tests') - parser.add_option("--port", type="int", dest="port", default=9090, - help="port number for server to listen on") + parser.add_option("--port", type="int", dest="port", default=0, + help="port number for server to listen on (0 = auto)") parser.add_option('-v', '--verbose', action="store_const", dest="verbose", const=2, help="verbose output") diff --git a/test/py/TestServer.py b/test/py/TestServer.py index 3a2f639c0df..c2723e57d3b 100755 --- a/test/py/TestServer.py +++ b/test/py/TestServer.py @@ -28,6 +28,7 @@ from util import local_libpath sys.path.insert(0, local_libpath()) from thrift.protocol import TProtocol, TProtocolDecorator +from thrift.Thrift import TException SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -328,7 +329,9 @@ def main(options): tfactory = TTransport.TBufferedTransportFactory() # if --zlib, then wrap server transport, and use a different transport factory if options.zlib: - transport = TZlibTransport.TZlibTransport(transport) # wrap with zlib + if server_type != "TProcessPoolServer": + transport = TZlibTransport.TZlibTransport(transport) # wrap with zlib + # Avoid wrapping the server transport for process pools; TZlibTransport isn't picklable on spawn. tfactory = TZlibTransport.TZlibTransportFactory() # do server-specific setup here: