Scopes and application integration
Use hydra.utils.execution_whitelist() when trusted code calls instantiate()
indirectly, when several instantiate() calls share a whitelist, or when
Python logging configured by Hydra needs the same policy.
Direct calls
For one direct instantiate() call, pass the expected targets from trusted
Python code:
from hydra.utils import instantiate
model = instantiate(
cfg.model,
_execution_whitelist_="my_app.models.*",
)
Use execution_whitelist() as a context manager when trusted code calls
instantiate() indirectly, so there is no direct call site at which to pass
_execution_whitelist_. A context is also useful when a block performs several
instantiate() calls or configures logging through Hydra:
from hydra.utils import execution_whitelist
with execution_whitelist("my_app.*"):
build_components(cfg)
Nested contexts
Nested contexts are additive by default. The inner context permits the union of the outer and inner entries. Exiting the inner block restores the exact outer policy, including when the block exits because of an exception:
with execution_whitelist("my_app.models.*"):
with execution_whitelist("my_app.optimizers.*"):
build_training_components(cfg) # Both entries are active.
instantiate(cfg.model) # Only my_app.models.* remains active.
Use reset=True when the inner operation must use exactly its supplied policy
instead of adding to the outer context:
with execution_whitelist("my_app.*"):
with execution_whitelist("my_app.models.*", reset=True):
instantiate(cfg.model)
A whitelist passed directly to instantiate() also adds to the active context.
Pass a resetting policy to make the call-site policy authoritative:
model = instantiate(
cfg.model,
_execution_whitelist_=execution_whitelist(
"my_app.models.*",
reset=True,
),
)
An additive inner context does not reinstate checks if an outer context uses
UNSAFE_DISABLE_EXECUTION_CHECKS. Use reset=True with an explicit whitelist
to restore enforcement for the inner operation.
Share a whitelist between call sites
If several trusted call sites must use the same whitelist, define one immutable value in a small leaf module that imports no application modules:
# my_app/execution_policy.py
from typing import Final
EXECUTION_WHITELIST: Final[tuple[str, ...]] = (
"my_app.logging.CustomHandler",
"my_app.models.*",
)
String target names avoid import cycles and import-time side effects. The tuple
cannot be changed in place, and Final lets static type checkers reject
rebinding. Import this value wherever the same policy is required:
# my_app/main.py
import hydra
from my_app.execution_policy import EXECUTION_WHITELIST
@hydra.main(
version_base=None,
config_path="conf",
config_name="config",
execution_whitelist=EXECUTION_WHITELIST,
)
def my_app(cfg):
...
These precautions prevent accidental changes; malicious code that is already running can still monkeypatch the policy module. The execution whitelist does not provide a security boundary against code that is already executing in the process.
Frameworks and plugins
Application code
An application integrating a third-party framework remains responsible only for its application-owned targets. It supplies that policy around the framework call and does not maintain the framework's internal whitelist:
# my_app/main.py — application-owned code
from hydra.utils import execution_whitelist
from training_framework.training import train
with execution_whitelist("my_app.*"):
train(cfg)
Framework and plugin code
Framework authors should authorize only framework-owned targets around their internal Hydra calls. For example, a training framework can authorize its built-in models and datasets while still accepting application-owned implementations through the outer policy:
# training_framework/training.py — code shipped by the framework
from hydra.utils import execution_whitelist, instantiate
def train(cfg):
with execution_whitelist(
(
"training_framework.models.*",
"training_framework.datasets.*",
)
):
model = instantiate(cfg.model)
dataset = instantiate(cfg.dataset)
train_model(model, dataset)
While the framework instantiates the model and dataset, both its inner policy and the application's outer policy are active. The configuration can therefore select either framework-provided or application-provided implementations.
The same ownership rule applies to Hydra plugins. Hydra instantiates launcher
and sweeper plugin configs non-recursively. If a plugin config contains nested
_target_ values, the plugin author should call instantiate() with a
plugin-owned whitelist. Application authors remain responsible for targets
owned by their applications.
Async tasks and application-created threads
The whitelist context is isolated between overlapping async tasks. It is not guaranteed to propagate into threads created by application code. Re-establish it at the worker boundary from a trusted Python constant:
from concurrent.futures import ThreadPoolExecutor
from hydra.utils import execution_whitelist, instantiate
from my_app.execution_policy import EXECUTION_WHITELIST
def build_model(model_cfg):
with execution_whitelist(EXECUTION_WHITELIST, reset=True):
return instantiate(model_cfg)
with ThreadPoolExecutor() as executor:
model = executor.submit(build_model, cfg.model).result()
For a single instantiate() call in a worker, pass the same resetting policy at
the call site:
model = instantiate(
cfg.model,
_execution_whitelist_=execution_whitelist(
EXECUTION_WHITELIST,
reset=True,
),
)
reset=True makes the trusted worker policy authoritative instead of adding it
to any execution whitelist that happens to be active in that thread.