diff --git a/cli/tests/unit/test_tjwater_cli.py b/cli/tests/unit/test_tjwater_cli.py index 410974f..08a119f 100644 --- a/cli/tests/unit/test_tjwater_cli.py +++ b/cli/tests/unit/test_tjwater_cli.py @@ -851,6 +851,66 @@ def test_main_invalid_scada_field_is_rejected_before_request(capsys): assert "cleaned_value" in stdout +def test_data_scada_get_rejects_removed_kind_before_request(capsys): + exit_code = main(["data", "scada", "get", "--kind", "device", "--id", "D1"]) + stdout = capsys.readouterr().out + + assert exit_code == 2 + assert '"code": "INVALID_PARAMETER"' in stdout + assert "device" in stdout + assert "info" in stdout + + +def test_data_scada_list_help_only_shows_info_kind(): + result = runner.invoke(app, ["data", "scada", "list", "--help"]) + + assert result.exit_code == 0 + assert "info" in result.stdout + assert "device" not in result.stdout + assert "element" not in result.stdout + + +def test_data_scada_help_no_longer_lists_schema(): + result = runner.invoke(app, ["data", "scada", "help"]) + payload = json.loads(result.stdout) + + assert result.exit_code == 0 + commands = {command["command"] for command in payload["commands"]} + assert "data scada get" in commands + assert "data scada list" in commands + assert "data scada schema" not in commands + + +def test_data_scada_schema_command_is_removed(): + result = runner.invoke(app, ["data", "scada", "schema", "--kind", "info"]) + + assert result.exit_code == 2 + assert "No such command 'schema'" in result.output + + +def test_data_help_no_longer_lists_extension_or_misc(): + result = runner.invoke(app, ["data", "help"]) + payload = json.loads(result.stdout) + + assert result.exit_code == 0 + commands = {command["command"] for command in payload["commands"]} + assert "data timeseries" in commands + assert "data scada" in commands + assert "data scheme" in commands + assert "data extension" not in commands + assert "data misc" not in commands + + +def test_removed_data_extension_and_misc_commands_fail(): + extension_result = runner.invoke(app, ["data", "extension", "list"]) + misc_result = runner.invoke(app, ["data", "misc", "sensor-placements"]) + + assert extension_result.exit_code == 2 + assert "No such command 'extension'" in extension_result.output + assert misc_result.exit_code == 2 + assert "No such command 'misc'" in misc_result.output + + def test_main_bare_analysis_returns_typer_help_without_json_error(capsys): exit_code = main(["analysis"]) stdout = capsys.readouterr().out diff --git a/cli/tjwater_cli/apps.py b/cli/tjwater_cli/apps.py index ce3ba92..cd7614d 100644 --- a/cli/tjwater_cli/apps.py +++ b/cli/tjwater_cli/apps.py @@ -26,8 +26,6 @@ data_timeseries_scada_app = typer.Typer(no_args_is_help=True, cls=TJWaterGroup) data_timeseries_composite_app = typer.Typer(no_args_is_help=True, cls=TJWaterGroup) data_scada_app = typer.Typer(no_args_is_help=True, cls=TJWaterGroup) data_scheme_app = typer.Typer(no_args_is_help=True, cls=TJWaterGroup) -data_extension_app = typer.Typer(no_args_is_help=True, cls=TJWaterGroup) -data_misc_app = typer.Typer(no_args_is_help=True, cls=TJWaterGroup) app.add_typer(network_app, name="network") app.add_typer(component_app, name="component") @@ -50,8 +48,6 @@ data_timeseries_app.add_typer(data_timeseries_scada_app, name="scada") data_timeseries_app.add_typer(data_timeseries_composite_app, name="composite") data_app.add_typer(data_scada_app, name="scada") data_app.add_typer(data_scheme_app, name="scheme") -data_app.add_typer(data_extension_app, name="extension") -data_app.add_typer(data_misc_app, name="misc") GROUP_HELP_APPS: list[tuple[typer.Typer, tuple[str, ...]]] = [ (network_app, ("network",)), @@ -75,8 +71,6 @@ GROUP_HELP_APPS: list[tuple[typer.Typer, tuple[str, ...]]] = [ (data_timeseries_composite_app, ("data", "timeseries", "composite")), (data_scada_app, ("data", "scada")), (data_scheme_app, ("data", "scheme")), - (data_extension_app, ("data", "extension")), - (data_misc_app, ("data", "misc")), ] TOP_LEVEL_COMMANDS = {"help", "network", "component", "simulation", "analysis", "data"} diff --git a/cli/tjwater_cli/commands_data.py b/cli/tjwater_cli/commands_data.py index 2c780a6..69b8968 100644 --- a/cli/tjwater_cli/commands_data.py +++ b/cli/tjwater_cli/commands_data.py @@ -5,8 +5,6 @@ from typing import Annotated import typer from .apps import ( - data_extension_app, - data_misc_app, data_scada_app, data_scheme_app, data_timeseries_composite_app, @@ -22,7 +20,6 @@ from .option_types import ( JUNCTION_TIMESERIES_FIELDS, SCADA_TIMESERIES_FIELDS, ScadaListKind, - ScadaSchemaKind, SimulationQuery, timeseries_fields_for_element_type, ) @@ -414,15 +411,6 @@ def data_composite_pipeline_health( def _scada_mapping(kind: str, action: str) -> tuple[str, dict[str, str]]: mapping = { - ("device", "schema"): ("/getscadadeviceschema/", {}), - ("device", "get"): ("/getscadadevice/", {"id_param": "id"}), - ("device", "list"): ("/getallscadadevices/", {}), - ("device-data", "schema"): ("/getscadadevicedataschema/", {}), - ("device-data", "get"): ("/getscadadevicedata/", {"id_param": "device_id"}), - ("element", "schema"): ("/getscadaelementschema/", {}), - ("element", "get"): ("/getscadaelement/", {"id_param": "id"}), - ("element", "list"): ("/getscadaelements/", {}), - ("info", "schema"): ("/getscadainfoschema/", {}), ("info", "get"): ("/getscadainfo/", {"id_param": "id"}), ("info", "list"): ("/getallscadainfo/", {}), } @@ -437,28 +425,10 @@ def _scada_mapping(kind: str, action: str) -> tuple[str, dict[str, str]]: return result -@data_scada_app.command("schema") -def data_scada_schema( - ctx: typer.Context, - kind: Annotated[ScadaSchemaKind, typer.Option("--kind", help="SCADA 类型,仅支持 device|device-data|element|info")], -) -> None: - runtime = runtime_context(ctx) - path, _ = _scada_mapping(kind.value, "schema") - emit_api( - ctx, - summary="读取 SCADA schema 成功", - method="GET", - path=path, - params={"network": require_network(runtime)}, - require_auth=True, - require_network_ctx=True, - ) - - @data_scada_app.command("get") def data_scada_get( ctx: typer.Context, - kind: Annotated[ScadaSchemaKind, typer.Option("--kind", help="SCADA 类型,仅支持 device|device-data|element|info")], + kind: Annotated[ScadaListKind, typer.Option("--kind", help="SCADA 类型,仅支持 info")], id: Annotated[str, typer.Option("--id", help="记录 ID")], ) -> None: runtime = runtime_context(ctx) @@ -478,7 +448,7 @@ def data_scada_get( @data_scada_app.command("list") def data_scada_list( ctx: typer.Context, - kind: Annotated[ScadaListKind, typer.Option("--kind", help="SCADA 类型,仅支持 device|element|info;device-data 无 list 接口")], + kind: Annotated[ScadaListKind, typer.Option("--kind", help="SCADA 类型,仅支持 info")], ) -> None: runtime = runtime_context(ctx) path, _ = _scada_mapping(kind.value, "list") @@ -536,76 +506,3 @@ def data_scheme_list(ctx: typer.Context) -> None: require_auth=True, require_network_ctx=True, ) - - -@data_extension_app.command("keys") -def data_extension_keys(ctx: typer.Context) -> None: - runtime = runtime_context(ctx) - emit_api( - ctx, - summary="读取扩展数据键成功", - method="GET", - path="/getallextensiondatakeys/", - params={"network": require_network(runtime)}, - require_auth=True, - require_network_ctx=True, - ) - - -@data_extension_app.command("get") -def data_extension_get( - ctx: typer.Context, - key: Annotated[str, typer.Option("--key", help="扩展键")], -) -> None: - runtime = runtime_context(ctx) - emit_api( - ctx, - summary="读取扩展数据成功", - method="GET", - path="/getextensiondata/", - params={"network": require_network(runtime), "key": key}, - require_auth=True, - require_network_ctx=True, - ) - - -@data_extension_app.command("list") -def data_extension_list(ctx: typer.Context) -> None: - runtime = runtime_context(ctx) - emit_api( - ctx, - summary="读取扩展数据列表成功", - method="GET", - path="/getallextensiondata/", - params={"network": require_network(runtime)}, - require_auth=True, - require_network_ctx=True, - ) - - -@data_misc_app.command("sensor-placements") -def data_misc_sensor_placements(ctx: typer.Context) -> None: - runtime = runtime_context(ctx) - emit_api( - ctx, - summary="读取传感器位置成功", - method="GET", - path="/getallsensorplacements/", - params={"network": require_network(runtime)}, - require_auth=True, - require_network_ctx=True, - ) - - -@data_misc_app.command("burst-location-results") -def data_misc_burst_location_results(ctx: typer.Context) -> None: - runtime = runtime_context(ctx) - emit_api( - ctx, - summary="读取爆管定位结果成功", - method="GET", - path="/getallburstlocateresults/", - params={"network": require_network(runtime)}, - require_auth=True, - require_network_ctx=True, - ) diff --git a/cli/tjwater_cli/helping.py b/cli/tjwater_cli/helping.py index a88a650..5a6895c 100644 --- a/cli/tjwater_cli/helping.py +++ b/cli/tjwater_cli/helping.py @@ -100,9 +100,8 @@ def _sample_option_value(path: tuple[str, ...], option_name: str) -> str: (("component", "option", "schema"), "kind"): "time", (("component", "option", "get"), "kind"): "time", (("data", "timeseries", "composite"), "kind"): "scada-simulation", - (("data", "scada", "schema"), "kind"): "device", - (("data", "scada", "get"), "kind"): "device", - (("data", "scada", "list"), "kind"): "device", + (("data", "scada", "get"), "kind"): "info", + (("data", "scada", "list"), "kind"): "info", } if (path, option_name) in path_specific_samples: return path_specific_samples[(path, option_name)] diff --git a/cli/tjwater_cli/option_types.py b/cli/tjwater_cli/option_types.py index a642e32..8f83f67 100644 --- a/cli/tjwater_cli/option_types.py +++ b/cli/tjwater_cli/option_types.py @@ -36,16 +36,7 @@ class DataSource(str, Enum): SIMULATION = "simulation" -class ScadaSchemaKind(str, Enum): - DEVICE = "device" - DEVICE_DATA = "device-data" - ELEMENT = "element" - INFO = "info" - - class ScadaListKind(str, Enum): - DEVICE = "device" - ELEMENT = "element" INFO = "info" diff --git a/cli/tjwater_cli/registry.py b/cli/tjwater_cli/registry.py index 43c9860..201afd8 100644 --- a/cli/tjwater_cli/registry.py +++ b/cli/tjwater_cli/registry.py @@ -16,7 +16,7 @@ GROUP_SUMMARIES: dict[tuple[str, ...], str] = { ("analysis", "burst-location", "schemes"): "爆管定位方案查询命令。", ("analysis", "risk"): "风险分析相关命令。", ("analysis", "sensor-placement"): "传感器选址相关命令。", - ("data",): "时序、SCADA、方案和扩展数据查询命令。", + ("data",): "时序、SCADA 和方案数据查询命令。", ("data", "timeseries"): "时序数据查询命令。", ("data", "timeseries", "realtime"): "实时模拟时序查询命令。", ("data", "timeseries", "scheme"): "方案时序查询命令。", @@ -24,8 +24,6 @@ GROUP_SUMMARIES: dict[tuple[str, ...], str] = { ("data", "timeseries", "composite"): "复合时序查询命令。", ("data", "scada"): "SCADA 元数据查询命令。", ("data", "scheme"): "方案数据查询命令。", - ("data", "extension"): "扩展数据查询命令。", - ("data", "misc"): "其他结果数据查询命令。", } HIDDEN_PATH_PREFIXES: tuple[tuple[str, ...], ...] = ( @@ -468,41 +466,22 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = { ), examples=("tjwater-cli data timeseries composite pipeline-health --pipe P1 --start-time 2025-01-02T03:00:00+08:00 --end-time 2025-01-02T04:00:00+08:00",), ), - ("data", "scada", "schema"): CommandDoc( - path=("data", "scada", "schema"), - summary="读取 SCADA schema", - description="kind 支持 device、device-data、element、info。", - options=(CommandOptionDoc("kind", "SCADA 数据类型", required=True),), - examples=( - "tjwater-cli data scada schema --kind device", - "tjwater-cli data scada schema --kind device-data", - "tjwater-cli data scada schema --kind element", - "tjwater-cli data scada schema --kind info", - ), - ), ("data", "scada", "get"): CommandDoc( path=("data", "scada", "get"), summary="读取单条 SCADA 元数据", - description="kind 支持 device、device-data、element、info。", + description="kind 仅支持 info。", options=( CommandOptionDoc("kind", "SCADA 数据类型", required=True), CommandOptionDoc("id", "记录 ID", required=True), ), - examples=( - "tjwater-cli data scada get --kind device --id D1", - "tjwater-cli data scada get --kind element --id E1", - ), + examples=("tjwater-cli data scada get --kind info --id SCADA-001",), ), ("data", "scada", "list"): CommandDoc( path=("data", "scada", "list"), summary="列出 SCADA 元数据", - description="kind 支持 device、element、info;device-data 当前后端无 list 接口。", + description="kind 仅支持 info。", options=(CommandOptionDoc("kind", "SCADA 数据类型", required=True),), - examples=( - "tjwater-cli data scada list --kind device", - "tjwater-cli data scada list --kind element", - "tjwater-cli data scada list --kind info", - ), + examples=("tjwater-cli data scada list --kind info",), ), ("data", "scheme", "schema"): CommandDoc( path=("data", "scheme", "schema"), @@ -523,37 +502,6 @@ COMMAND_DOCS: dict[tuple[str, ...], CommandDoc] = { description="调用 /getallschemes/。", examples=("tjwater-cli data scheme list",), ), - ("data", "extension", "keys"): CommandDoc( - path=("data", "extension", "keys"), - summary="列出扩展数据键", - description="调用 /getallextensiondatakeys/。", - examples=("tjwater-cli data extension keys",), - ), - ("data", "extension", "get"): CommandDoc( - path=("data", "extension", "get"), - summary="读取扩展数据", - description="调用 /getextensiondata/。", - options=(CommandOptionDoc("key", "扩展键", required=True),), - examples=("tjwater-cli data extension get --key my_key",), - ), - ("data", "extension", "list"): CommandDoc( - path=("data", "extension", "list"), - summary="列出扩展数据", - description="调用 /getallextensiondata/。", - examples=("tjwater-cli data extension list",), - ), - ("data", "misc", "sensor-placements"): CommandDoc( - path=("data", "misc", "sensor-placements"), - summary="列出传感器布置结果", - description="调用 /getallsensorplacements/。", - examples=("tjwater-cli data misc sensor-placements",), - ), - ("data", "misc", "burst-location-results"): CommandDoc( - path=("data", "misc", "burst-location-results"), - summary="列出爆管定位结果", - description="调用 /getallburstlocateresults/。", - examples=("tjwater-cli data misc burst-location-results",), - ), } diff --git a/cli/tjwater_cli_endpoint_scope.md b/cli/tjwater_cli_endpoint_scope.md index c441c74..1413674 100644 --- a/cli/tjwater_cli_endpoint_scope.md +++ b/cli/tjwater_cli_endpoint_scope.md @@ -259,12 +259,8 @@ app/api/v1/endpoints/project_data.py | `tjwater-cli data timeseries scada query --device-id ID --start-time TIME --end-time TIME [--device-id ID ...] [--field FIELD]` | `GET /scada/by-ids-time-range`、`GET /scada/by-ids-field-time-range` | SCADA 时序;CLI 把重复 `--device-id` 转换为后端逗号分隔参数 | | `tjwater-cli data timeseries composite --kind scada-simulation\|element-simulation\|element-scada --feature FEATURE --start-time TIME --end-time TIME` | `GET /composite/*` | 复合查询,`--feature` 可重复 | | `tjwater-cli data timeseries composite pipeline-health --pipe PIPE --start-time TIME --end-time TIME` | `GET /composite/pipeline-health-prediction` | 管道健康预测 | -| `tjwater-cli data scada schema --kind device\|device-data\|element\|info` | `GET /getscada*schema/` | `SCADA` 元数据 `schema` | -| `tjwater-cli data scada get\|list --kind device\|device-data\|element\|info` | `scada.py` 下 `GET` 查询接口 | `SCADA` 元数据 | +| `tjwater-cli data scada get\|list --kind info` | `GET /getscadainfo/`、`GET /getallscadainfo/` | `SCADA info` 元数据 | | `tjwater-cli data scheme schema\|get\|list` | `schemes.py` 下 `GET` 接口 | 当前 project 方案查询 | -| `tjwater-cli data extension keys\|get\|list` | `extension.py` 下 `GET` 查询接口 | 当前 project 扩展数据查询 | -| `tjwater-cli data misc sensor-placements` | `GET /getallsensorplacements/` | 当前 project 传感器位置 | -| `tjwater-cli data misc burst-location-results` | `GET /getallburstlocateresults/` | 当前 project 爆管定位结果 | - `realtime` 是首批 simulation 结果的主读取域;CLI 可以按任务语义组合 `links`、`nodes`、`simulation-by-id-time`、`simulation-by-time-property`,但底层数据源仍以 `realtime.py` 为准。 - `realtime`、`scheme`、`composite` 等时间查询命令面向用户时仍按 **UTC+8** 输入;CLI/服务端负责转换为后端使用的 **UTC0** 条件进行检索。若返回结果直接包含时间戳,必须显式带时区,避免把存储时间和展示时间混淆。