feat(api): standardize REST contracts and auth
This commit is contained in:
@@ -32,24 +32,18 @@ def test_load_auth_context_supports_aliases(monkeypatch):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_PROJECT_ID", "p1")
|
||||
monkeypatch.setenv("TJWATER_USERNAME", "tester")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "net1")
|
||||
|
||||
auth = core.load_auth_context(auth_stdin=False)
|
||||
|
||||
assert auth.server == "http://server"
|
||||
assert auth.access_token == "abc"
|
||||
assert auth.project_id == "p1"
|
||||
assert auth.username == "tester"
|
||||
assert auth.network == "net1"
|
||||
|
||||
|
||||
def test_build_runtime_context_uses_default_server(monkeypatch):
|
||||
monkeypatch.delenv("TJWATER_SERVER", raising=False)
|
||||
monkeypatch.delenv("TJWATER_ACCESS_TOKEN", raising=False)
|
||||
monkeypatch.delenv("TJWATER_PROJECT_ID", raising=False)
|
||||
monkeypatch.delenv("TJWATER_USERNAME", raising=False)
|
||||
monkeypatch.delenv("TJWATER_NETWORK", raising=False)
|
||||
monkeypatch.delenv("TJWATER_EXTRA_HEADERS", raising=False)
|
||||
|
||||
runtime = core.build_runtime_context(
|
||||
@@ -68,7 +62,7 @@ def test_auth_stdin_can_be_reused_with_runtime_context_cache(monkeypatch):
|
||||
def fake_request_json(ctx, **kwargs):
|
||||
observed_runtime_ids.append(id(ctx))
|
||||
assert ctx.auth.access_token == "token-1"
|
||||
assert kwargs["params"] == {"network": "tjwater", "junction": "11"}
|
||||
assert kwargs["params"] == {"junction": "11"}
|
||||
return {"id": "11"}, 5
|
||||
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
@@ -81,7 +75,6 @@ def test_auth_stdin_can_be_reused_with_runtime_context_cache(monkeypatch):
|
||||
"server": "http://server",
|
||||
"access_token": "token-1",
|
||||
"project_id": "project-1",
|
||||
"network": "tjwater",
|
||||
}
|
||||
),
|
||||
)
|
||||
@@ -105,7 +98,6 @@ def test_network_get_junction_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-junction-properties", "--junction", "J1"])
|
||||
@@ -116,8 +108,8 @@ def test_network_get_junction_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == {"id": "J1"}
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getjunctionproperties/",
|
||||
"params": {"network": "tjwater", "junction": "J1"},
|
||||
"path": "/junctions/properties",
|
||||
"params": {"junction": "J1"},
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +124,6 @@ def test_network_get_pipe_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-pipe-properties", "--pipe", "P1"])
|
||||
@@ -143,8 +134,8 @@ def test_network_get_pipe_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == {"id": "P1"}
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getpipeproperties/",
|
||||
"params": {"network": "tjwater", "pipe": "P1"},
|
||||
"path": "/pipes/properties",
|
||||
"params": {"pipe": "P1"},
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +150,6 @@ def test_network_get_all_pipes_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-all-pipes-properties"])
|
||||
@@ -170,8 +160,8 @@ def test_network_get_all_pipes_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == [{"id": "P1"}]
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getallpipeproperties/",
|
||||
"params": {"network": "tjwater"},
|
||||
"path": "/pipes",
|
||||
"params": {},
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +176,6 @@ def test_network_get_reservoir_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-reservoir-properties", "--reservoir", "R1"])
|
||||
@@ -197,8 +186,8 @@ def test_network_get_reservoir_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == {"id": "R1"}
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getreservoirproperties/",
|
||||
"params": {"network": "tjwater", "reservoir": "R1"},
|
||||
"path": "/reservoirs/properties",
|
||||
"params": {"reservoir": "R1"},
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +202,6 @@ def test_network_get_all_reservoir_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-all-reservoirs-properties"])
|
||||
@@ -224,8 +212,8 @@ def test_network_get_all_reservoir_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == [{"id": "R1"}]
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getallreservoirproperties/",
|
||||
"params": {"network": "tjwater"},
|
||||
"path": "/reservoirs",
|
||||
"params": {},
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +228,6 @@ def test_network_get_tank_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-tank-properties", "--tank", "T1"])
|
||||
@@ -251,8 +238,8 @@ def test_network_get_tank_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == {"id": "T1"}
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/gettankproperties/",
|
||||
"params": {"network": "tjwater", "tank": "T1"},
|
||||
"path": "/tanks/properties",
|
||||
"params": {"tank": "T1"},
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +254,6 @@ def test_network_get_all_tank_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-all-tanks-properties"])
|
||||
@@ -278,8 +264,8 @@ def test_network_get_all_tank_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == [{"id": "T1"}]
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getalltankproperties/",
|
||||
"params": {"network": "tjwater"},
|
||||
"path": "/tanks",
|
||||
"params": {},
|
||||
}
|
||||
|
||||
|
||||
@@ -294,7 +280,6 @@ def test_network_get_pump_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-pump-properties", "--pump", "PU1"])
|
||||
@@ -305,8 +290,8 @@ def test_network_get_pump_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == {"id": "PU1"}
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getpumpproperties/",
|
||||
"params": {"network": "tjwater", "pump": "PU1"},
|
||||
"path": "/pumps/properties",
|
||||
"params": {"pump": "PU1"},
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +306,6 @@ def test_network_get_all_pump_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-all-pumps-properties"])
|
||||
@@ -332,8 +316,8 @@ def test_network_get_all_pump_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == [{"id": "PU1"}]
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getallpumpproperties/",
|
||||
"params": {"network": "tjwater"},
|
||||
"path": "/pumps",
|
||||
"params": {},
|
||||
}
|
||||
|
||||
|
||||
@@ -348,7 +332,6 @@ def test_network_get_valve_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-valve-properties", "--valve", "V1"])
|
||||
@@ -359,8 +342,8 @@ def test_network_get_valve_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == {"id": "V1"}
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getvalveproperties/",
|
||||
"params": {"network": "tjwater", "valve": "V1"},
|
||||
"path": "/valves/properties",
|
||||
"params": {"valve": "V1"},
|
||||
}
|
||||
|
||||
|
||||
@@ -375,7 +358,6 @@ def test_network_get_all_valve_properties_uses_network_context(monkeypatch):
|
||||
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "tjwater")
|
||||
monkeypatch.setattr(common, "request_json", fake_request_json)
|
||||
|
||||
result = runner.invoke(app, ["network", "get-all-valves-properties"])
|
||||
@@ -386,8 +368,8 @@ def test_network_get_all_valve_properties_uses_network_context(monkeypatch):
|
||||
assert payload["data"] == [{"id": "V1"}]
|
||||
assert captured == {
|
||||
"access_token": "abc",
|
||||
"path": "/getallvalveproperties/",
|
||||
"params": {"network": "tjwater"},
|
||||
"path": "/valves",
|
||||
"params": {},
|
||||
}
|
||||
|
||||
|
||||
@@ -525,7 +507,6 @@ def test_realtime_property_help_lists_supported_fields():
|
||||
def test_analysis_burst_returns_next_step_to_fetch_scheme(monkeypatch, tmp_path: Path):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
burst_path = tmp_path / "burst.json"
|
||||
burst_path.write_text('[{"id":"P1","size":3.5}]', encoding="utf-8")
|
||||
|
||||
@@ -559,7 +540,6 @@ def test_analysis_burst_returns_next_step_to_fetch_scheme(monkeypatch, tmp_path:
|
||||
def test_analysis_contaminant_sends_required_scheme_name(monkeypatch):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
captured = {}
|
||||
|
||||
def fake_request(**kwargs):
|
||||
@@ -588,7 +568,6 @@ def test_analysis_contaminant_sends_required_scheme_name(monkeypatch):
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert captured["params"] == {
|
||||
"network": "demo",
|
||||
"start_time": "2025-01-02T03:04:05+08:00",
|
||||
"source": "N1",
|
||||
"concentration": 10.0,
|
||||
@@ -600,7 +579,6 @@ def test_analysis_contaminant_sends_required_scheme_name(monkeypatch):
|
||||
def test_analysis_flushing_sends_required_scheme_name(monkeypatch, tmp_path: Path):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
captured = {}
|
||||
valve_path = tmp_path / "valve.json"
|
||||
valve_path.write_text('[{"valve":"V1","opening":0.5}]', encoding="utf-8")
|
||||
@@ -633,11 +611,10 @@ def test_analysis_flushing_sends_required_scheme_name(monkeypatch, tmp_path: Pat
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert captured["params"] == {
|
||||
"network": "demo",
|
||||
"start_time": "2025-01-02T03:04:05+08:00",
|
||||
"valves": ["V1"],
|
||||
"valves_k": [0.5],
|
||||
"drainage_node_ID": "N1",
|
||||
"drainage_node_id": "N1",
|
||||
"flush_flow": 100.0,
|
||||
"duration": 900,
|
||||
"scheme_name": "flush_case_01",
|
||||
@@ -647,7 +624,6 @@ def test_analysis_flushing_sends_required_scheme_name(monkeypatch, tmp_path: Pat
|
||||
def test_analysis_valve_close_sends_required_scheme_name(monkeypatch):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
captured = {}
|
||||
|
||||
def fake_request(**kwargs):
|
||||
@@ -676,7 +652,6 @@ def test_analysis_valve_close_sends_required_scheme_name(monkeypatch):
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert captured["params"] == {
|
||||
"network": "demo",
|
||||
"start_time": "2025-01-02T03:04:05+08:00",
|
||||
"valves": ["V1"],
|
||||
"duration": 900,
|
||||
@@ -687,7 +662,6 @@ def test_analysis_valve_close_sends_required_scheme_name(monkeypatch):
|
||||
def test_analysis_contaminant_requires_scheme(monkeypatch, capsys):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
|
||||
exit_code = main(
|
||||
[
|
||||
@@ -713,7 +687,6 @@ def test_analysis_contaminant_requires_scheme(monkeypatch, capsys):
|
||||
def test_analysis_flushing_requires_scheme(monkeypatch, tmp_path: Path, capsys):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
valve_path = tmp_path / "valve.json"
|
||||
valve_path.write_text('[{"valve":"V1","opening":0.5}]', encoding="utf-8")
|
||||
|
||||
@@ -741,7 +714,6 @@ def test_analysis_flushing_requires_scheme(monkeypatch, tmp_path: Path, capsys):
|
||||
def test_analysis_valve_close_requires_scheme(monkeypatch, capsys):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
|
||||
exit_code = main(
|
||||
[
|
||||
@@ -921,7 +893,6 @@ def test_main_bare_analysis_returns_typer_help_without_json_error(capsys):
|
||||
def test_simulation_run_translates_rfc3339(monkeypatch):
|
||||
monkeypatch.setenv("TJWATER_SERVER", "http://server")
|
||||
monkeypatch.setenv("TJWATER_ACCESS_TOKEN", "abc")
|
||||
monkeypatch.setenv("TJWATER_NETWORK", "demo")
|
||||
captured = {}
|
||||
|
||||
def fake_request(**kwargs):
|
||||
@@ -944,7 +915,6 @@ def test_simulation_run_translates_rfc3339(monkeypatch):
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert captured["json"] == {
|
||||
"name": "demo",
|
||||
"start_time": "2025-01-02T03:04:05+08:00",
|
||||
"duration": 30,
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ from .core import (
|
||||
parse_time_with_timezone,
|
||||
parse_valve_setting_file,
|
||||
request_json,
|
||||
require_network,
|
||||
require_username,
|
||||
resolve_scheme,
|
||||
)
|
||||
from .option_types import DataSource, ValveMode
|
||||
@@ -41,11 +39,9 @@ def simulation_run(
|
||||
duration: Annotated[int, typer.Option("--duration", help="持续分钟数")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
network = require_network(runtime)
|
||||
parsed = parse_time_with_timezone(start_time, option_name="--start-time")
|
||||
end_time = (parsed + timedelta(minutes=duration)).isoformat()
|
||||
body = {
|
||||
"name": network,
|
||||
"start_time": parsed.replace(microsecond=0).isoformat(),
|
||||
"duration": duration,
|
||||
}
|
||||
@@ -53,10 +49,9 @@ def simulation_run(
|
||||
ctx,
|
||||
summary="触发模拟成功",
|
||||
method="POST",
|
||||
path="/simulations/run-by-date",
|
||||
path="/simulation-runs",
|
||||
json_body=body,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
next_commands=[
|
||||
f"tjwater-cli data timeseries realtime links --start-time {parsed.isoformat()} --end-time {end_time}",
|
||||
f"tjwater-cli data timeseries realtime nodes --start-time {parsed.isoformat()} --end-time {end_time}",
|
||||
@@ -76,9 +71,8 @@ def analysis_burst(
|
||||
ids, sizes = parse_burst_file(burst_file)
|
||||
scheme_name = resolve_scheme(runtime, scheme, required=True)
|
||||
params = {
|
||||
"network": require_network(runtime),
|
||||
"modify_pattern_start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"burst_ID": ids,
|
||||
"burst_id": ids,
|
||||
"burst_size": sizes,
|
||||
"modify_total_duration": duration,
|
||||
"scheme_name": scheme_name,
|
||||
@@ -86,11 +80,10 @@ def analysis_burst(
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="爆管分析执行成功",
|
||||
method="GET",
|
||||
path="/burst-analysis",
|
||||
method="POST",
|
||||
path="/burst-analyses",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
next_commands=[
|
||||
f"tjwater-cli data scheme get --name {scheme_name}",
|
||||
"tjwater-cli data scheme list",
|
||||
@@ -110,7 +103,6 @@ def analysis_valve(
|
||||
scheme: Annotated[str | None, typer.Option("--scheme", help="close 模式的方案名称")] = None,
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
network = require_network(runtime)
|
||||
if mode == ValveMode.CLOSE:
|
||||
if not start_time or not valve:
|
||||
raise CLIError(
|
||||
@@ -120,7 +112,6 @@ def analysis_valve(
|
||||
exit_code=2,
|
||||
)
|
||||
params = {
|
||||
"network": network,
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"valves": valve,
|
||||
"duration": duration or 900,
|
||||
@@ -129,11 +120,10 @@ def analysis_valve(
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="阀门关闭分析执行成功",
|
||||
method="GET",
|
||||
path="/valve_close_analysis/",
|
||||
method="POST",
|
||||
path="/valve-isolation-analyses",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
return
|
||||
if mode == ValveMode.ISOLATION:
|
||||
@@ -144,17 +134,16 @@ def analysis_valve(
|
||||
message="isolation mode requires at least one --element",
|
||||
exit_code=2,
|
||||
)
|
||||
params = {"network": network, "accident_element": element}
|
||||
params = {"accident_element": element}
|
||||
if disabled_valve:
|
||||
params["disabled_valves"] = disabled_valve
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="阀门隔离分析执行成功",
|
||||
method="GET",
|
||||
path="/valve-isolation-analysis",
|
||||
method="POST",
|
||||
path="/valve-isolation-analyses",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
return
|
||||
raise AssertionError(f"unreachable valve mode: {mode}")
|
||||
@@ -173,11 +162,10 @@ def analysis_flushing(
|
||||
runtime = runtime_context(ctx)
|
||||
valves, openings = parse_valve_setting_file(valve_setting_file)
|
||||
params = {
|
||||
"network": require_network(runtime),
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"valves": valves,
|
||||
"valves_k": openings,
|
||||
"drainage_node_ID": drainage_node,
|
||||
"drainage_node_id": drainage_node,
|
||||
"flush_flow": flow,
|
||||
"duration": duration or 900,
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
@@ -185,11 +173,10 @@ def analysis_flushing(
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="冲洗分析执行成功",
|
||||
method="GET",
|
||||
path="/flushing-analysis",
|
||||
method="POST",
|
||||
path="/flushing-analyses",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -203,15 +190,13 @@ def analysis_age(
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="水龄分析执行成功",
|
||||
method="GET",
|
||||
path="/age_analysis/",
|
||||
method="POST",
|
||||
path="/water-age-analyses",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"duration": duration,
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -227,7 +212,6 @@ def analysis_contaminant(
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
params = {
|
||||
"network": require_network(runtime),
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"source": source_node,
|
||||
"concentration": concentration,
|
||||
@@ -239,11 +223,10 @@ def analysis_contaminant(
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="污染物模拟执行成功",
|
||||
method="GET",
|
||||
path="/contaminant-simulation",
|
||||
method="POST",
|
||||
path="/contaminant-simulations",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -256,21 +239,17 @@ def analysis_sensor_placement_kmeans(
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
body = {
|
||||
"name": require_network(runtime),
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
"sensor_number": count,
|
||||
"min_diameter": min_diameter,
|
||||
"username": require_username(runtime),
|
||||
}
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="传感器选址执行成功",
|
||||
method="POST",
|
||||
path="/pressure_sensor_placement_kmeans/",
|
||||
path="/pressure-sensor-placement-kmeans",
|
||||
json_body=body,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
require_username_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -283,7 +262,6 @@ def analysis_leakage_identify(
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
body = {
|
||||
"network": require_network(runtime),
|
||||
"scada_start": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"scada_end": parse_time_with_timezone(end_time, option_name="--end-time").isoformat(),
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
@@ -292,10 +270,9 @@ def analysis_leakage_identify(
|
||||
ctx,
|
||||
summary="漏损识别执行成功",
|
||||
method="POST",
|
||||
path="/leakage/identify/",
|
||||
path="/leakage-identifications",
|
||||
json_body=body,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -308,11 +285,9 @@ def analysis_leakage_schemes_list(ctx: typer.Context) -> None:
|
||||
method="GET",
|
||||
path="/schemes",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"scheme_type": "dma_leak_identification",
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -328,11 +303,9 @@ def analysis_leakage_schemes_get(
|
||||
method="GET",
|
||||
path=f"/schemes/{scheme_name}",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"scheme_type": "dma_leak_identification",
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -345,7 +318,6 @@ def analysis_burst_detection_detect(
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
body = {
|
||||
"network": require_network(runtime),
|
||||
"scada_start": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"scada_end": parse_time_with_timezone(end_time, option_name="--end-time").isoformat(),
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
@@ -354,10 +326,9 @@ def analysis_burst_detection_detect(
|
||||
ctx,
|
||||
summary="爆管检测执行成功",
|
||||
method="POST",
|
||||
path="/burst-detection/detect/",
|
||||
path="/burst-detections",
|
||||
json_body=body,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -370,11 +341,9 @@ def analysis_burst_detection_schemes_list(ctx: typer.Context) -> None:
|
||||
method="GET",
|
||||
path="/schemes",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"scheme_type": "burst_detection",
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -390,11 +359,9 @@ def analysis_burst_detection_schemes_get(
|
||||
method="GET",
|
||||
path=f"/schemes/{scheme_name}",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"scheme_type": "burst_detection",
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -416,7 +383,6 @@ def analysis_burst_location_locate(
|
||||
pressure_payload = parse_optional_dataset_file(pressure_file, label="pressure") or {}
|
||||
flow_payload = parse_optional_dataset_file(flow_file, label="flow") or {}
|
||||
body = {
|
||||
"network": require_network(runtime),
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
"data_source": data_source.value,
|
||||
"scada_burst_start": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
@@ -436,10 +402,9 @@ def analysis_burst_location_locate(
|
||||
ctx,
|
||||
summary="爆管定位执行成功",
|
||||
method="POST",
|
||||
path="/burst-location/locate/",
|
||||
path="/burst-locations",
|
||||
json_body=body,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -452,11 +417,9 @@ def analysis_burst_location_schemes_list(ctx: typer.Context) -> None:
|
||||
method="GET",
|
||||
path="/schemes",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"scheme_type": "burst_location",
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -472,11 +435,9 @@ def analysis_burst_location_schemes_get(
|
||||
method="GET",
|
||||
path=f"/schemes/{scheme_name}",
|
||||
params={
|
||||
"network": require_network(runtime),
|
||||
"scheme_type": "burst_location",
|
||||
},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -490,10 +451,9 @@ def analysis_risk_pipe_now(
|
||||
ctx,
|
||||
summary="读取当前管道风险成功",
|
||||
method="GET",
|
||||
path="/getpiperiskprobabilitynow/",
|
||||
params={"network": require_network(runtime), "pipe_id": pipe},
|
||||
path="/pipes/risk-probability-now",
|
||||
params={"pipe_id": pipe},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -507,32 +467,26 @@ def analysis_risk_pipe_history(
|
||||
ctx,
|
||||
summary="读取历史管道风险成功",
|
||||
method="GET",
|
||||
path="/getpiperiskprobability/",
|
||||
params={"network": require_network(runtime), "pipe_id": pipe},
|
||||
path="/pipes/risk-probability",
|
||||
params={"pipe_id": pipe},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@analysis_risk_app.command("network")
|
||||
def analysis_risk_network(ctx: typer.Context) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
network = require_network(runtime)
|
||||
probabilities, duration_prob = request_json(
|
||||
runtime,
|
||||
method="GET",
|
||||
path="/getnetworkpiperiskprobabilitynow/",
|
||||
params={"network": network},
|
||||
path="/network-pipe-risk-probability-nows",
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
geometries, duration_geo = request_json(
|
||||
runtime,
|
||||
method="GET",
|
||||
path="/getpiperiskprobabilitygeometries/",
|
||||
params={"network": network},
|
||||
path="/pipes/risk-probability-geometries",
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
emit_success(
|
||||
summary="读取全网风险成功",
|
||||
|
||||
@@ -13,7 +13,7 @@ from .apps import (
|
||||
data_timeseries_scheme_app,
|
||||
)
|
||||
from .common import emit_api, runtime_context
|
||||
from .core import CLIError, parse_time_with_timezone, require_network, resolve_scheme
|
||||
from .core import CLIError, parse_time_with_timezone, resolve_scheme
|
||||
from .option_types import (
|
||||
CompositeKind,
|
||||
ElementType,
|
||||
@@ -73,7 +73,7 @@ def data_realtime_links(
|
||||
ctx,
|
||||
summary="读取实时管道数据成功",
|
||||
method="GET",
|
||||
path="/realtime/links",
|
||||
path="/timeseries/realtime/links",
|
||||
params={
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"end_time": parse_time_with_timezone(end_time, option_name="--end-time").isoformat(),
|
||||
@@ -93,7 +93,7 @@ def data_realtime_nodes(
|
||||
ctx,
|
||||
summary="读取实时节点数据成功",
|
||||
method="GET",
|
||||
path="/realtime/nodes",
|
||||
path="/timeseries/realtime/nodes",
|
||||
params={
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
"end_time": parse_time_with_timezone(end_time, option_name="--end-time").isoformat(),
|
||||
@@ -114,7 +114,7 @@ def data_realtime_simulation_by_id_time(
|
||||
ctx,
|
||||
summary="读取实时模拟数据成功",
|
||||
method="GET",
|
||||
path="/realtime/query/by-id-time",
|
||||
path="/timeseries/realtime/simulation-results",
|
||||
params={
|
||||
"id": id,
|
||||
"type": type.value,
|
||||
@@ -137,7 +137,7 @@ def data_realtime_simulation_by_time_property(
|
||||
ctx,
|
||||
summary="读取实时属性聚合数据成功",
|
||||
method="GET",
|
||||
path="/realtime/query/by-time-property",
|
||||
path="/timeseries/realtime/records",
|
||||
params={
|
||||
"type": type.value,
|
||||
"query_time": parse_time_with_timezone(time, option_name="--time").isoformat(),
|
||||
@@ -161,7 +161,7 @@ def data_scheme_links(
|
||||
ctx,
|
||||
summary="读取方案管道数据成功",
|
||||
method="GET",
|
||||
path="/scheme/links",
|
||||
path="/timeseries/schemes/links",
|
||||
params={
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
"scheme_type": _scheme_type_option(scheme_type),
|
||||
@@ -189,7 +189,7 @@ def data_scheme_node_field(
|
||||
ctx,
|
||||
summary="读取方案节点字段成功",
|
||||
method="GET",
|
||||
path=f"/scheme/nodes/{node}/field",
|
||||
path=f"/timeseries/schemes/nodes/{node}/field",
|
||||
params={
|
||||
"field": field,
|
||||
"scheme_name": resolve_scheme(runtime, scheme, required=True),
|
||||
@@ -233,7 +233,7 @@ def data_scheme_simulation(
|
||||
ctx,
|
||||
summary="读取方案单点模拟数据成功",
|
||||
method="GET",
|
||||
path="/scheme/query/by-id-time",
|
||||
path="/timeseries/schemes/simulation-results",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_project=True,
|
||||
@@ -253,7 +253,7 @@ def data_scheme_simulation(
|
||||
ctx,
|
||||
summary="读取方案属性聚合数据成功",
|
||||
method="GET",
|
||||
path="/scheme/query/by-scheme-time-property",
|
||||
path="/timeseries/schemes/records",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_project=True,
|
||||
@@ -270,7 +270,7 @@ def data_scada_query(
|
||||
end_time: Annotated[str, typer.Option("--end-time", help="结束时间")],
|
||||
field: Annotated[str | None, typer.Option("--field", help="字段名,仅支持 monitored_value|cleaned_value")] = None,
|
||||
) -> None:
|
||||
path = "/scada/by-ids-field-time-range" if field else "/scada/by-ids-time-range"
|
||||
path = "/timeseries/scada-readings/fields" if field else "/timeseries/scada-readings"
|
||||
params = {
|
||||
"device_ids": ",".join(device_id),
|
||||
"start_time": parse_time_with_timezone(start_time, option_name="--start-time").isoformat(),
|
||||
@@ -334,7 +334,7 @@ def data_timeseries_composite(
|
||||
ctx,
|
||||
summary="读取复合 SCADA-模拟数据成功",
|
||||
method="GET",
|
||||
path="/composite/scada-simulation",
|
||||
path="/timeseries/views/scada-simulations",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_project=True,
|
||||
@@ -357,7 +357,7 @@ def data_timeseries_composite(
|
||||
ctx,
|
||||
summary="读取复合元素模拟数据成功",
|
||||
method="GET",
|
||||
path="/composite/element-simulation",
|
||||
path="/timeseries/views/element-simulations",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_project=True,
|
||||
@@ -377,7 +377,7 @@ def data_timeseries_composite(
|
||||
ctx,
|
||||
summary="读取元素关联 SCADA 数据成功",
|
||||
method="GET",
|
||||
path="/composite/element-scada",
|
||||
path="/timeseries/views/element-scada-readings",
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_project=True,
|
||||
@@ -398,21 +398,19 @@ def data_composite_pipeline_health(
|
||||
ctx,
|
||||
summary="读取管道健康预测成功",
|
||||
method="GET",
|
||||
path="/composite/pipeline-health-prediction",
|
||||
path="/pipeline-health-predictions",
|
||||
params={
|
||||
"network_name": require_network(runtime_context(ctx)),
|
||||
"query_time": parse_time_with_timezone(end_time, option_name="--end-time").isoformat(),
|
||||
},
|
||||
require_auth=True,
|
||||
require_project=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
def _scada_mapping(kind: str, action: str) -> tuple[str, dict[str, str]]:
|
||||
mapping = {
|
||||
("info", "get"): ("/getscadainfo/", {"id_param": "id"}),
|
||||
("info", "list"): ("/getallscadainfo/", {}),
|
||||
("info", "get"): ("/scada-info/detail", {"id_param": "id"}),
|
||||
("info", "list"): ("/scada-info", {}),
|
||||
}
|
||||
result = mapping.get((kind, action))
|
||||
if result is None:
|
||||
@@ -433,7 +431,7 @@ def data_scada_get(
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
path, meta = _scada_mapping(kind.value, "get")
|
||||
params = {"network": require_network(runtime), meta["id_param"]: id}
|
||||
params = {meta["id_param"]: id}
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取 SCADA 数据成功",
|
||||
@@ -441,7 +439,6 @@ def data_scada_get(
|
||||
path=path,
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -457,9 +454,7 @@ def data_scada_list(
|
||||
summary="读取 SCADA 列表成功",
|
||||
method="GET",
|
||||
path=path,
|
||||
params={"network": require_network(runtime)},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -470,10 +465,8 @@ def data_scheme_schema(ctx: typer.Context) -> None:
|
||||
ctx,
|
||||
summary="读取方案 schema 成功",
|
||||
method="GET",
|
||||
path="/getschemeschema/",
|
||||
params={"network": require_network(runtime)},
|
||||
path="/network-schemas/scheme",
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -487,10 +480,9 @@ def data_scheme_get(
|
||||
ctx,
|
||||
summary="读取方案成功",
|
||||
method="GET",
|
||||
path="/getscheme/",
|
||||
params={"network": require_network(runtime), "schema_name": name},
|
||||
path="/schemes/detail",
|
||||
params={"schema_name": name},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -502,7 +494,5 @@ def data_scheme_list(ctx: typer.Context) -> None:
|
||||
summary="读取方案列表成功",
|
||||
method="GET",
|
||||
path="/schemes",
|
||||
params={"network": require_network(runtime)},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
@@ -5,8 +5,8 @@ from typing import Annotated
|
||||
import typer
|
||||
|
||||
from .apps import component_option_app, network_app
|
||||
from .common import emit_api, runtime_context
|
||||
from .core import CLIError, require_network
|
||||
from .common import emit_api
|
||||
from .core import CLIError
|
||||
from .option_types import ComponentOptionKind
|
||||
|
||||
|
||||
@@ -15,15 +15,13 @@ def network_get_junction_properties(
|
||||
ctx: typer.Context,
|
||||
junction: Annotated[str, typer.Option("--junction", help="节点 ID")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取节点属性成功",
|
||||
method="GET",
|
||||
path="/getjunctionproperties/",
|
||||
params={"network": require_network(runtime), "junction": junction},
|
||||
path="/junctions/properties",
|
||||
params={"junction": junction},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -32,29 +30,25 @@ def network_get_pipe_properties(
|
||||
ctx: typer.Context,
|
||||
pipe: Annotated[str, typer.Option("--pipe", help="管道 ID")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取管道属性成功",
|
||||
method="GET",
|
||||
path="/getpipeproperties/",
|
||||
params={"network": require_network(runtime), "pipe": pipe},
|
||||
path="/pipes/properties",
|
||||
params={"pipe": pipe},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@network_app.command("get-all-pipes-properties")
|
||||
def network_get_all_pipes_properties(ctx: typer.Context) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取全部管道属性成功",
|
||||
method="GET",
|
||||
path="/getallpipeproperties/",
|
||||
params={"network": require_network(runtime)},
|
||||
path="/pipes",
|
||||
params={},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -63,29 +57,25 @@ def network_get_reservoir_properties(
|
||||
ctx: typer.Context,
|
||||
reservoir: Annotated[str, typer.Option("--reservoir", help="水库 ID")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取水库属性成功",
|
||||
method="GET",
|
||||
path="/getreservoirproperties/",
|
||||
params={"network": require_network(runtime), "reservoir": reservoir},
|
||||
path="/reservoirs/properties",
|
||||
params={"reservoir": reservoir},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@network_app.command("get-all-reservoirs-properties")
|
||||
def network_get_all_reservoir_properties(ctx: typer.Context) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取全部水库属性成功",
|
||||
method="GET",
|
||||
path="/getallreservoirproperties/",
|
||||
params={"network": require_network(runtime)},
|
||||
path="/reservoirs",
|
||||
params={},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -94,29 +84,25 @@ def network_get_tank_properties(
|
||||
ctx: typer.Context,
|
||||
tank: Annotated[str, typer.Option("--tank", help="水箱 ID")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取水箱属性成功",
|
||||
method="GET",
|
||||
path="/gettankproperties/",
|
||||
params={"network": require_network(runtime), "tank": tank},
|
||||
path="/tanks/properties",
|
||||
params={"tank": tank},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@network_app.command("get-all-tanks-properties")
|
||||
def network_get_all_tank_properties(ctx: typer.Context) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取全部水箱属性成功",
|
||||
method="GET",
|
||||
path="/getalltankproperties/",
|
||||
params={"network": require_network(runtime)},
|
||||
path="/tanks",
|
||||
params={},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -125,29 +111,25 @@ def network_get_pump_properties(
|
||||
ctx: typer.Context,
|
||||
pump: Annotated[str, typer.Option("--pump", help="水泵 ID")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取水泵属性成功",
|
||||
method="GET",
|
||||
path="/getpumpproperties/",
|
||||
params={"network": require_network(runtime), "pump": pump},
|
||||
path="/pumps/properties",
|
||||
params={"pump": pump},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@network_app.command("get-all-pumps-properties")
|
||||
def network_get_all_pump_properties(ctx: typer.Context) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取全部水泵属性成功",
|
||||
method="GET",
|
||||
path="/getallpumpproperties/",
|
||||
params={"network": require_network(runtime)},
|
||||
path="/pumps",
|
||||
params={},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -156,29 +138,25 @@ def network_get_valve_properties(
|
||||
ctx: typer.Context,
|
||||
valve: Annotated[str, typer.Option("--valve", help="阀门 ID")],
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取阀门属性成功",
|
||||
method="GET",
|
||||
path="/getvalveproperties/",
|
||||
params={"network": require_network(runtime), "valve": valve},
|
||||
path="/valves/properties",
|
||||
params={"valve": valve},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@network_app.command("get-all-valves-properties")
|
||||
def network_get_all_valve_properties(ctx: typer.Context) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
emit_api(
|
||||
ctx,
|
||||
summary="读取全部阀门属性成功",
|
||||
method="GET",
|
||||
path="/getallvalveproperties/",
|
||||
params={"network": require_network(runtime)},
|
||||
path="/valves",
|
||||
params={},
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -188,9 +166,8 @@ def component_option_schema(
|
||||
kind: Annotated[ComponentOptionKind, typer.Option("--kind", help="选项类型,仅支持 time|energy|pump-energy|network")],
|
||||
pump: Annotated[str | None, typer.Option("--pump", help="pump-energy 时需要的泵 ID")] = None,
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
path = _component_option_path(kind.value, schema=True)
|
||||
params = {"network": require_network(runtime)}
|
||||
params: dict[str, str] = {}
|
||||
if kind == ComponentOptionKind.PUMP_ENERGY and pump:
|
||||
params["pump"] = pump
|
||||
emit_api(
|
||||
@@ -200,7 +177,6 @@ def component_option_schema(
|
||||
path=path,
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -210,9 +186,8 @@ def component_option_get(
|
||||
kind: Annotated[ComponentOptionKind, typer.Option("--kind", help="选项类型,仅支持 time|energy|pump-energy|network")],
|
||||
pump: Annotated[str | None, typer.Option("--pump", help="pump-energy 时需要的泵 ID")] = None,
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
path = _component_option_path(kind.value, schema=False)
|
||||
params = {"network": require_network(runtime)}
|
||||
params: dict[str, str] = {}
|
||||
if kind == ComponentOptionKind.PUMP_ENERGY:
|
||||
if not pump:
|
||||
raise CLIError(
|
||||
@@ -229,20 +204,19 @@ def component_option_get(
|
||||
path=path,
|
||||
params=params,
|
||||
require_auth=True,
|
||||
require_network_ctx=True,
|
||||
)
|
||||
|
||||
|
||||
def _component_option_path(kind: str, *, schema: bool) -> str:
|
||||
routes = {
|
||||
("time", True): "/gettimeschema",
|
||||
("time", False): "/gettimeproperties/",
|
||||
("energy", True): "/getenergyschema/",
|
||||
("energy", False): "/getenergyproperties/",
|
||||
("pump-energy", True): "/getpumpenergyschema/",
|
||||
("pump-energy", False): "/getpumpenergyproperties//",
|
||||
("network", True): "/getoptionschema/",
|
||||
("network", False): "/getoptionproperties/",
|
||||
("time", True): "/network-schemas/time",
|
||||
("time", False): "/network-options/time",
|
||||
("energy", True): "/network-schemas/energy",
|
||||
("energy", False): "/network-options/energy",
|
||||
("pump-energy", True): "/network-schemas/pump-energy",
|
||||
("pump-energy", False): "/network-options/pump-energy",
|
||||
("network", True): "/network-schemas/option",
|
||||
("network", False): "/network-options",
|
||||
}
|
||||
path = routes.get((kind, schema))
|
||||
if path is None:
|
||||
|
||||
@@ -38,8 +38,6 @@ def emit_api(
|
||||
json_body: Any = None,
|
||||
require_auth: bool = True,
|
||||
require_project: bool = False,
|
||||
require_network_ctx: bool = False,
|
||||
require_username_ctx: bool = False,
|
||||
next_commands: list[str] | None = None,
|
||||
) -> None:
|
||||
runtime = runtime_context(ctx)
|
||||
@@ -51,8 +49,6 @@ def emit_api(
|
||||
json_body=json_body,
|
||||
require_auth=require_auth,
|
||||
require_project=require_project,
|
||||
require_network_ctx=require_network_ctx,
|
||||
require_username_ctx=require_username_ctx,
|
||||
)
|
||||
emit_success(
|
||||
summary=summary,
|
||||
|
||||
+23
-59
@@ -17,8 +17,6 @@ SCHEMA_VERSION = "tjwater-cli/v1"
|
||||
CLI_NAME = "tjwater-cli"
|
||||
DEFAULT_TIMEOUT = 180
|
||||
DEFAULT_SERVER = "http://192.168.1.114:8000"
|
||||
|
||||
|
||||
class CLIError(Exception):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -46,8 +44,6 @@ class AuthContext:
|
||||
server: str | None = None
|
||||
access_token: str | None = None
|
||||
project_id: str | None = None
|
||||
username: str | None = None
|
||||
network: str | None = None
|
||||
headers: dict[str, str] = field(default_factory=dict)
|
||||
|
||||
|
||||
@@ -97,8 +93,6 @@ def load_auth_context(auth_stdin: bool = False) -> AuthContext:
|
||||
"server": os.getenv("TJWATER_SERVER"),
|
||||
"access_token": os.getenv("TJWATER_ACCESS_TOKEN"),
|
||||
"project_id": os.getenv("TJWATER_PROJECT_ID"),
|
||||
"username": os.getenv("TJWATER_USERNAME"),
|
||||
"network": os.getenv("TJWATER_NETWORK"),
|
||||
"headers": json.loads(extra_headers) if extra_headers else {},
|
||||
}
|
||||
|
||||
@@ -115,8 +109,6 @@ def load_auth_context(auth_stdin: bool = False) -> AuthContext:
|
||||
server=_pick(raw, "server", "base_url"),
|
||||
access_token=_pick(raw, "access_token", "token", "accessToken"),
|
||||
project_id=_pick(raw, "project_id", "projectId", "x_project_id"),
|
||||
username=_pick(raw, "username", "preferred_username"),
|
||||
network=_pick(raw, "network", "project_code", "projectCode", "project"),
|
||||
headers={str(key): str(value) for key, value in headers.items()},
|
||||
)
|
||||
|
||||
@@ -175,30 +167,6 @@ def require_project_id(ctx: RuntimeContext) -> str:
|
||||
)
|
||||
|
||||
|
||||
def require_network(ctx: RuntimeContext) -> str:
|
||||
if ctx.auth.network:
|
||||
return ctx.auth.network
|
||||
raise CLIError(
|
||||
"认证失败",
|
||||
code="NETWORK_CONTEXT_REQUIRED",
|
||||
message="missing network in auth context for legacy network-based endpoints",
|
||||
exit_code=3,
|
||||
next_commands=["add network to auth context"],
|
||||
)
|
||||
|
||||
|
||||
def require_username(ctx: RuntimeContext) -> str:
|
||||
if ctx.auth.username:
|
||||
return ctx.auth.username
|
||||
raise CLIError(
|
||||
"认证失败",
|
||||
code="USERNAME_CONTEXT_REQUIRED",
|
||||
message="missing username in auth context",
|
||||
exit_code=3,
|
||||
next_commands=["add username to auth context"],
|
||||
)
|
||||
|
||||
|
||||
def resolve_scheme(ctx: RuntimeContext, explicit_scheme: str | None, *, required: bool = False) -> str | None:
|
||||
scheme = explicit_scheme or ctx.scheme
|
||||
if required and not scheme:
|
||||
@@ -254,14 +222,14 @@ def parse_burst_file(path: Path) -> tuple[list[str], list[float]]:
|
||||
raw = read_json_input(path, label="burst")
|
||||
if isinstance(raw, dict) and "bursts" in raw:
|
||||
raw = raw["bursts"]
|
||||
if isinstance(raw, dict) and "burst_ID" in raw and "burst_size" in raw:
|
||||
ids = [str(item) for item in raw["burst_ID"]]
|
||||
if isinstance(raw, dict) and "burst_id" in raw and "burst_size" in raw:
|
||||
ids = [str(item) for item in raw["burst_id"]]
|
||||
sizes = [float(item) for item in raw["burst_size"]]
|
||||
if len(ids) != len(sizes):
|
||||
raise CLIError(
|
||||
"CLI 参数错误",
|
||||
code="BURST_FILE_INVALID",
|
||||
message="burst file burst_ID and burst_size must have the same length",
|
||||
message="burst file burst_id and burst_size must have the same length",
|
||||
exit_code=2,
|
||||
)
|
||||
return ids, sizes
|
||||
@@ -282,7 +250,7 @@ def parse_burst_file(path: Path) -> tuple[list[str], list[float]]:
|
||||
raise CLIError(
|
||||
"CLI 参数错误",
|
||||
code="BURST_FILE_INVALID",
|
||||
message="burst file must be a JSON array or object with burst_ID/burst_size",
|
||||
message="burst file must be a JSON array or object with burst_id/burst_size",
|
||||
exit_code=2,
|
||||
)
|
||||
|
||||
@@ -404,12 +372,13 @@ def _parse_response_body(response: requests.Response) -> Any:
|
||||
return {}
|
||||
|
||||
|
||||
def _with_network_param(params: dict[str, Any] | None, network: str) -> dict[str, Any]:
|
||||
params = dict(params or {})
|
||||
if "network" in params or "network_name" in params or "name" in params:
|
||||
return params
|
||||
params["network"] = network
|
||||
return params
|
||||
def _prepare_public_request(
|
||||
method: str,
|
||||
path: str,
|
||||
params: dict[str, Any] | None,
|
||||
json_body: Any,
|
||||
) -> tuple[str, str, dict[str, Any] | None, Any]:
|
||||
return method.upper(), path.rstrip("/") or "/", params or None, json_body
|
||||
|
||||
|
||||
def request_json(
|
||||
@@ -421,18 +390,14 @@ def request_json(
|
||||
json_body: Any = None,
|
||||
require_auth: bool = True,
|
||||
require_project: bool = False,
|
||||
require_network_ctx: bool = False,
|
||||
require_username_ctx: bool = False,
|
||||
) -> tuple[Any, int]:
|
||||
require_server(ctx)
|
||||
network = None
|
||||
if require_network_ctx:
|
||||
network = require_network(ctx)
|
||||
if require_username_ctx:
|
||||
require_username(ctx)
|
||||
if network and (params is not None or json_body is None):
|
||||
params = _with_network_param(params, network)
|
||||
|
||||
method, path, params, json_body = _prepare_public_request(
|
||||
method,
|
||||
path,
|
||||
params,
|
||||
json_body,
|
||||
)
|
||||
url = f"{require_server(ctx)}/api/v1{path}"
|
||||
headers = build_headers(ctx, require_auth=require_auth, require_project=require_project)
|
||||
started = time.monotonic()
|
||||
@@ -482,15 +447,14 @@ def request_bytes(
|
||||
params: dict[str, Any] | None = None,
|
||||
require_auth: bool = True,
|
||||
require_project: bool = False,
|
||||
require_network_ctx: bool = False,
|
||||
) -> tuple[bytes, int]:
|
||||
require_server(ctx)
|
||||
network = None
|
||||
if require_network_ctx:
|
||||
network = require_network(ctx)
|
||||
if network:
|
||||
params = _with_network_param(params, network)
|
||||
|
||||
method, path, params, _ = _prepare_public_request(
|
||||
method,
|
||||
path,
|
||||
params,
|
||||
None,
|
||||
)
|
||||
url = f"{require_server(ctx)}/api/v1{path}"
|
||||
headers = build_headers(ctx, require_auth=require_auth, require_project=require_project)
|
||||
started = time.monotonic()
|
||||
|
||||
+35
-35
@@ -35,73 +35,73 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("network", "get-junction-properties"): CommandDoc(
|
||||
path=("network", "get-junction-properties"),
|
||||
summary="读取节点属性",
|
||||
description="调用 /getjunctionproperties/。",
|
||||
description="调用 GET /api/v1/junctions/{junction_id}/properties。",
|
||||
options=(CommandOptionDoc("junction", "节点 ID", required=True),),
|
||||
examples=("tjwater-cli network get-junction-properties --junction J1",),
|
||||
),
|
||||
("network", "get-pipe-properties"): CommandDoc(
|
||||
path=("network", "get-pipe-properties"),
|
||||
summary="读取管道属性",
|
||||
description="调用 /getpipeproperties/。",
|
||||
description="调用 GET /api/v1/pipes/{pipe_id}/properties。",
|
||||
options=(CommandOptionDoc("pipe", "管道 ID", required=True),),
|
||||
examples=("tjwater-cli network get-pipe-properties --pipe P1",),
|
||||
),
|
||||
("network", "get-all-pipes-properties"): CommandDoc(
|
||||
path=("network", "get-all-pipes-properties"),
|
||||
summary="读取全部管道属性",
|
||||
description="调用 /getallpipeproperties/。",
|
||||
description="调用 GET /api/v1/pipes/properties。",
|
||||
examples=("tjwater-cli network get-all-pipes-properties",),
|
||||
),
|
||||
("network", "get-reservoir-properties"): CommandDoc(
|
||||
path=("network", "get-reservoir-properties"),
|
||||
summary="读取水库属性",
|
||||
description="调用 /getreservoirproperties/。",
|
||||
description="调用 GET /api/v1/reservoirs/{reservoir_id}/properties。",
|
||||
options=(CommandOptionDoc("reservoir", "水库 ID", required=True),),
|
||||
examples=("tjwater-cli network get-reservoir-properties --reservoir R1",),
|
||||
),
|
||||
("network", "get-all-reservoirs-properties"): CommandDoc(
|
||||
path=("network", "get-all-reservoirs-properties"),
|
||||
summary="读取全部水库属性",
|
||||
description="调用 /getallreservoirproperties/。",
|
||||
description="调用 GET /api/v1/reservoirs/properties。",
|
||||
examples=("tjwater-cli network get-all-reservoirs-properties",),
|
||||
),
|
||||
("network", "get-tank-properties"): CommandDoc(
|
||||
path=("network", "get-tank-properties"),
|
||||
summary="读取水箱属性",
|
||||
description="调用 /gettankproperties/。",
|
||||
description="调用 GET /api/v1/tanks/{tank_id}/properties。",
|
||||
options=(CommandOptionDoc("tank", "水箱 ID", required=True),),
|
||||
examples=("tjwater-cli network get-tank-properties --tank T1",),
|
||||
),
|
||||
("network", "get-all-tanks-properties"): CommandDoc(
|
||||
path=("network", "get-all-tanks-properties"),
|
||||
summary="读取全部水箱属性",
|
||||
description="调用 /getalltankproperties/。",
|
||||
description="调用 GET /api/v1/tanks/properties。",
|
||||
examples=("tjwater-cli network get-all-tanks-properties",),
|
||||
),
|
||||
("network", "get-pump-properties"): CommandDoc(
|
||||
path=("network", "get-pump-properties"),
|
||||
summary="读取水泵属性",
|
||||
description="调用 /getpumpproperties/。",
|
||||
description="调用 GET /api/v1/pumps/{pump_id}/properties。",
|
||||
options=(CommandOptionDoc("pump", "水泵 ID", required=True),),
|
||||
examples=("tjwater-cli network get-pump-properties --pump PU1",),
|
||||
),
|
||||
("network", "get-all-pumps-properties"): CommandDoc(
|
||||
path=("network", "get-all-pumps-properties"),
|
||||
summary="读取全部水泵属性",
|
||||
description="调用 /getallpumpproperties/。",
|
||||
description="调用 GET /api/v1/pumps/properties。",
|
||||
examples=("tjwater-cli network get-all-pumps-properties",),
|
||||
),
|
||||
("network", "get-valve-properties"): CommandDoc(
|
||||
path=("network", "get-valve-properties"),
|
||||
summary="读取阀门属性",
|
||||
description="调用 /getvalveproperties/。",
|
||||
description="调用 GET /api/v1/valves/{valve_id}/properties。",
|
||||
options=(CommandOptionDoc("valve", "阀门 ID", required=True),),
|
||||
examples=("tjwater-cli network get-valve-properties --valve V1",),
|
||||
),
|
||||
("network", "get-all-valves-properties"): CommandDoc(
|
||||
path=("network", "get-all-valves-properties"),
|
||||
summary="读取全部阀门属性",
|
||||
description="调用 /getallvalveproperties/。",
|
||||
description="调用 GET /api/v1/valves/properties。",
|
||||
examples=("tjwater-cli network get-all-valves-properties",),
|
||||
),
|
||||
("component", "option", "schema"): CommandDoc(
|
||||
@@ -137,7 +137,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("simulation", "run"): CommandDoc(
|
||||
path=("simulation", "run"),
|
||||
summary="触发指定绝对时间的模拟运行",
|
||||
description="把显式带时区的 RFC3339 start-time 直接传给 /simulations/run-by-date;服务端按带时区时间处理并统一按 UTC 存储结果,实时数据需后续通过 data timeseries 在对应时间段查询。duration 单位为分钟。",
|
||||
description="把显式带时区的 RFC3339 start-time 直接传给 POST /api/v1/simulation-runs;服务端按带时区时间处理并统一按 UTC 存储结果,实时数据需后续通过 data timeseries 在对应时间段查询。duration 单位为分钟。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("duration", "持续分钟数", required=True),
|
||||
@@ -152,7 +152,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("analysis", "burst"): CommandDoc(
|
||||
path=("analysis", "burst"),
|
||||
summary="执行爆管分析",
|
||||
description="读取 burst-file 并转换为 burst_ID[] / burst_size[];接口本身只返回分析执行结果,方案数据需后续通过 data scheme 命令获取。duration 单位为秒。",
|
||||
description="读取 burst-file 的 burst_id[] / burst_size[] 并调用 POST /api/v1/burst-analyses;接口本身只返回分析执行结果,方案数据需后续通过 data scheme 命令获取。duration 单位为秒。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("duration", "持续秒数", required=True),
|
||||
@@ -201,7 +201,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("analysis", "age"): CommandDoc(
|
||||
path=("analysis", "age"),
|
||||
summary="执行水龄分析",
|
||||
description="调用 /age_analysis/。duration 单位为秒。",
|
||||
description="调用 POST /api/v1/water-age-analyses。duration 单位为秒。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("duration", "持续秒数", required=True),
|
||||
@@ -211,7 +211,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("analysis", "contaminant"): CommandDoc(
|
||||
path=("analysis", "contaminant"),
|
||||
summary="执行污染物模拟",
|
||||
description="调用 /contaminant-simulation。duration 单位为秒。",
|
||||
description="调用 POST /api/v1/contaminant-simulations。duration 单位为秒。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("duration", "持续秒数", required=True),
|
||||
@@ -247,19 +247,19 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("analysis", "leakage", "schemes", "list"): CommandDoc(
|
||||
path=("analysis", "leakage", "schemes", "list"),
|
||||
summary="列出漏损方案",
|
||||
description="调用 /schemes,并传入 scheme_type=dma_leak_identification。",
|
||||
description="调用 GET /api/v1/schemes,并传入 scheme_type=dma_leak_identification。",
|
||||
examples=("tjwater-cli analysis leakage schemes list",),
|
||||
),
|
||||
("analysis", "leakage", "schemes", "get"): CommandDoc(
|
||||
path=("analysis", "leakage", "schemes", "get"),
|
||||
summary="读取漏损方案详情",
|
||||
description="调用 /schemes/{scheme_name},并传入 scheme_type=dma_leak_identification。",
|
||||
description="调用 GET /api/v1/schemes/{scheme_name},并传入 scheme_type=dma_leak_identification。",
|
||||
examples=("tjwater-cli analysis leakage schemes get my_scheme",),
|
||||
),
|
||||
("analysis", "burst-detection", "detect"): CommandDoc(
|
||||
path=("analysis", "burst-detection", "detect"),
|
||||
summary="执行爆管检测",
|
||||
description="调用 /burst-detection/detect/。",
|
||||
description="调用 POST /api/v1/burst-detections。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的 SCADA 开始时间", required=True),
|
||||
CommandOptionDoc("end-time", "显式带时区的 SCADA 结束时间", required=True),
|
||||
@@ -270,19 +270,19 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("analysis", "burst-detection", "schemes", "list"): CommandDoc(
|
||||
path=("analysis", "burst-detection", "schemes", "list"),
|
||||
summary="列出爆管检测方案",
|
||||
description="调用 /schemes,并传入 scheme_type=burst_detection。",
|
||||
description="调用 GET /api/v1/schemes,并传入 scheme_type=burst_detection。",
|
||||
examples=("tjwater-cli analysis burst-detection schemes list",),
|
||||
),
|
||||
("analysis", "burst-detection", "schemes", "get"): CommandDoc(
|
||||
path=("analysis", "burst-detection", "schemes", "get"),
|
||||
summary="读取爆管检测方案详情",
|
||||
description="调用 /schemes/{scheme_name},并传入 scheme_type=burst_detection。",
|
||||
description="调用 GET /api/v1/schemes/{scheme_name},并传入 scheme_type=burst_detection。",
|
||||
examples=("tjwater-cli analysis burst-detection schemes get my_scheme",),
|
||||
),
|
||||
("analysis", "burst-location", "locate"): CommandDoc(
|
||||
path=("analysis", "burst-location", "locate"),
|
||||
summary="执行爆管定位",
|
||||
description="调用 /burst-location/locate/;需要 burst-leakage。支持 monitoring 和 simulation 两种数据源。",
|
||||
description="调用 POST /api/v1/burst-locations;需要 burst-leakage。支持 monitoring 和 simulation 两种数据源。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的 SCADA 开始时间", required=True),
|
||||
CommandOptionDoc("end-time", "显式带时区的 SCADA 结束时间", required=True),
|
||||
@@ -303,26 +303,26 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("analysis", "burst-location", "schemes", "list"): CommandDoc(
|
||||
path=("analysis", "burst-location", "schemes", "list"),
|
||||
summary="列出爆管定位方案",
|
||||
description="调用 /schemes,并传入 scheme_type=burst_location。",
|
||||
description="调用 GET /api/v1/schemes,并传入 scheme_type=burst_location。",
|
||||
examples=("tjwater-cli analysis burst-location schemes list",),
|
||||
),
|
||||
("analysis", "burst-location", "schemes", "get"): CommandDoc(
|
||||
path=("analysis", "burst-location", "schemes", "get"),
|
||||
summary="读取爆管定位方案详情",
|
||||
description="调用 /schemes/{scheme_name},并传入 scheme_type=burst_location。",
|
||||
description="调用 GET /api/v1/schemes/{scheme_name},并传入 scheme_type=burst_location。",
|
||||
examples=("tjwater-cli analysis burst-location schemes get my_scheme",),
|
||||
),
|
||||
("analysis", "risk", "pipe-now"): CommandDoc(
|
||||
path=("analysis", "risk", "pipe-now"),
|
||||
summary="读取单条管道当前风险",
|
||||
description="调用 /getpiperiskprobabilitynow/。",
|
||||
description="调用 GET /api/v1/pipes/risk-probability-now。",
|
||||
options=(CommandOptionDoc("pipe", "管道 ID", required=True),),
|
||||
examples=("tjwater-cli analysis risk pipe-now --pipe P1",),
|
||||
),
|
||||
("analysis", "risk", "pipe-history"): CommandDoc(
|
||||
path=("analysis", "risk", "pipe-history"),
|
||||
summary="读取单条管道历史风险",
|
||||
description="调用 /getpiperiskprobability/。",
|
||||
description="调用 GET /api/v1/pipes/risk-probability。",
|
||||
options=(CommandOptionDoc("pipe", "管道 ID", required=True),),
|
||||
examples=("tjwater-cli analysis risk pipe-history --pipe P1",),
|
||||
),
|
||||
@@ -335,7 +335,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "realtime", "links"): CommandDoc(
|
||||
path=("data", "timeseries", "realtime", "links"),
|
||||
summary="查询实时管道时序",
|
||||
description="调用 /realtime/links。",
|
||||
description="调用 GET /api/v1/timeseries/realtime/links。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("end-time", "显式带时区的结束时间", required=True),
|
||||
@@ -345,7 +345,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "realtime", "nodes"): CommandDoc(
|
||||
path=("data", "timeseries", "realtime", "nodes"),
|
||||
summary="查询实时节点时序",
|
||||
description="调用 /realtime/nodes。",
|
||||
description="调用 GET /api/v1/timeseries/realtime/nodes。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("end-time", "显式带时区的结束时间", required=True),
|
||||
@@ -355,7 +355,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "realtime", "simulation-by-id-time"): CommandDoc(
|
||||
path=("data", "timeseries", "realtime", "simulation-by-id-time"),
|
||||
summary="按元素和时间查询实时模拟结果",
|
||||
description="调用 /realtime/query/by-id-time。",
|
||||
description="调用 GET /api/v1/timeseries/realtime/by-element。",
|
||||
options=(
|
||||
CommandOptionDoc("id", "元素 ID", required=True),
|
||||
CommandOptionDoc("type", "元素类型:pipe 或 junction;links/nodes 是独立子命令,不是 type 取值", required=True),
|
||||
@@ -369,7 +369,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "realtime", "simulation-by-time-property"): CommandDoc(
|
||||
path=("data", "timeseries", "realtime", "simulation-by-time-property"),
|
||||
summary="按时间和属性查询实时模拟结果",
|
||||
description="调用 /realtime/query/by-time-property。pipe 属性:flow、friction、headloss、quality、reaction、setting、status、velocity;junction 属性:actual_demand、total_head、pressure、quality。",
|
||||
description="调用 GET /api/v1/timeseries/realtime/by-property。pipe 属性:flow、friction、headloss、quality、reaction、setting、status、velocity;junction 属性:actual_demand、total_head、pressure、quality。",
|
||||
options=(
|
||||
CommandOptionDoc("type", "元素类型:pipe 或 junction;links/nodes 是独立子命令,不是 type 取值", required=True),
|
||||
CommandOptionDoc("time", "显式带时区的查询时间", required=True),
|
||||
@@ -380,7 +380,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "scheme", "links"): CommandDoc(
|
||||
path=("data", "timeseries", "scheme", "links"),
|
||||
summary="查询方案管道时序",
|
||||
description="调用 /scheme/links。",
|
||||
description="调用 GET /api/v1/timeseries/schemes/links。",
|
||||
options=(
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
CommandOptionDoc("end-time", "显式带时区的结束时间", required=True),
|
||||
@@ -392,7 +392,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "scheme", "node-field"): CommandDoc(
|
||||
path=("data", "timeseries", "scheme", "node-field"),
|
||||
summary="查询方案节点字段时序",
|
||||
description="调用 /scheme/nodes/{node_id}/field。field 仅支持 actual_demand、total_head、pressure、quality。",
|
||||
description="调用 GET /api/v1/timeseries/schemes/nodes/{node_id}/{field}。field 仅支持 actual_demand、total_head、pressure、quality。",
|
||||
options=(
|
||||
CommandOptionDoc("node", "节点 ID", required=True),
|
||||
CommandOptionDoc("field", "字段名:actual_demand、total_head、pressure、quality", required=True),
|
||||
@@ -458,7 +458,7 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "timeseries", "composite", "pipeline-health"): CommandDoc(
|
||||
path=("data", "timeseries", "composite", "pipeline-health"),
|
||||
summary="查询管道健康预测",
|
||||
description="调用 /composite/pipeline-health-prediction。",
|
||||
description="调用 GET /api/v1/pipeline-health-predictions。",
|
||||
options=(
|
||||
CommandOptionDoc("pipe", "管道 ID", required=True),
|
||||
CommandOptionDoc("start-time", "显式带时区的开始时间", required=True),
|
||||
@@ -486,20 +486,20 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = {
|
||||
("data", "scheme", "schema"): CommandDoc(
|
||||
path=("data", "scheme", "schema"),
|
||||
summary="读取方案 schema",
|
||||
description="调用 /getschemeschema/。",
|
||||
description="调用 GET /api/v1/network-schemas/scheme。",
|
||||
examples=("tjwater-cli data scheme schema",),
|
||||
),
|
||||
("data", "scheme", "get"): CommandDoc(
|
||||
path=("data", "scheme", "get"),
|
||||
summary="读取单条方案",
|
||||
description="调用 /getscheme/。",
|
||||
description="调用 GET /api/v1/schemes/detail。",
|
||||
options=(CommandOptionDoc("name", "方案名称", required=True),),
|
||||
examples=("tjwater-cli data scheme get --name my_scheme",),
|
||||
),
|
||||
("data", "scheme", "list"): CommandDoc(
|
||||
path=("data", "scheme", "list"),
|
||||
summary="列出方案",
|
||||
description="调用 /schemes。",
|
||||
description="调用 GET /api/v1/schemes。",
|
||||
examples=("tjwater-cli data scheme list",),
|
||||
),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user