feat(core): clone commands and actions when binding runtimes
Add clone support across Action types and Command so commands can be safely registered or runner-bound without mutating the original instances. - clone BaseAction implementations across simple, composite, IO, prompt, file, HTTP, process, and signal actions - bind cloned commands in Falyx.add_command_from_command() and CommandRunner - preserve local never_prompt settings when cloning actions - rename shared runtime state from options to options_manager for consistency - seed root and execution option namespaces consistently - apply scoped root and namespace option overrides during routing and dispatch - improve namespace completion by delegating option suggestions to FalyxParser - enrich missing-value errors and error hints
This commit is contained in:
120
tests/test_falyx/test_dispatch_contract.py
Normal file
120
tests/test_falyx/test_dispatch_contract.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import pytest
|
||||
|
||||
from falyx import Falyx
|
||||
from falyx.routing import RouteKind, RouteResult
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_seeds_namespace_defaults_into_default_namespace(
|
||||
monkeypatch,
|
||||
):
|
||||
flx = Falyx(program="falyx")
|
||||
command = flx.add_command("D", "Deploy", action=lambda: "ok", aliases=["deploy"])
|
||||
|
||||
route = RouteResult(
|
||||
kind=RouteKind.COMMAND,
|
||||
namespace=flx,
|
||||
context=flx.get_current_invocation_context(),
|
||||
command=command,
|
||||
namespace_defaults={"region": "us-east"},
|
||||
namespace_overrides={},
|
||||
)
|
||||
|
||||
seen = {}
|
||||
|
||||
async def fake_execute(*, command, args, kwargs, execution_args, **_):
|
||||
seen["region"] = flx.options_manager.get("region", None, "default")
|
||||
return "ok"
|
||||
|
||||
monkeypatch.setattr(flx._executor, "execute", fake_execute)
|
||||
|
||||
result = await flx._dispatch_route(
|
||||
route=route,
|
||||
args=(),
|
||||
kwargs={},
|
||||
execution_args={},
|
||||
)
|
||||
|
||||
assert result == "ok"
|
||||
assert seen["region"] == "us-east"
|
||||
|
||||
assert flx.options_manager.get("region", None, "default") == "us-east"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_applies_namespace_overrides_temporarily_in_default_namespace(
|
||||
monkeypatch,
|
||||
):
|
||||
flx = Falyx(program="falyx")
|
||||
command = flx.add_command("D", "Deploy", action=lambda: "ok", aliases=["deploy"])
|
||||
|
||||
flx.options_manager.set("region", "us-east", "default")
|
||||
|
||||
route = RouteResult(
|
||||
kind=RouteKind.COMMAND,
|
||||
namespace=flx,
|
||||
context=flx.get_current_invocation_context(),
|
||||
command=command,
|
||||
namespace_defaults={},
|
||||
namespace_overrides={"region": "us-west"},
|
||||
)
|
||||
|
||||
seen = {}
|
||||
|
||||
async def fake_execute(*, command, args, kwargs, execution_args, **_):
|
||||
seen["region"] = flx.options_manager.get("region", None, "default")
|
||||
return "ok"
|
||||
|
||||
monkeypatch.setattr(flx._executor, "execute", fake_execute)
|
||||
|
||||
result = await flx._dispatch_route(
|
||||
route=route,
|
||||
args=(),
|
||||
kwargs={},
|
||||
execution_args={},
|
||||
raise_on_error=False,
|
||||
wrap_errors=True,
|
||||
)
|
||||
|
||||
assert result == "ok"
|
||||
assert seen["region"] == "us-west"
|
||||
|
||||
assert flx.options_manager.get("region", None, "default") == "us-east"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_namespace_overrides_do_not_leak_after_command_execution(monkeypatch):
|
||||
flx = Falyx(program="falyx")
|
||||
command = flx.add_command("D", "Deploy", action=lambda: "ok", aliases=["deploy"])
|
||||
|
||||
flx.options_manager.set("profile", "dev", "default")
|
||||
|
||||
route = RouteResult(
|
||||
kind=RouteKind.COMMAND,
|
||||
namespace=flx,
|
||||
context=flx.get_current_invocation_context(),
|
||||
command=command,
|
||||
namespace_defaults={"region": "us-east"},
|
||||
namespace_overrides={"profile": "prod"},
|
||||
)
|
||||
|
||||
async def fake_execute(*, command, args, kwargs, execution_args, **_):
|
||||
assert flx.options_manager.get("region", None, "default") == "us-east"
|
||||
assert flx.options_manager.get("profile", None, "default") == "prod"
|
||||
return "ok"
|
||||
|
||||
monkeypatch.setattr(flx._executor, "execute", fake_execute)
|
||||
|
||||
result = await flx._dispatch_route(
|
||||
route=route,
|
||||
args=(),
|
||||
kwargs={},
|
||||
execution_args={},
|
||||
raise_on_error=False,
|
||||
wrap_errors=True,
|
||||
)
|
||||
|
||||
assert result == "ok"
|
||||
|
||||
assert flx.options_manager.get("region", None, "default") == "us-east"
|
||||
assert flx.options_manager.get("profile", None, "default") == "dev"
|
||||
Reference in New Issue
Block a user