_print_versions.py 4.5 KB

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