info.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. from __future__ import annotations
  2. import logging
  3. import os
  4. import platform
  5. import sys
  6. import tempfile
  7. IMPLEMENTATION = platform.python_implementation()
  8. IS_PYPY = IMPLEMENTATION == "PyPy"
  9. IS_GRAALPY = IMPLEMENTATION == "GraalVM"
  10. IS_RUSTPYTHON = IMPLEMENTATION == "RustPython"
  11. IS_CPYTHON = IMPLEMENTATION == "CPython"
  12. IS_WIN = sys.platform == "win32"
  13. IS_MAC_ARM64 = sys.platform == "darwin" and platform.machine() == "arm64"
  14. ROOT = os.path.realpath(os.path.join(os.path.abspath(__file__), os.path.pardir, os.path.pardir))
  15. IS_ZIPAPP = os.path.isfile(ROOT)
  16. _CAN_SYMLINK = _FS_CASE_SENSITIVE = _CFG_DIR = _DATA_DIR = None
  17. LOGGER = logging.getLogger(__name__)
  18. def fs_is_case_sensitive() -> bool:
  19. global _FS_CASE_SENSITIVE # noqa: PLW0603
  20. if _FS_CASE_SENSITIVE is None:
  21. with tempfile.NamedTemporaryFile(prefix="TmP") as tmp_file:
  22. _FS_CASE_SENSITIVE = not os.path.exists(tmp_file.name.lower())
  23. LOGGER.debug("filesystem is %scase-sensitive", "" if _FS_CASE_SENSITIVE else "not ")
  24. return _FS_CASE_SENSITIVE
  25. def fs_supports_symlink() -> bool:
  26. global _CAN_SYMLINK # noqa: PLW0603
  27. if _CAN_SYMLINK is None:
  28. can = False
  29. if hasattr(os, "symlink"):
  30. # Creating a symlink can fail for a variety of reasons, indicating that the filesystem does not support it.
  31. # E.g. on Linux with a VFAT partition mounted.
  32. with tempfile.NamedTemporaryFile(prefix="TmP") as tmp_file:
  33. temp_dir = os.path.dirname(tmp_file.name)
  34. dest = os.path.join(temp_dir, f"{tmp_file.name}-{'b'}")
  35. try:
  36. os.symlink(tmp_file.name, dest)
  37. can = True
  38. except (OSError, NotImplementedError):
  39. pass # symlink is not supported
  40. finally:
  41. if os.path.lexists(dest):
  42. os.remove(dest)
  43. LOGGER.debug("symlink on filesystem does%s work", "" if can else " not")
  44. _CAN_SYMLINK = can
  45. return _CAN_SYMLINK
  46. def fs_path_id(path: str) -> str:
  47. return path.casefold() if fs_is_case_sensitive() else path
  48. __all__ = (
  49. "IS_CPYTHON",
  50. "IS_GRAALPY",
  51. "IS_MAC_ARM64",
  52. "IS_PYPY",
  53. "IS_RUSTPYTHON",
  54. "IS_WIN",
  55. "IS_ZIPAPP",
  56. "ROOT",
  57. "fs_is_case_sensitive",
  58. "fs_path_id",
  59. "fs_supports_symlink",
  60. )