core.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. """
  2. certifi.py
  3. ~~~~~~~~~~
  4. This module returns the installation location of cacert.pem or its contents.
  5. """
  6. import sys
  7. if sys.version_info >= (3, 11):
  8. from importlib.resources import as_file, files
  9. _CACERT_CTX = None
  10. _CACERT_PATH = None
  11. def where() -> str:
  12. # This is slightly terrible, but we want to delay extracting the file
  13. # in cases where we're inside of a zipimport situation until someone
  14. # actually calls where(), but we don't want to re-extract the file
  15. # on every call of where(), so we'll do it once then store it in a
  16. # global variable.
  17. global _CACERT_CTX
  18. global _CACERT_PATH
  19. if _CACERT_PATH is None:
  20. # This is slightly janky, the importlib.resources API wants you to
  21. # manage the cleanup of this file, so it doesn't actually return a
  22. # path, it returns a context manager that will give you the path
  23. # when you enter it and will do any cleanup when you leave it. In
  24. # the common case of not needing a temporary file, it will just
  25. # return the file system location and the __exit__() is a no-op.
  26. #
  27. # We also have to hold onto the actual context manager, because
  28. # it will do the cleanup whenever it gets garbage collected, so
  29. # we will also store that at the global level as well.
  30. _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem"))
  31. _CACERT_PATH = str(_CACERT_CTX.__enter__())
  32. return _CACERT_PATH
  33. def contents() -> str:
  34. return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii")
  35. elif sys.version_info >= (3, 7):
  36. from importlib.resources import path as get_path, read_text
  37. _CACERT_CTX = None
  38. _CACERT_PATH = None
  39. def where() -> str:
  40. # This is slightly terrible, but we want to delay extracting the
  41. # file in cases where we're inside of a zipimport situation until
  42. # someone actually calls where(), but we don't want to re-extract
  43. # the file on every call of where(), so we'll do it once then store
  44. # it in a global variable.
  45. global _CACERT_CTX
  46. global _CACERT_PATH
  47. if _CACERT_PATH is None:
  48. # This is slightly janky, the importlib.resources API wants you
  49. # to manage the cleanup of this file, so it doesn't actually
  50. # return a path, it returns a context manager that will give
  51. # you the path when you enter it and will do any cleanup when
  52. # you leave it. In the common case of not needing a temporary
  53. # file, it will just return the file system location and the
  54. # __exit__() is a no-op.
  55. #
  56. # We also have to hold onto the actual context manager, because
  57. # it will do the cleanup whenever it gets garbage collected, so
  58. # we will also store that at the global level as well.
  59. _CACERT_CTX = get_path("certifi", "cacert.pem")
  60. _CACERT_PATH = str(_CACERT_CTX.__enter__())
  61. return _CACERT_PATH
  62. def contents() -> str:
  63. return read_text("certifi", "cacert.pem", encoding="ascii")
  64. else:
  65. import os
  66. import types
  67. from typing import Union
  68. Package = Union[types.ModuleType, str]
  69. Resource = Union[str, "os.PathLike"]
  70. # This fallback will work for Python versions prior to 3.7 that lack the
  71. # importlib.resources module but relies on the existing `where` function
  72. # so won't address issues with environments like PyOxidizer that don't set
  73. # __file__ on modules.
  74. def read_text(
  75. package: Package,
  76. resource: Resource,
  77. encoding: str = 'utf-8',
  78. errors: str = 'strict'
  79. ) -> str:
  80. with open(where(), encoding=encoding) as data:
  81. return data.read()
  82. # If we don't have importlib.resources, then we will just do the old logic
  83. # of assuming we're on the filesystem and munge the path directly.
  84. def where() -> str:
  85. f = os.path.dirname(__file__)
  86. return os.path.join(f, "cacert.pem")
  87. def contents() -> str:
  88. return read_text("certifi", "cacert.pem", encoding="ascii")