44
55This module returns the installation location of cacert.pem or its contents.
66"""
7- import os
8- import types
9- from typing import Union
7+ import sys
108
11- try :
12- from importlib .resources import path as get_path , read_text
9+
10+ if sys .version_info >= (3 , 9 ):
11+
12+ from importlib .resources import as_file , files
1313
1414 _CACERT_CTX = None
1515 _CACERT_PATH = None
@@ -33,36 +33,45 @@ def where() -> str:
3333 # We also have to hold onto the actual context manager, because
3434 # it will do the cleanup whenever it gets garbage collected, so
3535 # we will also store that at the global level as well.
36- _CACERT_CTX = get_path ( "certifi" , "cacert.pem" )
36+ _CACERT_CTX = as_file ( files ( "certifi" ). joinpath ( "cacert.pem" ) )
3737 _CACERT_PATH = str (_CACERT_CTX .__enter__ ())
3838
3939 return _CACERT_PATH
4040
41+ def contents () -> str :
42+ return files ("certifi" ).joinpath ("cacert.pem" ).read_text (encoding = "ascii" )
43+
44+ else :
4145
42- except ImportError :
43- Package = Union [types .ModuleType , str ]
44- Resource = Union [str , "os.PathLike" ]
46+ from importlib .resources import path as get_path , read_text
4547
46- # This fallback will work for Python versions prior to 3.7 that lack the
47- # importlib.resources module but relies on the existing `where` function
48- # so won't address issues with environments like PyOxidizer that don't set
49- # __file__ on modules.
50- def read_text (
51- package : Package ,
52- resource : Resource ,
53- encoding : str = 'utf-8' ,
54- errors : str = 'strict'
55- ) -> str :
56- with open (where (), encoding = encoding ) as data :
57- return data .read ()
48+ _CACERT_CTX = None
49+ _CACERT_PATH = None
5850
59- # If we don't have importlib.resources, then we will just do the old logic
60- # of assuming we're on the filesystem and munge the path directly.
6151 def where () -> str :
62- f = os .path .dirname (__file__ )
63-
64- return os .path .join (f , "cacert.pem" )
52+ # This is slightly terrible, but we want to delay extracting the
53+ # file in cases where we're inside of a zipimport situation until
54+ # someone actually calls where(), but we don't want to re-extract
55+ # the file on every call of where(), so we'll do it once then store
56+ # it in a global variable.
57+ global _CACERT_CTX
58+ global _CACERT_PATH
59+ if _CACERT_PATH is None :
60+ # This is slightly janky, the importlib.resources API wants you
61+ # to manage the cleanup of this file, so it doesn't actually
62+ # return a path, it returns a context manager that will give
63+ # you the path when you enter it and will do any cleanup when
64+ # you leave it. In the common case of not needing a temporary
65+ # file, it will just return the file system location and the
66+ # __exit__() is a no-op.
67+ #
68+ # We also have to hold onto the actual context manager, because
69+ # it will do the cleanup whenever it gets garbage collected, so
70+ # we will also store that at the global level as well.
71+ _CACERT_CTX = get_path ("certifi" , "cacert.pem" )
72+ _CACERT_PATH = str (_CACERT_CTX .__enter__ ())
6573
74+ return _CACERT_PATH
6675
67- def contents () -> str :
68- return read_text ("certifi" , "cacert.pem" , encoding = "ascii" )
76+ def contents () -> str :
77+ return read_text ("certifi" , "cacert.pem" , encoding = "ascii" )
0 commit comments