4242 contextvars .ContextVar ("_sandbox_sys_modules" , default = None )
4343)
4444
45+ # Extra passthrough modules for the active sandbox, from
46+ # SandboxPolicy.passthrough_modules.
47+ _policy_passthroughs : contextvars .ContextVar [frozenset [str ]] = contextvars .ContextVar (
48+ "_policy_passthroughs" , default = frozenset ()
49+ )
50+
4551
4652class SandboxRestrictionError (RuntimeError ):
4753 """Raised when workflow code calls a non-deterministic function."""
@@ -573,9 +579,10 @@ def __init__(
573579 self ._blocked = blocked or set ()
574580
575581 def _is_passthrough (self , name : str ) -> bool :
576- for prefix in self ._passthrough :
577- if name == prefix or name .startswith (prefix + "." ):
578- return True
582+ for prefixes in (self ._passthrough , _policy_passthroughs .get ()):
583+ for prefix in prefixes :
584+ if name == prefix or name .startswith (prefix + "." ):
585+ return True
579586 return False
580587
581588 def find_spec (
@@ -921,9 +928,17 @@ class SandboxPolicy:
921928 A handler that raises is logged and skipped, and never masks the
922929 workflow's own exception. Handlers must be thread-safe: other runs
923930 may be executing concurrently.
931+
932+ ``passthrough_modules`` are extra modules — each name covering its
933+ submodules too — served from the host instead of re-imported per
934+ run, in addition to the built-in passthrough set. Use for large or
935+ stateful modules that are safe to share; nothing checks them for
936+ nondeterminism, and their state is shared with the host and every
937+ concurrent run.
924938 """
925939
926940 cleanups : tuple [CleanupHandler , ...] = ()
941+ passthrough_modules : frozenset [str ] = frozenset ()
927942
928943
929944# TODO: we probably want to support some form of sandbox caching
@@ -946,9 +961,11 @@ def workflow_sandbox(*, random_seed: str, policy: SandboxPolicy | None = None) -
946961 table_token = _sandbox_sys_modules .set (table )
947962 sandbox_token = _in_sandbox .set (True )
948963 random_token = _sandbox_random .set (random .Random (random_seed ))
964+ passthrough_token = _policy_passthroughs .set (frozenset (policy .passthrough_modules ))
949965 try :
950966 yield
951967 finally :
968+ _policy_passthroughs .reset (passthrough_token )
952969 _sandbox_random .reset (random_token )
953970 _in_sandbox .reset (sandbox_token )
954971 _sandbox_sys_modules .reset (table_token )
0 commit comments