1111from .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+
1425def dprint (* args , fill = None , fill_width = 60 , ** kwargs ):
1526 if fill is not None :
1627 sep = str (kwargs .get ('sep' , ' ' ))
@@ -20,21 +31,55 @@ def dprint(*args, fill=None, fill_width=60, **kwargs):
2031 print ("[UnitTesting]" , * args , ** kwargs )
2132
2233
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+ }
65+
66+
2367# check the link for comments
2468# https://github.com/divmain/GitSavvy/blob/599ba3cdb539875568a96a53fafb033b01708a67/common/util/reload.py
2569def 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,29 @@ 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+ Reload a Package Control dependency.
108+
109+ Package Control dependencies aren't regular packages, so we don't want to
110+ call `sublime_plugin.unload_module` or `sublime_plugin.reload_plugin`.
111+ Instead, we manually unload all of the modules in the dependency and then
112+ `reload_package` any packages that use that dependency. (We have to manually
113+ unload the dependency's modules because calling `reload_package` on a
114+ dependent module will not unload the dependency.)
115+ """
116+ for name in get_package_modules (dependency_name ):
117+ del sys .modules [name ]
118+
119+ manager = PackageManager ()
120+ for package in manager .list_packages ():
121+ if dependency_name in manager .get_dependencies (package ):
122+ reload_package (package , dummy = False , verbose = verbose )
123+
124+ if dummy :
125+ load_dummy (verbose )
126+
127+
60128def load_dummy (verbose ):
61129 """
62130 Hack to trigger automatic "reloading plugins".
@@ -67,20 +135,25 @@ def load_dummy(verbose):
67135 dprint ("installing dummy package" )
68136 dummy = "_dummy_package"
69137 dummy_py = os .path .join (sublime .packages_path (), "%s.py" % dummy )
70- open (dummy_py , "w" ).close ()
138+ with open (dummy_py , "w" ):
139+ pass
71140
72141 def remove_dummy (trial = 0 ):
73142 if dummy in sys .modules :
74143 if verbose :
75144 dprint ("removing dummy package" )
76- if os . path . exists ( dummy_py ) :
145+ try :
77146 os .unlink (dummy_py )
147+ except FileNotFoundError :
148+ pass
78149 after_remove_dummy ()
79150 elif trial < 300 :
80151 threading .Timer (0.1 , lambda : remove_dummy (trial + 1 )).start ()
81152 else :
82- if os . path . exists ( dummy_py ) :
153+ try :
83154 os .unlink (dummy_py )
155+ except FileNotFoundError :
156+ pass
84157
85158 condition = threading .Condition ()
86159
@@ -112,8 +185,8 @@ def reload_missing(modules, verbose):
112185
113186def reload_plugin (pkg_name ):
114187 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" )]
188+ plugins = [pkg_name + "." + os .path .splitext (file_path )[0 ]
189+ for file_path in os .listdir (pkg_path ) if file_path .endswith (".py" )]
117190 for plugin in plugins :
118191 sublime_plugin .reload_plugin (plugin )
119192
0 commit comments