77This module returns the installation location of cacert.pem or its contents.
88"""
99import os
10- import types
11- from typing import Union
10+ import sys
1211
13- try :
14- from importlib .resources import path as get_path , read_text
12+
13+ if sys .version_info >= (3 , 9 ):
14+
15+ from importlib .resources import as_file , files
1516
1617 _CACERT_CTX = None
1718 _CACERT_PATH = None
@@ -35,36 +36,59 @@ def where() -> str:
3536 # We also have to hold onto the actual context manager, because
3637 # it will do the cleanup whenever it gets garbage collected, so
3738 # we will also store that at the global level as well.
38- _CACERT_CTX = get_path ( "certifi" , "cacert.pem" )
39+ _CACERT_CTX = as_file ( files ( "certifi" ). joinpath ( "cacert.pem" ) )
3940 _CACERT_PATH = str (_CACERT_CTX .__enter__ ())
4041
4142 return _CACERT_PATH
4243
44+ else :
4345
44- except ImportError :
45- Package = Union [types .ModuleType , str ]
46- Resource = Union [str , "os.PathLike" ]
47-
48- # This fallback will work for Python versions prior to 3.7 that lack the
49- # importlib.resources module but relies on the existing `where` function
50- # so won't address issues with environments like PyOxidizer that don't set
51- # __file__ on modules.
52- def read_text (
53- package : Package ,
54- resource : Resource ,
55- encoding : str = 'utf-8' ,
56- errors : str = 'strict'
57- ) -> str :
58- with open (where (), "r" , encoding = encoding ) as data :
59- return data .read ()
60-
61- # If we don't have importlib.resources, then we will just do the old logic
62- # of assuming we're on the filesystem and munge the path directly.
63- def where () -> str :
64- f = os .path .dirname (__file__ )
46+ try :
47+ from importlib .resources import path as get_path
48+
49+ _CACERT_CTX = None
50+ _CACERT_PATH = None
51+
52+ def where () -> str :
53+ # This is slightly terrible, but we want to delay extracting the
54+ # file in cases where we're inside of a zipimport situation until
55+ # someone actually calls where(), but we don't want to re-extract
56+ # the file on every call of where(), so we'll do it once then store
57+ # it in a global variable.
58+ global _CACERT_CTX
59+ global _CACERT_PATH
60+ if _CACERT_PATH is None :
61+ # This is slightly janky, the importlib.resources API wants you
62+ # to manage the cleanup of this file, so it doesn't actually
63+ # return a path, it returns a context manager that will give
64+ # you the path when you enter it and will do any cleanup when
65+ # you leave it. In the common case of not needing a temporary
66+ # file, it will just return the file system location and the
67+ # __exit__() is a no-op.
68+ #
69+ # We also have to hold onto the actual context manager, because
70+ # it will do the cleanup whenever it gets garbage collected, so
71+ # we will also store that at the global level as well.
72+ _CACERT_CTX = get_path ("certifi" , "cacert.pem" )
73+ _CACERT_PATH = str (_CACERT_CTX .__enter__ ())
74+
75+ return _CACERT_PATH
76+
77+ except ImportError :
78+ # This fallback will work for Python versions prior to 3.7 that lack
79+ # the importlib.resources module but relies on the existing `where`
80+ # function so won't address issues with environments like PyOxidizer
81+ # that don't set __file__ on modules.
82+
83+ # If we don't have importlib.resources, then we will just do the old
84+ # logic of assuming we're on the filesystem and munge the path
85+ # directly.
86+ def where () -> str :
87+ f = os .path .dirname (__file__ )
6588
66- return os .path .join (f , "cacert.pem" )
89+ return os .path .join (f , "cacert.pem" )
6790
6891
6992def contents () -> str :
70- return read_text ("certifi" , "cacert.pem" , encoding = "ascii" )
93+ with open (where (), encoding = "ascii" ) as fp :
94+ return fp .read ()
0 commit comments