From ce336bb2cfecc2827ea8ac71eb1095fca4b2d4a9 Mon Sep 17 00:00:00 2001 From: HansBug Date: Fri, 27 Oct 2023 12:23:02 +0800 Subject: [PATCH] dev(hansbug): add backport support for tempfile in Python3.10 --- hbutils/system/filesystem/tempfile.py | 77 ++++++++++++++++++++++++++- requirements-doc.txt | 2 +- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/hbutils/system/filesystem/tempfile.py b/hbutils/system/filesystem/tempfile.py index c0d750645bf..2ac27653fd5 100644 --- a/hbutils/system/filesystem/tempfile.py +++ b/hbutils/system/filesystem/tempfile.py @@ -6,6 +6,7 @@ import platform import shutil import tempfile +import types import warnings import weakref @@ -15,8 +16,82 @@ _python_version_tuple = tuple(map(int, platform.python_version_tuple())) -if _python_version_tuple >= (3, 8): +if _python_version_tuple >= (3, 10): from tempfile import TemporaryDirectory + +elif _python_version_tuple >= (3, 8): + class TemporaryDirectory: + """Create and return a temporary directory. This has the same + behavior as mkdtemp but can be used as a context manager. For + example: + + with TemporaryDirectory() as tmpdir: + ... + + Upon exiting the context, the directory and everything contained + in it are removed. + """ + + def __init__(self, suffix=None, prefix=None, dir=None, + ignore_cleanup_errors=False): + self.name = tempfile.mkdtemp(suffix, prefix, dir) + self._ignore_cleanup_errors = ignore_cleanup_errors + self._finalizer = weakref.finalize( + self, self._cleanup, self.name, + warn_message="Implicitly cleaning up {!r}".format(self), + ignore_errors=self._ignore_cleanup_errors) + + @classmethod + def _rmtree(cls, name, ignore_errors=False): + def onerror(func, path, exc_info): + if issubclass(exc_info[0], PermissionError): + def resetperms(path): + try: + os.chflags(path, 0) + except AttributeError: + pass + os.chmod(path, 0o700) + + try: + if path != name: + resetperms(os.path.dirname(path)) + resetperms(path) + + try: + os.unlink(path) + # PermissionError is raised on FreeBSD for directories + except (IsADirectoryError, PermissionError): + cls._rmtree(path, ignore_errors=ignore_errors) + except FileNotFoundError: + pass + elif issubclass(exc_info[0], FileNotFoundError): + pass + else: + if not ignore_errors: + raise + + shutil.rmtree(name, onerror=onerror) + + @classmethod + def _cleanup(cls, name, warn_message, ignore_errors=False): + cls._rmtree(name, ignore_errors=ignore_errors) + warnings.warn(warn_message, ResourceWarning) + + def __repr__(self): + return "<{} {!r}>".format(self.__class__.__name__, self.name) + + def __enter__(self): + return self.name + + def __exit__(self, exc, value, tb): + self.cleanup() + + def cleanup(self): + if self._finalizer.detach() or os.path.exists(self.name): + self._rmtree(self.name, ignore_errors=self._ignore_cleanup_errors) + + __class_getitem__ = classmethod(types.GenericAlias) + else: class TemporaryDirectory(object): """ diff --git a/requirements-doc.txt b/requirements-doc.txt index fb0ddf9259c..3b30ef742c0 100644 --- a/requirements-doc.txt +++ b/requirements-doc.txt @@ -1,7 +1,7 @@ Jinja2~=3.0.0 sphinx~=3.2.0 sphinx_rtd_theme~=0.4.3 -enum_tools +enum_tools~=0.9.0 sphinx-toolbox plantumlcli>=0.0.2 packaging