You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.7 KiB

from __future__ import annotations
import codecs
import json
import locale
import os
import platform
import struct
import sys
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pandas._typing import JSONSerializable
from pandas.compat._optional import (
VERSIONS,
get_version,
import_optional_dependency,
)
def _get_commit_hash() -> str | None:
"""
Use vendored versioneer code to get git hash, which handles
git worktree correctly.
"""
try:
from pandas._version_meson import ( # pyright: ignore [reportMissingImports]
__git_version__,
)
return __git_version__
except ImportError:
from pandas._version import get_versions
versions = get_versions()
return versions["full-revisionid"]
def _get_sys_info() -> dict[str, JSONSerializable]:
"""
Returns system information as a JSON serializable dictionary.
"""
uname_result = platform.uname()
language_code, encoding = locale.getlocale()
return {
"commit": _get_commit_hash(),
"python": ".".join([str(i) for i in sys.version_info]),
"python-bits": struct.calcsize("P") * 8,
"OS": uname_result.system,
"OS-release": uname_result.release,
"Version": uname_result.version,
"machine": uname_result.machine,
"processor": uname_result.processor,
"byteorder": sys.byteorder,
"LC_ALL": os.environ.get("LC_ALL"),
"LANG": os.environ.get("LANG"),
"LOCALE": {"language-code": language_code, "encoding": encoding},
}
def _get_dependency_info() -> dict[str, JSONSerializable]:
"""
Returns dependency information as a JSON serializable dictionary.
"""
deps = [
"pandas",
# required
"numpy",
"pytz",
"dateutil",
# install / build,
"setuptools",
"pip",
"Cython",
# test
"pytest",
"hypothesis",
# docs
"sphinx",
# Other, need a min version
"blosc",
"feather",
"xlsxwriter",
"lxml.etree",
"html5lib",
"pymysql",
"psycopg2",
"jinja2",
# Other, not imported.
"IPython",
"pandas_datareader",
]
deps.extend(list(VERSIONS))
result: dict[str, JSONSerializable] = {}
for modname in deps:
mod = import_optional_dependency(modname, errors="ignore")
result[modname] = get_version(mod) if mod else None
return result
def show_versions(as_json: str | bool = False) -> None:
"""
Provide useful information, important for bug reports.
It comprises info about hosting operation system, pandas version,
and versions of other installed relative packages.
Parameters
----------
as_json : str or bool, default False
* If False, outputs info in a human readable form to the console.
* If str, it will be considered as a path to a file.
Info will be written to that file in JSON format.
* If True, outputs info in JSON format to the console.
Examples
--------
>>> pd.show_versions() # doctest: +SKIP
Your output may look something like this:
INSTALLED VERSIONS
------------------
commit : 37ea63d540fd27274cad6585082c91b1283f963d
python : 3.10.6.final.0
python-bits : 64
OS : Linux
OS-release : 5.10.102.1-microsoft-standard-WSL2
Version : #1 SMP Wed Mar 2 00:30:59 UTC 2022
machine : x86_64
processor : x86_64
byteorder : little
LC_ALL : None
LANG : en_GB.UTF-8
LOCALE : en_GB.UTF-8
pandas : 2.0.1
numpy : 1.24.3
...
"""
sys_info = _get_sys_info()
deps = _get_dependency_info()
if as_json:
j = {"system": sys_info, "dependencies": deps}
if as_json is True:
sys.stdout.writelines(json.dumps(j, indent=2))
else:
assert isinstance(as_json, str) # needed for mypy
with codecs.open(as_json, "wb", encoding="utf8") as f:
json.dump(j, f, indent=2)
else:
assert isinstance(sys_info["LOCALE"], dict) # needed for mypy
language_code = sys_info["LOCALE"]["language-code"]
encoding = sys_info["LOCALE"]["encoding"]
sys_info["LOCALE"] = f"{language_code}.{encoding}"
maxlen = max(len(x) for x in deps)
print("\nINSTALLED VERSIONS")
print("------------------")
for k, v in sys_info.items():
print(f"{k:<{maxlen}}: {v}")
print("")
for k, v in deps.items():
print(f"{k:<{maxlen}}: {v}")