config: retire ServerArgs.override in favour of derive()
`ServerArgs.override(source, **fields)` was the last way to change a resolved
`ServerArgs` in place. Every remaining call-site was one of two things, and
neither wanted an in-place write:
- **A config for someone else.** A draft worker's context length, an encode
worker's device, the compile script's watchdog, the client's port pick, a test
fixture's backends. These already deepcopied first — the write was on the copy.
- **A launcher-stage resolution.** `resolve_auto_parsers` detected the chat
template's parsers and wrote them back, to be inherited by the schedulers it
spawns.
Both are "one config becomes another", so `derive(source, **fields)` returns the
variant and leaves the receiver — and any bags projected from it — untouched. It
deliberately is not `dataclasses.replace`: resolution does not re-run, because
the values being set are decided after it, from inputs it never had. Provenance
and the resolvable-field stash work as before, on the copy.
`resolve_auto_parsers` now computes the parsers and returns the config to launch
with; the detection helpers stop taking a config to mutate. `HiMambaRadixCache`
re-applied a HiCache layout normalization `__post_init__` already performs (the
same duplicate removed from `UnifiedRadixCache` in ebb1c88d23) and just goes.
With no in-place mutation left, `ServerArgs.__setattr__` raising after
resolution *is* the guarantee, so the textual writer ratchet retires and
`test_server_args_derive.py` pins the contract instead: the receiver survives
deriving, the published instance still refuses assignment, and deriving does not
publish. `SGLANG_STRICT_CONFIG_MUTATION` was already unused — the guard has been
unconditional since the mutation sweep — and goes with it.
The detection tests drop their `SimpleNamespace` stand-in for a real
`ServerArgs`; the test kit and the MLA chunk-metadata fixture publish a derived
variant instead of writing the runner's published config.
This commit is contained in:
@@ -13,6 +13,7 @@ from sglang.srt.parser.template_detection import (
|
||||
detect_tool_call_parser,
|
||||
resolve_auto_parsers,
|
||||
)
|
||||
from sglang.srt.server_args import ServerArgs
|
||||
from sglang.test.ci.ci_register import register_cpu_ci
|
||||
|
||||
register_cpu_ci(est_time=2.0, suite="base-a-test-cpu")
|
||||
@@ -769,21 +770,15 @@ class TestResolveAutoParsers(unittest.TestCase):
|
||||
|
||||
qwen3_template = "{% set enable_thinking = enable_thinking if enable_thinking is defined else true %}"
|
||||
|
||||
class _Args(SimpleNamespace):
|
||||
# Write-through override, per the runtime-context testing idiom:
|
||||
# production adjusts parsers through override(source, ...), so the
|
||||
# stand-in needs the method (a bare SimpleNamespace would raise).
|
||||
def override(self, source, **fields):
|
||||
for key, value in fields.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def _make_server_args(
|
||||
self, reasoning_parser=None, tool_call_parser=None, chat_template=None
|
||||
):
|
||||
return self._Args(
|
||||
# The dummy model path skips resolution; the tokenizer / HF-config
|
||||
# loads that detection performs are patched per test.
|
||||
return ServerArgs(
|
||||
model_path="dummy",
|
||||
reasoning_parser=reasoning_parser,
|
||||
tool_call_parser=tool_call_parser,
|
||||
model_path="Qwen/Qwen3-0.6B",
|
||||
trust_remote_code=False,
|
||||
chat_template=chat_template,
|
||||
)
|
||||
@@ -826,7 +821,11 @@ class TestResolveAutoParsers(unittest.TestCase):
|
||||
|
||||
def test_nonexistent_model_disables_both_parsers(self):
|
||||
args = self._make_server_args(reasoning_parser="auto", tool_call_parser="auto")
|
||||
args.model_path = "nonexistent/model-does-not-exist-xyz"
|
||||
args = self._make_server_args(
|
||||
reasoning_parser="auto",
|
||||
tool_call_parser="auto",
|
||||
)
|
||||
object.__setattr__(args, "model_path", "nonexistent/model-does-not-exist-xyz")
|
||||
with _patch_hf_transformers_utils(
|
||||
Mock(side_effect=RuntimeError("tokenizer unavailable")),
|
||||
Mock(side_effect=RuntimeError("config unavailable")),
|
||||
|
||||
Reference in New Issue
Block a user