Skip to content

Commit 38f90dd

Browse files
committed
update reloader code
1 parent 81d243b commit 38f90dd

File tree

1 file changed

+83
-12
lines changed

1 file changed

+83
-12
lines changed

unittesting/utils/reloader.py

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,75 @@
1111
from .stack_meter import StackMeter
1212

1313

14+
try:
15+
from package_control.package_manager import PackageManager
16+
17+
def is_dependency(pkg_name):
18+
return PackageManager()._is_dependency(pkg_name)
19+
20+
except ImportError:
21+
def is_dependency(pkg_name):
22+
return False
23+
24+
1425
def dprint(*args, fill=None, fill_width=60, **kwargs):
1526
if fill is not None:
1627
sep = str(kwargs.get('sep', ' '))
1728
caption = sep.join(args)
1829
args = "{0:{fill}<{width}}".format(caption and caption + sep,
1930
fill=fill, width=fill_width),
20-
print("[UnitTesting]", *args, **kwargs)
31+
print("[Package Reloader]", *args, **kwargs)
32+
33+
34+
def path_contains(a, b):
35+
return a == b or b.startswith(a + os.sep)
36+
37+
38+
def get_package_modules(pkg_name):
39+
in_installed_path = functools.partial(
40+
path_contains,
41+
os.path.join(
42+
sublime.installed_packages_path(),
43+
pkg_name + '.sublime-package'
44+
)
45+
)
46+
47+
in_package_path = functools.partial(
48+
path_contains,
49+
os.path.join(sublime.packages_path(), pkg_name)
50+
)
51+
52+
def module_in_package(module):
53+
file = getattr(module, '__file__', '')
54+
paths = getattr(module, '__path__', ())
55+
return (
56+
in_installed_path(file) or any(map(in_installed_path, paths)) or
57+
in_package_path(file) or any(map(in_package_path, paths))
58+
)
59+
60+
return {
61+
name: module
62+
for name, module in sys.modules.items()
63+
if module_in_package(module)
64+
}
2165

2266

2367
# check the link for comments
2468
# https://github.com/divmain/GitSavvy/blob/599ba3cdb539875568a96a53fafb033b01708a67/common/util/reload.py
2569
def reload_package(pkg_name, dummy=True, verbose=True):
70+
if is_dependency(pkg_name):
71+
reload_dependency(pkg_name, dummy, verbose)
72+
return
73+
2674
if pkg_name not in sys.modules:
2775
dprint("error:", pkg_name, "is not loaded.")
2876
return
2977

30-
main = sys.modules[pkg_name]
31-
3278
if verbose:
3379
dprint("begin", fill='=')
3480

35-
modules = {main.__name__: main}
36-
modules.update({name: module for name, module in sys.modules.items()
37-
if name.startswith(pkg_name + ".")})
81+
modules = get_package_modules(pkg_name)
82+
3883
for m in modules:
3984
if m in sys.modules:
4085
sublime_plugin.unload_module(modules[m])
@@ -44,7 +89,7 @@ def reload_package(pkg_name, dummy=True, verbose=True):
4489
with intercepting_imports(modules, verbose), \
4590
importing_fromlist_aggresively(modules):
4691

47-
reload_plugin(main.__name__)
92+
reload_plugin(pkg_name)
4893
except Exception:
4994
dprint("reload failed.", fill='-')
5095
reload_missing(modules, verbose)
@@ -57,6 +102,27 @@ def reload_package(pkg_name, dummy=True, verbose=True):
57102
dprint("end", fill='-')
58103

59104

105+
def reload_dependency(dependency_name, dummy=True, verbose=True):
106+
"""
107+
Package Control dependencies aren't regular packages, so we don't want to
108+
call `sublime_plugin.unload_module` or `sublime_plugin.reload_plugin`.
109+
Instead, we manually unload all of the modules in the dependency and then
110+
`reload_package` any packages that use that dependency. (We have to manually
111+
unload the dependency's modules because calling `reload_package` on a
112+
dependent module will not unload the dependency.)
113+
"""
114+
for name in get_package_modules(dependency_name):
115+
del sys.modules[name]
116+
117+
manager = PackageManager()
118+
for package in manager.list_packages():
119+
if dependency_name in manager.get_dependencies(package):
120+
reload_package(package, dummy=False, verbose=verbose)
121+
122+
if dummy:
123+
load_dummy(verbose)
124+
125+
60126
def load_dummy(verbose):
61127
"""
62128
Hack to trigger automatic "reloading plugins".
@@ -67,20 +133,25 @@ def load_dummy(verbose):
67133
dprint("installing dummy package")
68134
dummy = "_dummy_package"
69135
dummy_py = os.path.join(sublime.packages_path(), "%s.py" % dummy)
70-
open(dummy_py, "w").close()
136+
with open(dummy_py, "w"):
137+
pass
71138

72139
def remove_dummy(trial=0):
73140
if dummy in sys.modules:
74141
if verbose:
75142
dprint("removing dummy package")
76-
if os.path.exists(dummy_py):
143+
try:
77144
os.unlink(dummy_py)
145+
except FileNotFoundError:
146+
pass
78147
after_remove_dummy()
79148
elif trial < 300:
80149
threading.Timer(0.1, lambda: remove_dummy(trial + 1)).start()
81150
else:
82-
if os.path.exists(dummy_py):
151+
try:
83152
os.unlink(dummy_py)
153+
except FileNotFoundError:
154+
pass
84155

85156
condition = threading.Condition()
86157

@@ -112,8 +183,8 @@ def reload_missing(modules, verbose):
112183

113184
def reload_plugin(pkg_name):
114185
pkg_path = os.path.join(os.path.realpath(sublime.packages_path()), pkg_name)
115-
plugins = [pkg_name + "." + os.path.splitext(f)[0]
116-
for f in os.listdir(pkg_path) if f.endswith(".py")]
186+
plugins = [pkg_name + "." + os.path.splitext(file_path)[0]
187+
for file_path in os.listdir(pkg_path) if file_path.endswith(".py")]
117188
for plugin in plugins:
118189
sublime_plugin.reload_plugin(plugin)
119190

0 commit comments

Comments
 (0)