codekingpro/portable-devtools
114k
1"""Module containing bug report helper(s)."""2 3# pyright: reportUnknownMemberType=false4 5import json6import platform7import ssl8import sys9from typing import Any10 11import idna12import urllib313 14from . import __version__ as requests_version15 16try:17 import charset_normalizer18except ImportError:19 charset_normalizer = None20 21try:22 import chardet # type: ignore[import-not-found]23except ImportError:24 chardet = None25 26try:27 from urllib3.contrib import pyopenssl28except ImportError:29 pyopenssl = None30 OpenSSL = None31 cryptography = None32else:33 import cryptography # type: ignore[import-not-found]34 import OpenSSL # type: ignore[import-not-found]35 36 37def _implementation():38 """Return a dict with the Python implementation and version.39 40 Provide both the name and the version of the Python implementation41 currently running. For example, on CPython 3.10.3 it will return42 {'name': 'CPython', 'version': '3.10.3'}.43 44 This function works best on CPython and PyPy: in particular, it probably45 doesn't work for Jython or IronPython. Future investigation should be done46 to work out the correct shape of the code for those platforms.47 """48 implementation = platform.python_implementation()49 50 if implementation == "CPython":51 implementation_version = platform.python_version()52 elif implementation == "PyPy":53 pypy = sys.pypy_version_info # type: ignore[attr-defined]54 implementation_version = f"{pypy.major}.{pypy.minor}.{pypy.micro}"55 if sys.pypy_version_info.releaselevel != "final": # type: ignore[attr-defined]56 implementation_version = "".join(57 [implementation_version, sys.pypy_version_info.releaselevel] # type: ignore[attr-defined]58 )59 elif implementation == "Jython":60 implementation_version = platform.python_version() # Complete Guess61 elif implementation == "IronPython":62 implementation_version = platform.python_version() # Complete Guess63 else:64 implementation_version = "Unknown"65 66 return {"name": implementation, "version": implementation_version}67 68 69def info() -> dict[str, Any]:70 """Generate information for a bug report."""71 try:72 platform_info = {73 "system": platform.system(),74 "release": platform.release(),75 }76 except OSError:77 platform_info = {78 "system": "Unknown",79 "release": "Unknown",80 }81 82 implementation_info = _implementation()83 urllib3_info = {"version": urllib3.__version__} # type: ignore[reportPrivateImportUsage]84 charset_normalizer_info = {"version": None}85 chardet_info: dict[str, str | None] = {"version": None}86 if charset_normalizer:87 charset_normalizer_info = {"version": charset_normalizer.__version__}88 if chardet:89 chardet_info = {"version": chardet.__version__}90 91 pyopenssl_info: dict[str, str | None] = {92 "version": None,93 "openssl_version": "",94 }95 if OpenSSL:96 pyopenssl_info = {97 "version": OpenSSL.__version__,98 "openssl_version": f"{OpenSSL.SSL.OPENSSL_VERSION_NUMBER:x}",99 }100 cryptography_info = {101 "version": getattr(cryptography, "__version__", ""),102 }103 idna_info = {104 "version": getattr(idna, "__version__", ""),105 }106 107 system_ssl = ssl.OPENSSL_VERSION_NUMBER108 system_ssl_info = {"version": f"{system_ssl:x}" if system_ssl is not None else ""} # type: ignore[reportUnnecessaryComparison]109 110 return {111 "platform": platform_info,112 "implementation": implementation_info,113 "system_ssl": system_ssl_info,114 "using_pyopenssl": pyopenssl is not None,115 "using_charset_normalizer": chardet is None,116 "pyOpenSSL": pyopenssl_info,117 "urllib3": urllib3_info,118 "chardet": chardet_info,119 "charset_normalizer": charset_normalizer_info,120 "cryptography": cryptography_info,121 "idna": idna_info,122 "requests": {123 "version": requests_version,124 },125 }126 127 128def main():129 """Pretty-print the bug information as JSON."""130 print(json.dumps(info(), sort_keys=True, indent=2))131 132 133if __name__ == "__main__":134 main()135 