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