core.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. """
  2. certifi.py
  3. ~~~~~~~~~~
  4. This module returns the installation location of cacert.pem or its contents.
  5. """
  6. import sys
  7. import atexit
  8. def exit_cacert_ctx() -> None:
  9. _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr]
  10. if sys.version_info >= (3, 11):
  11. from importlib.resources import as_file, files
  12. _CACERT_CTX = None
  13. _CACERT_PATH = None
  14. def where() -> str:
  15. # This is slightly terrible, but we want to delay extracting the file
  16. # in cases where we're inside of a zipimport situation until someone
  17. # actually calls where(), but we don't want to re-extract the file
  18. # on every call of where(), so we'll do it once then store it in a
  19. # global variable.
  20. global _CACERT_CTX
  21. global _CACERT_PATH
  22. if _CACERT_PATH is None:
  23. # This is slightly janky, the importlib.resources API wants you to
  24. # manage the cleanup of this file, so it doesn't actually return a
  25. # path, it returns a context manager that will give you the path
  26. # when you enter it and will do any cleanup when you leave it. In
  27. # the common case of not needing a temporary file, it will just
  28. # return the file system location and the __exit__() is a no-op.
  29. #
  30. # We also have to hold onto the actual context manager, because
  31. # it will do the cleanup whenever it gets garbage collected, so
  32. # we will also store that at the global level as well.
  33. _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem"))
  34. _CACERT_PATH = str(_CACERT_CTX.__enter__())
  35. atexit.register(exit_cacert_ctx)
  36. return _CACERT_PATH
  37. def contents() -> str:
  38. return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii")
  39. else:
  40. from importlib.resources import path as get_path, read_text
  41. _CACERT_CTX = None
  42. _CACERT_PATH = None
  43. def where() -> str:
  44. # This is slightly terrible, but we want to delay extracting the
  45. # file in cases where we're inside of a zipimport situation until
  46. # someone actually calls where(), but we don't want to re-extract
  47. # the file on every call of where(), so we'll do it once then store
  48. # it in a global variable.
  49. global _CACERT_CTX
  50. global _CACERT_PATH
  51. if _CACERT_PATH is None:
  52. # This is slightly janky, the importlib.resources API wants you
  53. # to manage the cleanup of this file, so it doesn't actually
  54. # return a path, it returns a context manager that will give
  55. # you the path when you enter it and will do any cleanup when
  56. # you leave it. In the common case of not needing a temporary
  57. # file, it will just return the file system location and the
  58. # __exit__() is a no-op.
  59. #
  60. # We also have to hold onto the actual context manager, because
  61. # it will do the cleanup whenever it gets garbage collected, so
  62. # we will also store that at the global level as well.
  63. _CACERT_CTX = get_path("certifi", "cacert.pem")
  64. _CACERT_PATH = str(_CACERT_CTX.__enter__())
  65. atexit.register(exit_cacert_ctx)
  66. return _CACERT_PATH
  67. def contents() -> str:
  68. return read_text("certifi", "cacert.pem", encoding="ascii")