Skip to content

Commit bf1da5a

Browse files
committed
do full reload if allow_all_imports or hass_is_global change; see #74
1 parent b9781dc commit bf1da5a

File tree

4 files changed

+70
-19
lines changed

4 files changed

+70
-19
lines changed

custom_components/pyscript/__init__.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
CONF_ALLOW_ALL_IMPORTS,
3030
CONF_HASS_IS_GLOBAL,
3131
CONFIG_ENTRY,
32+
CONFIG_ENTRY_OLD,
3233
DOMAIN,
3334
FOLDER,
3435
LOGGER_PATH,
@@ -100,6 +101,24 @@ async def update_yaml_config(hass, config_entry):
100101
if config != config_entry.data:
101102
await hass.config_entries.flow.async_init(DOMAIN, context={"source": SOURCE_IMPORT}, data=config)
102103

104+
#
105+
# if hass_is_global or allow_all_imports have changed, we need to reload all scripts
106+
# since they affect all scripts
107+
#
108+
config_save = {
109+
param: config_entry.data.get(param, False) for param in {CONF_HASS_IS_GLOBAL, CONF_ALLOW_ALL_IMPORTS}
110+
}
111+
if DOMAIN not in hass.data:
112+
hass.data.setdefault(DOMAIN, {})
113+
if CONFIG_ENTRY_OLD in hass.data[DOMAIN]:
114+
old_entry = hass.data[DOMAIN][CONFIG_ENTRY_OLD]
115+
hass.data[DOMAIN][CONFIG_ENTRY_OLD] = config_save
116+
for param in {CONF_HASS_IS_GLOBAL, CONF_ALLOW_ALL_IMPORTS}:
117+
if old_entry.get(param, False) != config_entry.data.get(param, False):
118+
return True
119+
hass.data[DOMAIN][CONFIG_ENTRY_OLD] = config_save
120+
return False
121+
103122

104123
def start_global_contexts(global_ctx_only=None):
105124
"""Start all the file and apps global contexts."""
@@ -192,7 +211,7 @@ def check_event(event, do_reload):
192211
watchdog_q = asyncio.Queue(0)
193212
observer = watchdog.observers.Observer()
194213
if observer is not None:
195-
# don't run watchdog when we are testing (it patches to None)
214+
# don't run watchdog when we are testing (Observer() patches to None)
196215
hass.data[DOMAIN][WATCHDOG_OBSERVER] = observer
197216
hass.data[DOMAIN][WATCHDOG_TASK] = Function.create_task(task_watchdog(watchdog_q))
198217

@@ -201,11 +220,13 @@ def check_event(event, do_reload):
201220

202221
async def async_setup_entry(hass, config_entry):
203222
"""Initialize the pyscript config entry."""
223+
global_ctx_only = None
204224
if Function.hass:
205225
#
206226
# reload yaml if this isn't the first time (ie, on reload)
207227
#
208-
await update_yaml_config(hass, config_entry)
228+
if await update_yaml_config(hass, config_entry):
229+
global_ctx_only = "*"
209230

210231
Function.init(hass)
211232
Event.init(hass)
@@ -227,19 +248,20 @@ async def async_setup_entry(hass, config_entry):
227248
State.set_pyscript_config(config_entry.data)
228249

229250
await install_requirements(hass, config_entry, pyscript_folder)
230-
await load_scripts(hass, config_entry.data)
251+
await load_scripts(hass, config_entry.data, global_ctx_only=global_ctx_only)
231252

232253
async def reload_scripts_handler(call):
233254
"""Handle reload service calls."""
234255
_LOGGER.debug("reload: yaml, reloading scripts, and restarting")
235256

236-
await update_yaml_config(hass, config_entry)
257+
global_ctx_only = call.data.get("global_ctx", None) if call else None
258+
259+
if await update_yaml_config(hass, config_entry):
260+
global_ctx_only = "*"
237261
State.set_pyscript_config(config_entry.data)
238262

239263
await State.get_service_params()
240264

241-
global_ctx_only = call.data.get("global_ctx", None) if call else None
242-
243265
await install_requirements(hass, config_entry, pyscript_folder)
244266
await load_scripts(hass, config_entry.data, global_ctx_only=global_ctx_only)
245267

@@ -333,14 +355,13 @@ async def hass_stop(event):
333355

334356
async def async_unload_entry(hass, config_entry):
335357
"""Unload a config entry."""
336-
# Unload scripts
358+
_LOGGER.info("Unloading all scripts")
337359
await unload_scripts()
338360

339-
# Unsubscribe from listeners
340361
for unsub_listener in hass.data[DOMAIN][UNSUB_LISTENERS]:
341362
unsub_listener()
363+
hass.data[DOMAIN][UNSUB_LISTENERS] = []
342364

343-
hass.data.pop(DOMAIN)
344365
return True
345366

346367

custom_components/pyscript/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
DOMAIN = "pyscript"
44

55
CONFIG_ENTRY = "config_entry"
6+
CONFIG_ENTRY_OLD = "config_entry_old"
67
UNSUB_LISTENERS = "unsub_listeners"
78

89
FOLDER = "pyscript"

docs/reference.rst

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Configuration
99
Pyscript can be configured using the UI, or via yaml. To use the UI, go to the
1010
Configuration -> Integrations page and selection "+" to add ``Pyscript Python scripting``.
1111
After that, you can change the settings anytime by selecting "Options" under Pyscript
12-
in the Configuration page. You will need to select "reload" under Pyscript, or call
13-
the ``pyscript.reload`` service for the new settings to take effect.
12+
in the Configuration -> Integrations page. You will need to select "reload" under Pyscript,
13+
or call the ``pyscript.reload`` service for the new settings to take effect.
1414

1515
Alternatively, for yaml configuration, add ``pyscript:`` to ``<config>/configuration.yaml``.
1616
You can't mix these two methods - your initial choice determines how you should update
@@ -135,13 +135,13 @@ Reloading Scripts
135135
Manually reloading scripts via the ``pyscript.reload`` service is no longer necessary starting
136136
in 1.2.0, since changes are automatically detected and a reload is triggered.
137137

138-
By default, reloading only reloads scripts, apps or modules that have changed since they were last
139-
loaded. A change means the script, app or module file contents or modification time has changed.
140-
Additionally, an app is considered changed if its yaml configuration has changed. When a change is
141-
detected, additional files are also reloaded if they depend on a changed file. Additional files
142-
include all other files in a particular module or app (meaning the entire module or app is reloaded
143-
if any of its files or imports are changed), and if a module has changed, any other module, app or
144-
script that imports that module directly or indirectly is reloaded too.
138+
By default, calling the reload service only reloads scripts, apps or modules that have changed since
139+
they were last loaded. A change means the script, app or module file contents or modification time
140+
has changed. Additionally, an app is considered changed if its yaml configuration has changed. When
141+
a change is detected, additional files are also reloaded if they depend on a changed file.
142+
Additional files include all other files in a particular module or app (meaning the entire module or
143+
app is reloaded if any of its files or imports are changed), and if a module has changed, any other
144+
module, app or script that imports that module directly or indirectly is reloaded too.
145145

146146
A file is also considered changed if it is newly created or deleted (or "commented" by renaming it
147147
or a parent directory to start with ``#``). When reload detects a deleted file, the prior global
@@ -157,7 +157,8 @@ Additional files might still be reloaded too (all other files in the module or a
157157
modules, apps or scripts that import a module if ``global_ctx`` was set to a module).
158158

159159
If you want to manually reload all scripts, apps and modules, set ``global_ctx`` to ``*`` when
160-
you call ``pyscript.reload``.
160+
you call ``pyscript.reload``. Alternatively, the ``Reload`` option under pyscript in the
161+
in the Configuration -> Integrations page will always do a full reload.
161162

162163
Any function definitions, services and triggers in the reloaded files are re-created. Jupyter
163164
sessions are not affected. Any currently running functions (ie, functions that have been triggered

tests/test_unit_eval.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,34 @@ def func(incr):
703703
],
704704
[
705705
"""
706+
def f1(value):
707+
i = 1
708+
def f2(value):
709+
i = 2
710+
def f3(value):
711+
return value + i
712+
return f3(2 * value)
713+
return f2(2 * value)
714+
f1(10)
715+
""",
716+
42,
717+
],
718+
[
719+
"""
720+
def f1(value):
721+
i = 1
722+
def f2(value):
723+
i = 2
724+
def f3():
725+
return value + i
726+
return f3()
727+
return f2(2 * value)
728+
f1(10)
729+
""",
730+
22,
731+
],
732+
[
733+
"""
706734
def foo():
707735
global f_bar
708736
def f_bar():

0 commit comments

Comments
 (0)