jpayne@7: """Module containing bug report helper(s).""" jpayne@7: jpayne@7: import json jpayne@7: import platform jpayne@7: import ssl jpayne@7: import sys jpayne@7: jpayne@7: import idna jpayne@7: import urllib3 jpayne@7: jpayne@7: from . import __version__ as requests_version jpayne@7: jpayne@7: try: jpayne@7: import charset_normalizer jpayne@7: except ImportError: jpayne@7: charset_normalizer = None jpayne@7: jpayne@7: try: jpayne@7: import chardet jpayne@7: except ImportError: jpayne@7: chardet = None jpayne@7: jpayne@7: try: jpayne@7: from urllib3.contrib import pyopenssl jpayne@7: except ImportError: jpayne@7: pyopenssl = None jpayne@7: OpenSSL = None jpayne@7: cryptography = None jpayne@7: else: jpayne@7: import cryptography jpayne@7: import OpenSSL jpayne@7: jpayne@7: jpayne@7: def _implementation(): jpayne@7: """Return a dict with the Python implementation and version. jpayne@7: jpayne@7: Provide both the name and the version of the Python implementation jpayne@7: currently running. For example, on CPython 3.10.3 it will return jpayne@7: {'name': 'CPython', 'version': '3.10.3'}. jpayne@7: jpayne@7: This function works best on CPython and PyPy: in particular, it probably jpayne@7: doesn't work for Jython or IronPython. Future investigation should be done jpayne@7: to work out the correct shape of the code for those platforms. jpayne@7: """ jpayne@7: implementation = platform.python_implementation() jpayne@7: jpayne@7: if implementation == "CPython": jpayne@7: implementation_version = platform.python_version() jpayne@7: elif implementation == "PyPy": jpayne@7: implementation_version = "{}.{}.{}".format( jpayne@7: sys.pypy_version_info.major, jpayne@7: sys.pypy_version_info.minor, jpayne@7: sys.pypy_version_info.micro, jpayne@7: ) jpayne@7: if sys.pypy_version_info.releaselevel != "final": jpayne@7: implementation_version = "".join( jpayne@7: [implementation_version, sys.pypy_version_info.releaselevel] jpayne@7: ) jpayne@7: elif implementation == "Jython": jpayne@7: implementation_version = platform.python_version() # Complete Guess jpayne@7: elif implementation == "IronPython": jpayne@7: implementation_version = platform.python_version() # Complete Guess jpayne@7: else: jpayne@7: implementation_version = "Unknown" jpayne@7: jpayne@7: return {"name": implementation, "version": implementation_version} jpayne@7: jpayne@7: jpayne@7: def info(): jpayne@7: """Generate information for a bug report.""" jpayne@7: try: jpayne@7: platform_info = { jpayne@7: "system": platform.system(), jpayne@7: "release": platform.release(), jpayne@7: } jpayne@7: except OSError: jpayne@7: platform_info = { jpayne@7: "system": "Unknown", jpayne@7: "release": "Unknown", jpayne@7: } jpayne@7: jpayne@7: implementation_info = _implementation() jpayne@7: urllib3_info = {"version": urllib3.__version__} jpayne@7: charset_normalizer_info = {"version": None} jpayne@7: chardet_info = {"version": None} jpayne@7: if charset_normalizer: jpayne@7: charset_normalizer_info = {"version": charset_normalizer.__version__} jpayne@7: if chardet: jpayne@7: chardet_info = {"version": chardet.__version__} jpayne@7: jpayne@7: pyopenssl_info = { jpayne@7: "version": None, jpayne@7: "openssl_version": "", jpayne@7: } jpayne@7: if OpenSSL: jpayne@7: pyopenssl_info = { jpayne@7: "version": OpenSSL.__version__, jpayne@7: "openssl_version": f"{OpenSSL.SSL.OPENSSL_VERSION_NUMBER:x}", jpayne@7: } jpayne@7: cryptography_info = { jpayne@7: "version": getattr(cryptography, "__version__", ""), jpayne@7: } jpayne@7: idna_info = { jpayne@7: "version": getattr(idna, "__version__", ""), jpayne@7: } jpayne@7: jpayne@7: system_ssl = ssl.OPENSSL_VERSION_NUMBER jpayne@7: system_ssl_info = {"version": f"{system_ssl:x}" if system_ssl is not None else ""} jpayne@7: jpayne@7: return { jpayne@7: "platform": platform_info, jpayne@7: "implementation": implementation_info, jpayne@7: "system_ssl": system_ssl_info, jpayne@7: "using_pyopenssl": pyopenssl is not None, jpayne@7: "using_charset_normalizer": chardet is None, jpayne@7: "pyOpenSSL": pyopenssl_info, jpayne@7: "urllib3": urllib3_info, jpayne@7: "chardet": chardet_info, jpayne@7: "charset_normalizer": charset_normalizer_info, jpayne@7: "cryptography": cryptography_info, jpayne@7: "idna": idna_info, jpayne@7: "requests": { jpayne@7: "version": requests_version, jpayne@7: }, jpayne@7: } jpayne@7: jpayne@7: jpayne@7: def main(): jpayne@7: """Pretty-print the bug information as JSON.""" jpayne@7: print(json.dumps(info(), sort_keys=True, indent=2)) jpayne@7: jpayne@7: jpayne@7: if __name__ == "__main__": jpayne@7: main()