🚧 Add environment maneuverability

This commit is contained in:
Jonas Bengtsson
2026-10-04 22:48:10 +02:00
parent 68d3c42d79
commit 647c209e89
15 changed files with 850 additions and 46 deletions
+23 -1
View File
@@ -23,6 +23,7 @@ constructed on an engine.
from __future__ import annotations
import os
from collections.abc import Callable
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
@@ -312,14 +313,29 @@ class PlantEnv:
def load_env(ref: str, node: VirtualNode | None = None, *,
engine=None) -> PlantEnv:
engine=None, reload: bool = False) -> PlantEnv:
"""Load an environment from a module reference (FR-8.2.17).
Accepts ``pkg.mod.ClassName``, ``pkg.mod.factory_fn`` (returns a
PlantEnv), or a bare ``pkg.mod`` whose module defines either a
class named ``Env`` or a function ``make_env(...)``.
``reload=True`` (FR-10.2.17) invalidates the cached module first:
Python keeps modules in ``sys.modules``, so re-importing an
edited file would silently reuse the old class. Used by the web
UI's start/restart; the CLI runners start a fresh process anyway
and pass the default.
"""
import importlib
import sys
# environments resolve from the WORKING DIRECTORY by contract
# (``envs/`` is not part of the installed package). A console
# script puts its Scripts dir — not the cwd — on sys.path, so
# make the cwd importable before trying (idempotent).
cwd = os.getcwd()
if cwd not in sys.path:
sys.path.insert(0, cwd)
parts = ref.split(":")
attr_path = None
@@ -341,6 +357,12 @@ def load_env(ref: str, node: VirtualNode | None = None, *,
and leaf is None):
raise ScenarioError(f"--env {ref!r}: reference must include a module path")
if reload and mod_name in sys.modules:
# hot reload (FR-10.2.17): drop the cached module so the
# import below reads the file from disk again
sys.modules.pop(mod_name, None)
mod = None
if mod is None:
try:
mod = importlib.import_module(mod_name)