1from __future__ import annotations
2
3import json
4import locale
5import os
6import platform
7import struct
8import sys
9from typing import TYPE_CHECKING
10
11from pandas.util._decorators import set_module
12
13if TYPE_CHECKING:
14 from pandas._typing import JSONSerializable
15
16from pandas.compat._optional import (
17 VERSIONS,
18 get_version,
19 import_optional_dependency,
20)
21
22
23def _get_commit_hash() -> str | None:
24 """
25 Use vendored versioneer code to get git hash, which handles
26 git worktree correctly.
27 """
28 from pandas._version_meson import ( # pyright: ignore [reportMissingImports]
29 __git_version__,
30 )
31
32 return __git_version__
33
34
35def _get_sys_info() -> dict[str, JSONSerializable]:
36 """
37 Returns system information as a JSON serializable dictionary.
38 """
39 uname_result = platform.uname()
40 language_code, encoding = locale.getlocale()
41 return {
42 "commit": _get_commit_hash(),
43 "python": platform.python_version(),
44 "python-bits": struct.calcsize("P") * 8,
45 "OS": uname_result.system,
46 "OS-release": uname_result.release,
47 "Version": uname_result.version,
48 "machine": uname_result.machine,
49 "processor": uname_result.processor,
50 "byteorder": sys.byteorder,
51 "LC_ALL": os.environ.get("LC_ALL"),
52 "LANG": os.environ.get("LANG"),
53 "LOCALE": {"language-code": language_code, "encoding": encoding},
54 }
55
56
57def _get_dependency_info() -> dict[str, JSONSerializable]:
58 """
59 Returns dependency information as a JSON serializable dictionary.
60 """
61 deps = [
62 "pandas",
63 # required
64 "numpy",
65 "dateutil",
66 # install / build,
67 "pip",
68 "Cython",
69 # docs
70 "sphinx",
71 # Other, not imported.
72 "IPython",
73 ]
74 # Optional dependencies
75 deps.extend(list(VERSIONS))
76
77 result: dict[str, JSONSerializable] = {}
78 for modname in deps:
79 try:
80 mod = import_optional_dependency(modname, errors="ignore")
81 except Exception:
82 # Dependency conflicts may cause a non ImportError
83 result[modname] = "N/A"
84 else:
85 result[modname] = get_version(mod) if mod else None
86 return result
87
88
89@set_module("pandas")
90def show_versions(as_json: str | bool = False) -> None:
91 """
92 Provide useful information, important for bug reports.
93
94 It comprises info about hosting operation system, pandas version,
95 and versions of other installed relative packages.
96
97 Parameters
98 ----------
99 as_json : str or bool, default False
100 * If False, outputs info in a human readable form to the console.
101 * If str, it will be considered as a path to a file.
102 Info will be written to that file in JSON format.
103 * If True, outputs info in JSON format to the console.
104
105 See Also
106 --------
107 get_option : Retrieve the value of the specified option.
108 set_option : Set the value of the specified option or options.
109
110 Examples
111 --------
112 >>> pd.show_versions() # doctest: +SKIP
113 Your output may look something like this:
114 INSTALLED VERSIONS
115 ------------------
116 commit : 37ea63d540fd27274cad6585082c91b1283f963d
117 python : 3.10.6.final.0
118 python-bits : 64
119 OS : Linux
120 OS-release : 5.10.102.1-microsoft-standard-WSL2
121 Version : #1 SMP Wed Mar 2 00:30:59 UTC 2022
122 machine : x86_64
123 processor : x86_64
124 byteorder : little
125 LC_ALL : None
126 LANG : en_GB.UTF-8
127 LOCALE : en_GB.UTF-8
128 pandas : 2.0.1
129 numpy : 1.24.3
130 ...
131 """
132 sys_info = _get_sys_info()
133 deps = _get_dependency_info()
134
135 if as_json:
136 j = {"system": sys_info, "dependencies": deps}
137
138 if as_json is True:
139 sys.stdout.writelines(json.dumps(j, indent=2))
140 else:
141 assert isinstance(as_json, str) # needed for mypy
142 with open(as_json, "w", encoding="utf-8") as f:
143 json.dump(j, f, indent=2)
144
145 else:
146 assert isinstance(sys_info["LOCALE"], dict) # needed for mypy
147 language_code = sys_info["LOCALE"]["language-code"]
148 encoding = sys_info["LOCALE"]["encoding"]
149 sys_info["LOCALE"] = f"{language_code}.{encoding}"
150
151 maxlen = max(len(x) for x in deps)
152 print("\nINSTALLED VERSIONS")
153 print("------------------")
154 for k, v in sys_info.items():
155 print(f"{k:<{maxlen}}: {v}")
156 print("")
157 for k, v in deps.items():
158 print(f"{k:<{maxlen}}: {v}")