_runtime.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. # Copyright 2022-present, the HuggingFace Inc. team.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Check presence of installed packages at runtime."""
  15. import importlib.metadata
  16. import importlib.util
  17. import os
  18. import platform
  19. import sys
  20. import warnings
  21. from pathlib import Path
  22. from typing import Any, Literal
  23. from .. import __version__, constants
  24. _PY_VERSION: str = sys.version.split()[0].rstrip("+")
  25. _package_versions = {}
  26. _CANDIDATES = {
  27. "aiohttp": {"aiohttp"},
  28. "fastai": {"fastai"},
  29. "fastapi": {"fastapi"},
  30. "fastcore": {"fastcore"},
  31. "gradio": {"gradio"},
  32. "graphviz": {"graphviz"},
  33. "hf_xet": {"hf_xet"},
  34. "jinja": {"Jinja2"},
  35. "httpx": {"httpx"},
  36. "keras": {"keras"},
  37. "numpy": {"numpy"},
  38. "pillow": {"Pillow"},
  39. "pydantic": {"pydantic"},
  40. "pydot": {"pydot"},
  41. "safetensors": {"safetensors"},
  42. "tensorboard": {"tensorboardX"},
  43. "tensorflow": (
  44. "tensorflow",
  45. "tensorflow-cpu",
  46. "tensorflow-gpu",
  47. "tf-nightly",
  48. "tf-nightly-cpu",
  49. "tf-nightly-gpu",
  50. "intel-tensorflow",
  51. "intel-tensorflow-avx512",
  52. "tensorflow-rocm",
  53. "tensorflow-macos",
  54. ),
  55. "torch": {"torch"},
  56. }
  57. # Check once at runtime
  58. for candidate_name, package_names in _CANDIDATES.items():
  59. _package_versions[candidate_name] = "N/A"
  60. for name in package_names:
  61. try:
  62. _package_versions[candidate_name] = importlib.metadata.version(name)
  63. break
  64. except importlib.metadata.PackageNotFoundError:
  65. pass
  66. def _get_version(package_name: str) -> str:
  67. return _package_versions.get(package_name, "N/A")
  68. def is_package_available(package_name: str) -> bool:
  69. return _get_version(package_name) != "N/A"
  70. # Python
  71. def get_python_version() -> str:
  72. return _PY_VERSION
  73. # Huggingface Hub
  74. def get_hf_hub_version() -> str:
  75. return __version__
  76. # aiohttp
  77. def is_aiohttp_available() -> bool:
  78. return is_package_available("aiohttp")
  79. def get_aiohttp_version() -> str:
  80. return _get_version("aiohttp")
  81. # FastAI
  82. def is_fastai_available() -> bool:
  83. return is_package_available("fastai")
  84. def get_fastai_version() -> str:
  85. return _get_version("fastai")
  86. # FastAPI
  87. def is_fastapi_available() -> bool:
  88. return is_package_available("fastapi")
  89. def get_fastapi_version() -> str:
  90. return _get_version("fastapi")
  91. # Fastcore
  92. def is_fastcore_available() -> bool:
  93. return is_package_available("fastcore")
  94. def get_fastcore_version() -> str:
  95. return _get_version("fastcore")
  96. # FastAI
  97. def is_gradio_available() -> bool:
  98. return is_package_available("gradio")
  99. def get_gradio_version() -> str:
  100. return _get_version("gradio")
  101. # Graphviz
  102. def is_graphviz_available() -> bool:
  103. return is_package_available("graphviz")
  104. def get_graphviz_version() -> str:
  105. return _get_version("graphviz")
  106. # httpx
  107. def is_httpx_available() -> bool:
  108. return is_package_available("httpx")
  109. def get_httpx_version() -> str:
  110. return _get_version("httpx")
  111. # xet
  112. def is_xet_available() -> bool:
  113. # since hf_xet is automatically used if available, allow explicit disabling via environment variable
  114. if constants.HF_HUB_DISABLE_XET:
  115. return False
  116. return is_package_available("hf_xet")
  117. def get_xet_version() -> str:
  118. return _get_version("hf_xet")
  119. # keras
  120. def is_keras_available() -> bool:
  121. return is_package_available("keras")
  122. def get_keras_version() -> str:
  123. return _get_version("keras")
  124. # Numpy
  125. def is_numpy_available() -> bool:
  126. return is_package_available("numpy")
  127. def get_numpy_version() -> str:
  128. return _get_version("numpy")
  129. # Jinja
  130. def is_jinja_available() -> bool:
  131. return is_package_available("jinja")
  132. def get_jinja_version() -> str:
  133. return _get_version("jinja")
  134. # Pillow
  135. def is_pillow_available() -> bool:
  136. return is_package_available("pillow")
  137. def get_pillow_version() -> str:
  138. return _get_version("pillow")
  139. # Pydantic
  140. def is_pydantic_available() -> bool:
  141. if not is_package_available("pydantic"):
  142. return False
  143. # For Pydantic, we add an extra check to test whether it is correctly installed or not. If both pydantic 2.x and
  144. # typing_extensions<=4.5.0 are installed, then pydantic will fail at import time. This should not happen when
  145. # it is installed with `pip install huggingface_hub[inference]` but it can happen when it is installed manually
  146. # by the user in an environment that we don't control.
  147. #
  148. # Usually we won't need to do this kind of check on optional dependencies. However, pydantic is a special case
  149. # as it is automatically imported when doing `from huggingface_hub import ...` even if the user doesn't use it.
  150. #
  151. # See https://github.com/huggingface/huggingface_hub/pull/1829 for more details.
  152. try:
  153. from pydantic import validator # noqa: F401
  154. except ImportError:
  155. # Example: "ImportError: cannot import name 'TypeAliasType' from 'typing_extensions'"
  156. warnings.warn(
  157. "Pydantic is installed but cannot be imported. Please check your installation. `huggingface_hub` will "
  158. "default to not using Pydantic. Error message: '{e}'"
  159. )
  160. return False
  161. return True
  162. def get_pydantic_version() -> str:
  163. return _get_version("pydantic")
  164. # Pydot
  165. def is_pydot_available() -> bool:
  166. return is_package_available("pydot")
  167. def get_pydot_version() -> str:
  168. return _get_version("pydot")
  169. # Tensorboard
  170. def is_tensorboard_available() -> bool:
  171. return is_package_available("tensorboard")
  172. def get_tensorboard_version() -> str:
  173. return _get_version("tensorboard")
  174. # Tensorflow
  175. def is_tf_available() -> bool:
  176. return is_package_available("tensorflow")
  177. def get_tf_version() -> str:
  178. return _get_version("tensorflow")
  179. # Torch
  180. def is_torch_available() -> bool:
  181. return is_package_available("torch")
  182. def get_torch_version() -> str:
  183. return _get_version("torch")
  184. # Safetensors
  185. def is_safetensors_available() -> bool:
  186. return is_package_available("safetensors")
  187. # Shell-related helpers
  188. try:
  189. # Set to `True` if script is running in a Google Colab notebook.
  190. # If running in Google Colab, git credential store is set globally which makes the
  191. # warning disappear. See https://github.com/huggingface/huggingface_hub/issues/1043
  192. #
  193. # Taken from https://stackoverflow.com/a/63519730.
  194. _is_google_colab = "google.colab" in str(get_ipython()) # type: ignore # noqa: F821
  195. except NameError:
  196. _is_google_colab = False
  197. def is_notebook() -> bool:
  198. """Return `True` if code is executed in a notebook (Jupyter, Colab, QTconsole).
  199. Taken from https://stackoverflow.com/a/39662359.
  200. Adapted to make it work with Google colab as well.
  201. """
  202. try:
  203. shell_class = get_ipython().__class__ # type: ignore # noqa: F821
  204. for parent_class in shell_class.__mro__: # e.g. "is subclass of"
  205. if parent_class.__name__ == "ZMQInteractiveShell":
  206. return True # Jupyter notebook, Google colab or qtconsole
  207. return False
  208. except NameError:
  209. return False # Probably standard Python interpreter
  210. def is_google_colab() -> bool:
  211. """Return `True` if code is executed in a Google colab.
  212. Taken from https://stackoverflow.com/a/63519730.
  213. """
  214. return _is_google_colab
  215. def is_colab_enterprise() -> bool:
  216. """Return `True` if code is executed in a Google Colab Enterprise environment."""
  217. return os.environ.get("VERTEX_PRODUCT") == "COLAB_ENTERPRISE"
  218. # Check how huggingface_hub has been installed
  219. def installation_method() -> Literal["brew", "hf_installer", "pip", "unknown"]:
  220. """Return the installation method of the current environment.
  221. - "hf_installer" if installed via the official installer script
  222. - "brew" if installed via Homebrew
  223. - "pip" if pip is available (default fallback for standard Python environments)
  224. - "unknown" otherwise
  225. """
  226. if _is_brew_installation():
  227. return "brew"
  228. if _is_hf_installer_installation():
  229. return "hf_installer"
  230. if _is_pip_available():
  231. return "pip"
  232. return "unknown"
  233. def _is_brew_installation() -> bool:
  234. """Check if running from a Homebrew installation.
  235. Note: AI-generated by Claude.
  236. """
  237. exe_path = Path(sys.executable).resolve()
  238. exe_str = str(exe_path)
  239. # Check common Homebrew paths
  240. # /opt/homebrew (Apple Silicon), /usr/local (Intel)
  241. return "/Cellar/" in exe_str or "/opt/homebrew/" in exe_str or exe_str.startswith("/usr/local/Cellar/")
  242. def _is_hf_installer_installation() -> bool:
  243. """Return `True` if the current environment was set up via the official hf installer script.
  244. i.e. using one of
  245. curl -LsSf https://hf.co/cli/install.sh | bash
  246. powershell -ExecutionPolicy ByPass -c "irm https://hf.co/cli/install.ps1 | iex"
  247. """
  248. venv = sys.prefix # points to venv root if active
  249. marker = Path(venv) / ".hf_installer_marker"
  250. return marker.exists()
  251. def _is_pip_available() -> bool:
  252. """Return `True` if pip is importable in the current environment."""
  253. return importlib.util.find_spec("pip") is not None
  254. def dump_environment_info() -> dict[str, Any]:
  255. """Dump information about the machine to help debugging issues.
  256. Similar helper exist in:
  257. - `datasets` (https://github.com/huggingface/datasets/blob/main/src/datasets/commands/env.py)
  258. - `diffusers` (https://github.com/huggingface/diffusers/blob/main/src/diffusers/commands/env.py)
  259. - `transformers` (https://github.com/huggingface/transformers/blob/main/src/transformers/commands/env.py)
  260. """
  261. from huggingface_hub import get_token, whoami
  262. from huggingface_hub.utils import is_agent, list_credential_helpers
  263. token = get_token()
  264. # Generic machine info
  265. info: dict[str, Any] = {
  266. "huggingface_hub version": get_hf_hub_version(),
  267. "Platform": platform.platform(),
  268. "Python version": get_python_version(),
  269. }
  270. # Interpreter info
  271. try:
  272. shell_class = get_ipython().__class__ # type: ignore # noqa: F821
  273. info["Running in iPython ?"] = "Yes"
  274. info["iPython shell"] = shell_class.__name__
  275. except NameError:
  276. info["Running in iPython ?"] = "No"
  277. info["Running in notebook ?"] = "Yes" if is_notebook() else "No"
  278. info["Running in Google Colab ?"] = "Yes" if is_google_colab() else "No"
  279. info["Running in Google Colab Enterprise ?"] = "Yes" if is_colab_enterprise() else "No"
  280. # Login info
  281. info["Token path ?"] = constants.HF_TOKEN_PATH
  282. info["Has saved token ?"] = token is not None
  283. if token is not None:
  284. try:
  285. info["Who am I ?"] = whoami()["name"]
  286. except Exception:
  287. pass
  288. try:
  289. info["Configured git credential helpers"] = ", ".join(list_credential_helpers())
  290. except Exception:
  291. pass
  292. info["Run by AI agent ?"] = "Yes" if is_agent() else "No"
  293. # How huggingface_hub has been installed?
  294. info["Installation method"] = installation_method()
  295. # Installed dependencies
  296. info["httpx"] = get_httpx_version()
  297. info["hf_xet"] = get_xet_version()
  298. info["gradio"] = get_gradio_version()
  299. info["tensorboard"] = get_tensorboard_version()
  300. # Environment variables
  301. info["ENDPOINT"] = constants.ENDPOINT
  302. info["HF_HUB_CACHE"] = constants.HF_HUB_CACHE
  303. info["HF_ASSETS_CACHE"] = constants.HF_ASSETS_CACHE
  304. info["HF_TOKEN_PATH"] = constants.HF_TOKEN_PATH
  305. info["HF_STORED_TOKENS_PATH"] = constants.HF_STORED_TOKENS_PATH
  306. info["HF_HUB_OFFLINE"] = constants.HF_HUB_OFFLINE
  307. info["HF_HUB_DISABLE_TELEMETRY"] = constants.HF_HUB_DISABLE_TELEMETRY
  308. info["HF_HUB_DISABLE_PROGRESS_BARS"] = constants.HF_HUB_DISABLE_PROGRESS_BARS
  309. info["HF_HUB_DISABLE_SYMLINKS"] = constants.HF_HUB_DISABLE_SYMLINKS
  310. info["HF_HUB_DISABLE_SYMLINKS_WARNING"] = constants.HF_HUB_DISABLE_SYMLINKS_WARNING
  311. info["HF_HUB_DISABLE_EXPERIMENTAL_WARNING"] = constants.HF_HUB_DISABLE_EXPERIMENTAL_WARNING
  312. info["HF_HUB_DISABLE_IMPLICIT_TOKEN"] = constants.HF_HUB_DISABLE_IMPLICIT_TOKEN
  313. info["HF_HUB_DISABLE_XET"] = constants.HF_HUB_DISABLE_XET
  314. info["HF_HUB_ETAG_TIMEOUT"] = constants.HF_HUB_ETAG_TIMEOUT
  315. info["HF_HUB_DOWNLOAD_TIMEOUT"] = constants.HF_HUB_DOWNLOAD_TIMEOUT
  316. info["HF_XET_HIGH_PERFORMANCE"] = constants.HF_XET_HIGH_PERFORMANCE
  317. print("\nCopy-and-paste the text below in your GitHub issue.\n")
  318. print("\n".join([f"- {prop}: {val}" for prop, val in info.items()]) + "\n")
  319. return info