diff --git a/included_dependencies/certifi/core.py b/included_dependencies/certifi/core.py index 5d2b8cd3..5ca97800 100644 --- a/included_dependencies/certifi/core.py +++ b/included_dependencies/certifi/core.py @@ -8,52 +8,58 @@ This module returns the installation location of cacert.pem or its contents. """ import os -try: - from importlib.resources import path as get_path, read_text +## FFF change--`requests` already uses it's utils.extract_zipped_paths() +## on this, so the importlib.resources below is both redundant and +## sub-optimal--it apparently creates a new temp copy *every* time +## where() is called... - _CACERT_CTX = None - _CACERT_PATH = None +# try: +# from importlib.resources import path as get_path, read_text - def where(): - # This is slightly terrible, but we want to delay extracting the file - # in cases where we're inside of a zipimport situation until someone - # actually calls where(), but we don't want to re-extract the file - # on every call of where(), so we'll do it once then store it in a - # global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you to - # manage the cleanup of this file, so it doesn't actually return a - # path, it returns a context manager that will give you the path - # when you enter it and will do any cleanup when you leave it. In - # the common case of not needing a temporary file, it will just - # return the file system location and the __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = get_path("certifi", "cacert.pem") - _CACERT_PATH = str(_CACERT_CTX.__enter__()) +# _CACERT_CTX = None +# _CACERT_PATH = None - return _CACERT_PATH +# def where(): +# # This is slightly terrible, but we want to delay extracting the file +# # in cases where we're inside of a zipimport situation until someone +# # actually calls where(), but we don't want to re-extract the file +# # on every call of where(), so we'll do it once then store it in a +# # global variable. +# global _CACERT_CTX +# global _CACERT_PATH +# if _CACERT_PATH is None: +# # This is slightly janky, the importlib.resources API wants you to +# # manage the cleanup of this file, so it doesn't actually return a +# # path, it returns a context manager that will give you the path +# # when you enter it and will do any cleanup when you leave it. In +# # the common case of not needing a temporary file, it will just +# # return the file system location and the __exit__() is a no-op. +# # +# # We also have to hold onto the actual context manager, because +# # it will do the cleanup whenever it gets garbage collected, so +# # we will also store that at the global level as well. +# _CACERT_CTX = get_path("certifi", "cacert.pem") +# _CACERT_PATH = str(_CACERT_CTX.__enter__()) + +# return _CACERT_PATH -except ImportError: - # This fallback will work for Python versions prior to 3.7 that lack the - # importlib.resources module but relies on the existing `where` function - # so won't address issues with environments like PyOxidizer that don't set - # __file__ on modules. - def read_text(_module, _path, encoding="ascii"): - with open(where(), "r", encoding=encoding) as data: - return data.read() +# except ImportError: - # If we don't have importlib.resources, then we will just do the old logic - # of assuming we're on the filesystem and munge the path directly. - def where(): - f = os.path.dirname(__file__) +# This fallback will work for Python versions prior to 3.7 that lack the +# importlib.resources module but relies on the existing `where` function +# so won't address issues with environments like PyOxidizer that don't set +# __file__ on modules. +def read_text(_module, _path, encoding="ascii"): + with open(where(), "r", encoding=encoding) as data: + return data.read() - return os.path.join(f, "cacert.pem") +# If we don't have importlib.resources, then we will just do the old logic +# of assuming we're on the filesystem and munge the path directly. +def where(): + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") def contents(): diff --git a/included_dependencies/requests/utils.py b/included_dependencies/requests/utils.py index db67938e..e5b0b635 100644 --- a/included_dependencies/requests/utils.py +++ b/included_dependencies/requests/utils.py @@ -230,8 +230,32 @@ def guess_filename(obj): name[-1] != '>'): return os.path.basename(name) - def extract_zipped_paths(path): + ''' + FanFicFare calibre plugin code should extract only one copy of + each file and always to /fanficfare_files/... + + orig_extract_zipped_paths() extracts to /package/file, which + is *not* compared for age or anything. So it would be a hard bug + to track down when the bundled file changes but the code continues + to use the old tmp version anyway. Putting it under means it will be renewed each Calibre restart. + + orig_extract_zipped_paths is a bit inefficient in the way it + checks inside the zip file each time, but it's not bad enough to + completely re-do. + ''' + try: + from calibre.ptempfile import base_dir as calibre_base_dir + caltmpdir = os.path.join(calibre_base_dir(),"fanficfare_files") + if not os.path.isdir(caltmpdir): + os.mkdir(caltmpdir) + except: + caltmpdir = None + + return orig_extract_zipped_paths(path,tmp=caltmpdir) + +def orig_extract_zipped_paths(path,tmp=None): """Replace nonexistent paths that look like they refer to a member of a zip archive with the location of an extracted copy of the target, or else just return the provided path unchanged. @@ -255,7 +279,8 @@ def extract_zipped_paths(path): return path # we have a valid zip archive and a valid member of that archive - tmp = tempfile.gettempdir() + if not tmp: + tmp = tempfile.gettempdir() extracted_path = os.path.join(tmp, *member.split('/')) if not os.path.exists(extracted_path): extracted_path = zip_file.extract(member, path=tmp)