1from __future__ import annotations 
    2 
    3import codecs 
    4import json 
    5import locale 
    6import os 
    7import platform 
    8import struct 
    9import sys 
    10 
    11from pandas._typing import JSONSerializable 
    12from pandas.compat._optional import ( 
    13    VERSIONS, 
    14    get_version, 
    15    import_optional_dependency, 
    16) 
    17 
    18 
    19def _get_commit_hash() -> str | None: 
    20    """ 
    21    Use vendored versioneer code to get git hash, which handles 
    22    git worktree correctly. 
    23    """ 
    24    from pandas._version import get_versions 
    25 
    26    versions = get_versions() 
    27    return versions["full-revisionid"] 
    28 
    29 
    30def _get_sys_info() -> dict[str, JSONSerializable]: 
    31    """ 
    32    Returns system information as a JSON serializable dictionary. 
    33    """ 
    34    uname_result = platform.uname() 
    35    language_code, encoding = locale.getlocale() 
    36    return { 
    37        "commit": _get_commit_hash(), 
    38        "python": ".".join([str(i) for i in sys.version_info]), 
    39        "python-bits": struct.calcsize("P") * 8, 
    40        "OS": uname_result.system, 
    41        "OS-release": uname_result.release, 
    42        "Version": uname_result.version, 
    43        "machine": uname_result.machine, 
    44        "processor": uname_result.processor, 
    45        "byteorder": sys.byteorder, 
    46        "LC_ALL": os.environ.get("LC_ALL"), 
    47        "LANG": os.environ.get("LANG"), 
    48        "LOCALE": {"language-code": language_code, "encoding": encoding}, 
    49    } 
    50 
    51 
    52def _get_dependency_info() -> dict[str, JSONSerializable]: 
    53    """ 
    54    Returns dependency information as a JSON serializable dictionary. 
    55    """ 
    56    deps = [ 
    57        "pandas", 
    58        # required 
    59        "numpy", 
    60        "pytz", 
    61        "dateutil", 
    62        # install / build, 
    63        "setuptools", 
    64        "pip", 
    65        "Cython", 
    66        # test 
    67        "pytest", 
    68        "hypothesis", 
    69        # docs 
    70        "sphinx", 
    71        # Other, need a min version 
    72        "blosc", 
    73        "feather", 
    74        "xlsxwriter", 
    75        "lxml.etree", 
    76        "html5lib", 
    77        "pymysql", 
    78        "psycopg2", 
    79        "jinja2", 
    80        # Other, not imported. 
    81        "IPython", 
    82        "pandas_datareader", 
    83    ] 
    84    deps.extend(list(VERSIONS)) 
    85 
    86    result: dict[str, JSONSerializable] = {} 
    87    for modname in deps: 
    88        mod = import_optional_dependency(modname, errors="ignore") 
    89        result[modname] = get_version(mod) if mod else None 
    90    return result 
    91 
    92 
    93def show_versions(as_json: str | bool = False) -> None: 
    94    """ 
    95    Provide useful information, important for bug reports. 
    96 
    97    It comprises info about hosting operation system, pandas version, 
    98    and versions of other installed relative packages. 
    99 
    100    Parameters 
    101    ---------- 
    102    as_json : str or bool, default False 
    103        * If False, outputs info in a human readable form to the console. 
    104        * If str, it will be considered as a path to a file. 
    105          Info will be written to that file in JSON format. 
    106        * If True, outputs info in JSON format to the console. 
    107    """ 
    108    sys_info = _get_sys_info() 
    109    deps = _get_dependency_info() 
    110 
    111    if as_json: 
    112        j = {"system": sys_info, "dependencies": deps} 
    113 
    114        if as_json is True: 
    115            sys.stdout.writelines(json.dumps(j, indent=2)) 
    116        else: 
    117            assert isinstance(as_json, str)  # needed for mypy 
    118            with codecs.open(as_json, "wb", encoding="utf8") as f: 
    119                json.dump(j, f, indent=2) 
    120 
    121    else: 
    122        assert isinstance(sys_info["LOCALE"], dict)  # needed for mypy 
    123        language_code = sys_info["LOCALE"]["language-code"] 
    124        encoding = sys_info["LOCALE"]["encoding"] 
    125        sys_info["LOCALE"] = f"{language_code}.{encoding}" 
    126 
    127        maxlen = max(len(x) for x in deps) 
    128        print("\nINSTALLED VERSIONS") 
    129        print("------------------") 
    130        for k, v in sys_info.items(): 
    131            print(f"{k:<{maxlen}}: {v}") 
    132        print("") 
    133        for k, v in deps.items(): 
    134            print(f"{k:<{maxlen}}: {v}")