This would definitely seem to be down to plugin load order; for example:
a.py
import sublime
import sublime_plugin
from .a_settings import Settings
print("==> Settings import:", id(Settings))
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
print("Settings run: ", id(Settings))
a_settings.py
Settings = {}
print("==> Settings init:", id(Settings))
def plugin_loaded():
print("==> Settings set:", id(Settings))
On a fresh start, you see this in the console (redacting uninteresting bits):
reloading plugin A.a
==> Settings init: 2154390146440
==> Settings import: 2154390146440
reloading plugin A.a_settings
==> Settings init: 2154390145416
plugins loaded
==> Settings set: 2154390145416
>>> view.run_command("example")
Settings run: 2154390146440
When a.py
is loaded, it does an import
which causes a_settings.py
to initialize a dictionary which is given to a
; then Sublime loads the a_settings.py
plugin which replaces the dictionary with a new one.
When plugin_loaded
is called, it’s the new one that gets initialized, but the one in the command is still the original imported one. Saving the other file causes it to reload in a more controlled manner so that things work as expected.
Plugins load in lexical order and an import
of an already loaded plugin won’t cause it to reload (which causes problems all its own), so changing the names of the files would solve the problem, I would think. On the other hand I’m not 100% sure that the load order is officially documented versus just an implementation detail, so it may or may not be safe to rely on that if it works (on the other hand, PackageControl relies on this to set up dependency load order).
One potential solution would be to use a standard sublime-settings
file for this and let the core handle the setup of the settings, but that may not fit with your use case depending on what the Settings
dictionary here represents.
Another solution would be to have something in the second plugin return the instantiated object from a function call, then import the function instead:
a.py
import sublime
import sublime_plugin
from .a_settings import settings
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
print("Settings run: ", id(settings()))
print(settings()["first"])
a_settings.py
def settings():
print("==> Settings get:", id(settings.obj))
return settings.obj
def plugin_loaded():
settings.obj = {"first": "test"}
Now plugin_loaded()
still sets up the settings object, but it stashes it in a property of the settings()
function, and invoking the function returns the same object:
plugins loaded
>>> view.run_command("example")
==> Settings get: 2412655836296
Settings run: 2412655836296
==> Settings get: 2412655836296
test
There are likely other better solutions as well.