-
Notifications
You must be signed in to change notification settings - Fork 398
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[web] Patch Thrift deprecation for Python >=3.12
All of the currently available versions of Thrift use Python code that is deprected and gives an error when run on Python >=3.12. This change manually fixes the installed Thrift package. NOTE: This is a HACK and should be removed as soon as Thrift creates an updated version and CodeChecker is ported to use that version.
- Loading branch information
Showing
4 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
*.py[cod] | ||
|
||
build | ||
!/scripts/build | ||
build_dist | ||
venv | ||
venv_dev | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
This script applies a patch to the Thrift library used in CodeChecker. | ||
### Purpose: | ||
The Thrift library (used by CodeChecker) includes deprecated Python files in | ||
its implementation. | ||
This script patches those files to ensure compatibility with Python 3.12. | ||
### How It Works: | ||
- It takes the CodeChecker root directory as an argument. | ||
- It determines the Thrift installation path in the virtualenv. | ||
- It applies a predefined Git patch to the relevant files using a relative path. | ||
### When to Remove: | ||
Remove this script when upgrading to a Thrift version that no longer relies on | ||
deprecated Python files, eliminating the need for patching. | ||
""" | ||
|
||
import subprocess | ||
import sys | ||
import thrift | ||
from pathlib import Path | ||
|
||
THRIFT_PATCH_FILENAME = "thrift_patch_for_3.12.patch" | ||
|
||
if len(sys.argv) < 2: | ||
print("Usage: python script.py <codechecker_root_dir>") | ||
sys.exit(1) | ||
|
||
codechecker_root_dir = Path(sys.argv[1]).resolve() | ||
|
||
if not codechecker_root_dir.is_dir(): | ||
print(f"Error: {codechecker_root_dir} is not a valid directory") | ||
sys.exit(1) | ||
|
||
script_dir = Path(__file__).resolve().parent | ||
patch_file = script_dir / THRIFT_PATCH_FILENAME | ||
thrift_lib_dir = Path(thrift.__path__[0]).resolve() | ||
|
||
try: | ||
relative_thrift_lib_dir = thrift_lib_dir.relative_to(codechecker_root_dir) | ||
|
||
subprocess.run( | ||
["git", "apply", "--directory", str(relative_thrift_lib_dir), str(patch_file)], | ||
cwd=codechecker_root_dir, | ||
check=True, | ||
) | ||
print(f"Patch applied successfully to {thrift_lib_dir}") | ||
except ValueError: | ||
print(f"Error: {thrift_lib_dir} is not inside {codechecker_root_dir}") | ||
sys.exit(1) | ||
except subprocess.CalledProcessError as e: | ||
print(f"Error applying patch: {e}") | ||
sys.exit(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- a/transport/THttpClient.py | ||
+++ b/transport/THttpClient.py | ||
@@ -65,7 +65,45 @@ class THttpClient(TTransportBase): | ||
self.port = parsed.port or http_client.HTTPS_PORT | ||
self.certfile = cert_file | ||
self.keyfile = key_file | ||
- self.context = ssl.create_default_context(cafile=cafile) if (cafile and not ssl_context) else ssl_context | ||
+ # TODO: this is a hack that should be purged once Thrift's | ||
+ # Python library correctly supports Python >=3.12 versions. | ||
+ # Since from 3.12 the http.client.HTTPSConnection class' | ||
+ # constructor does not support keyword argument 'key_file' | ||
+ # and 'cert_file', we backport the logic here. | ||
+ # The latest versions almost do the right thing, but the | ||
+ # 'load_cert_chain' method is not called on the context object | ||
+ # by default in the newer implementations. It is unclear | ||
+ # whether CodeChecker's use of this THttpClient class would | ||
+ # actually need this, but I think it is safer to have this | ||
+ # called nevertheless to provide better parity with the original behaviour. | ||
+ # | ||
+ # old implementation of http.client.HTTPSConnection: | ||
+ # https://github.com/python/cpython/blob/3.11/Lib/http/client.py#L1419 | ||
+ # | ||
+ # new implementation of http.client.HTTPSConnection: | ||
+ # https://github.com/python/cpython/blob/3.13/Lib/http/client.py#L1454 | ||
+ if cafile and not ssl_context: | ||
+ if not Path(cafile).is_file(): | ||
+ raise ValueError("Invalid cafile path: '%s'" % (cafile)) | ||
+ | ||
+ new_context = ssl.create_default_context(cafile=cafile) | ||
+ | ||
+ if ssl.HAS_ALPN: | ||
+ new_context.set_alpn_protocols(['http/1.1', 'h2']) | ||
+ | ||
+ if key_file: | ||
+ if not Path(cert_file).is_file(): | ||
+ raise ValueError("Invalid cert_file path: '%s'" % (cert_file)) | ||
+ if not Path(key_file).is_file(): | ||
+ raise ValueError("Invalid key_file path: '%s'" % (key_file)) | ||
+ try: | ||
+ new_context.load_cert_chain(cert_file, key_file) | ||
+ except ssl.SSLError as e: | ||
+ raise ValueError("Failed to load cert/key files: %s" % (e)) | ||
+ | ||
+ self.context = new_context | ||
+ else: | ||
+ self.context = ssl_context | ||
self.host = parsed.hostname | ||
self.path = parsed.path | ||
if parsed.query: | ||
@@ -110,8 +148,6 @@ class THttpClient(TTransportBase): | ||
timeout=self.__timeout) | ||
elif self.scheme == 'https': | ||
self.__http = http_client.HTTPSConnection(self.host, self.port, | ||
- key_file=self.keyfile, | ||
- cert_file=self.certfile, | ||
timeout=self.__timeout, | ||
context=self.context) | ||
if self.using_proxy(): |