gradio

Форк
0
/
unload_modules.py 
165 строк · 5.8 Кб
1
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)
2
# Copyright (c) Yuichiro Tachibana (2023)
3
#
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15

16
import fnmatch
17
import logging
18
import os
19
import sys
20
import types
21
from typing import Optional, Set
22

23
LOGGER = logging.getLogger(__name__)
24

25
#
26
# Copied from https://github.com/streamlit/streamlit/blob/1.24.0/lib/streamlit/file_util.py
27
#
28

29
def file_is_in_folder_glob(filepath, folderpath_glob) -> bool:
30
    """Test whether a file is in some folder with globbing support.
31

32
    Parameters
33
    ----------
34
    filepath : str
35
        A file path.
36
    folderpath_glob: str
37
        A path to a folder that may include globbing.
38

39
    """
40
    # Make the glob always end with "/*" so we match files inside subfolders of
41
    # folderpath_glob.
42
    if not folderpath_glob.endswith("*"):
43
        if folderpath_glob.endswith("/"):
44
            folderpath_glob += "*"
45
        else:
46
            folderpath_glob += "/*"
47

48
    file_dir = os.path.dirname(filepath) + "/"
49
    return fnmatch.fnmatch(file_dir, folderpath_glob)
50

51

52
def get_directory_size(directory: str) -> int:
53
    """Return the size of a directory in bytes."""
54
    total_size = 0
55
    for dirpath, _, filenames in os.walk(directory):
56
        for f in filenames:
57
            fp = os.path.join(dirpath, f)
58
            total_size += os.path.getsize(fp)
59
    return total_size
60

61

62
def file_in_pythonpath(filepath) -> bool:
63
    """Test whether a filepath is in the same folder of a path specified in the PYTHONPATH env variable.
64

65

66
    Parameters
67
    ----------
68
    filepath : str
69
        An absolute file path.
70

71
    Returns
72
    -------
73
    boolean
74
        True if contained in PYTHONPATH, False otherwise. False if PYTHONPATH is not defined or empty.
75

76
    """
77
    pythonpath = os.environ.get("PYTHONPATH", "")
78
    if len(pythonpath) == 0:
79
        return False
80

81
    absolute_paths = [os.path.abspath(path) for path in pythonpath.split(os.pathsep)]
82
    return any(
83
        file_is_in_folder_glob(os.path.normpath(filepath), path)
84
        for path in absolute_paths
85
    )
86

87
#
88
# Copied from https://github.com/streamlit/streamlit/blob/1.24.0/lib/streamlit/watcher/local_sources_watcher.py
89
#
90

91
def get_module_paths(module: types.ModuleType) -> Set[str]:
92
    paths_extractors = [
93
        # https://docs.python.org/3/reference/datamodel.html
94
        # __file__ is the pathname of the file from which the module was loaded
95
        # if it was loaded from a file.
96
        # The __file__ attribute may be missing for certain types of modules
97
        lambda m: [m.__file__],
98
        # https://docs.python.org/3/reference/import.html#__spec__
99
        # The __spec__ attribute is set to the module spec that was used
100
        # when importing the module. one exception is __main__,
101
        # where __spec__ is set to None in some cases.
102
        # https://www.python.org/dev/peps/pep-0451/#id16
103
        # "origin" in an import context means the system
104
        # (or resource within a system) from which a module originates
105
        # ... It is up to the loader to decide on how to interpret
106
        # and use a module's origin, if at all.
107
        lambda m: [m.__spec__.origin],
108
        # https://www.python.org/dev/peps/pep-0420/
109
        # Handling of "namespace packages" in which the __path__ attribute
110
        # is a _NamespacePath object with a _path attribute containing
111
        # the various paths of the package.
112
        lambda m: list(m.__path__._path),
113
    ]
114

115
    all_paths = set()
116
    for extract_paths in paths_extractors:
117
        potential_paths = []
118
        try:
119
            potential_paths = extract_paths(module)
120
        except AttributeError:
121
            # Some modules might not have __file__ or __spec__ attributes.
122
            pass
123
        except Exception as e:
124
            LOGGER.warning(f"Examining the path of {module.__name__} raised: {e}")
125

126
        all_paths.update(
127
            [os.path.abspath(str(p)) for p in potential_paths if _is_valid_path(p)]
128
        )
129
    return all_paths
130

131

132
def _is_valid_path(path: Optional[str]) -> bool:
133
    return isinstance(path, str) and (os.path.isfile(path) or os.path.isdir(path))
134

135

136
#
137
# Original code
138
#
139

140
def unload_local_modules(target_dir_path: str = "."):
141
    """ Unload all modules that are in the target directory or in a subdirectory of it.
142
    It is necessary to unload modules before re-executing a script that imports the modules,
143
    so that the new version of the modules is loaded.
144
    The module unloading feature is extracted from Streamlit's LocalSourcesWatcher (https://github.com/streamlit/streamlit/blob/1.24.0/lib/streamlit/watcher/local_sources_watcher.py)
145
    and packaged as a standalone function.
146
    """
147
    target_dir_path = os.path.abspath(target_dir_path)
148
    loaded_modules = {} # filepath -> module_name
149

150
    # Copied from `LocalSourcesWatcher.update_watched_modules()`
151
    module_paths = {
152
        name: get_module_paths(module)
153
        for name, module in dict(sys.modules).items()
154
    }
155

156
    # Copied from `LocalSourcesWatcher._register_necessary_watchers()`
157
    for name, paths in module_paths.items():
158
        for path in paths:
159
            if file_is_in_folder_glob(path, target_dir_path) or file_in_pythonpath(path):
160
                loaded_modules[path] = name
161

162
    # Copied from `LocalSourcesWatcher.on_file_changed()`
163
    for module_name in loaded_modules.values():
164
        if module_name is not None and module_name in sys.modules:
165
            del sys.modules[module_name]
166

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.