1+ # -*- coding: utf-8 -*-
2+
13"""
24certifi.py
35~~~~~~~~~~
46
57This module returns the installation location of cacert.pem or its contents.
68"""
79import os
8- import types
9- from typing import Union
10+ import sys
11+
12+
13+ if sys .version_info >= (3 , 9 ):
1014
11- try :
12- from importlib .resources import path as get_path , read_text
15+ from importlib .resources import as_file , files
1316
1417 _CACERT_CTX = None
1518 _CACERT_PATH = None
@@ -33,36 +36,59 @@ def where() -> str:
3336 # We also have to hold onto the actual context manager, because
3437 # it will do the cleanup whenever it gets garbage collected, so
3538 # we will also store that at the global level as well.
36- _CACERT_CTX = get_path ( "certifi" , "cacert.pem" )
39+ _CACERT_CTX = as_file ( files ( "certifi" ). joinpath ( "cacert.pem" ) )
3740 _CACERT_PATH = str (_CACERT_CTX .__enter__ ())
3841
3942 return _CACERT_PATH
4043
44+ else :
4145
42- except ImportError :
43- Package = Union [types .ModuleType , str ]
44- Resource = Union [str , "os.PathLike" ]
45-
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 ()
58-
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.
61- def where () -> str :
62- 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__ )
6388
64- return os .path .join (f , "cacert.pem" )
89+ return os .path .join (f , "cacert.pem" )
6590
6691
6792def contents () -> str :
68- return read_text ("certifi" , "cacert.pem" , encoding = "ascii" )
93+ with open (where (), "r" , encoding = "ascii" ) as fp :
94+ return fp .read ()
0 commit comments