158 lines
4.2 KiB
Python
158 lines
4.2 KiB
Python
|
import codecs
|
||
|
import json
|
||
|
import locale
|
||
|
import os
|
||
|
import platform
|
||
|
import struct
|
||
|
import sys
|
||
|
from typing import Dict, Optional, Union
|
||
|
|
||
|
from pandas._typing import JSONSerializable
|
||
|
from pandas.compat._optional import VERSIONS, get_version, import_optional_dependency
|
||
|
|
||
|
|
||
|
def _get_commit_hash() -> Optional[str]:
|
||
|
"""
|
||
|
Use vendored versioneer code to get git hash, which handles
|
||
|
git worktree correctly.
|
||
|
"""
|
||
|
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,
|
||
|
"pip",
|
||
|
"setuptools",
|
||
|
"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, raise_on_missing=False, on_version="ignore"
|
||
|
)
|
||
|
result[modname] = get_version(mod) if mod else None
|
||
|
return result
|
||
|
|
||
|
|
||
|
def show_versions(as_json: Union[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.
|
||
|
"""
|
||
|
sys_info = _get_sys_info()
|
||
|
deps = _get_dependency_info()
|
||
|
|
||
|
if as_json:
|
||
|
j = {"system": sys_info, "dependencies": deps}
|
||
|
|
||
|
if as_json is True:
|
||
|
print(j)
|
||
|
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}")
|
||
|
|
||
|
|
||
|
def main() -> int:
|
||
|
from optparse import OptionParser
|
||
|
|
||
|
parser = OptionParser()
|
||
|
parser.add_option(
|
||
|
"-j",
|
||
|
"--json",
|
||
|
metavar="FILE",
|
||
|
nargs=1,
|
||
|
help="Save output as JSON into file, pass in '-' to output to stdout",
|
||
|
)
|
||
|
|
||
|
(options, args) = parser.parse_args()
|
||
|
|
||
|
if options.json == "-":
|
||
|
options.json = True
|
||
|
|
||
|
show_versions(as_json=options.json)
|
||
|
|
||
|
return 0
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
sys.exit(main())
|