mirror of
https://github.com/langgenius/dify.git
synced 2026-06-10 18:24:09 +08:00
chore(api): Suppress unknown contract checks by default (#36969)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
0019e6a6f3
commit
c88a38b8b5
@ -7,9 +7,9 @@ or ``Model.model_validate(...).model_dump()`` return.
|
||||
|
||||
Raw dictionaries, raw lists, ``None`` responses, streaming helpers, missing
|
||||
response schemas, and returns with non-literal status codes are classified as
|
||||
unknown so reviewers can triage them without blocking unrelated work. The one
|
||||
intentional non-schema mismatch is a known body/schema on a no-body status such
|
||||
as 204, 205, or 304.
|
||||
unknown. Unknown details are hidden by default to keep routine output focused;
|
||||
pass ``--include-unknown`` when triaging them. The one intentional non-schema
|
||||
mismatch is a known body/schema on a no-body status such as 204, 205, or 304.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -589,7 +589,7 @@ def as_jsonable(check: ContractCheck) -> dict[str, Any]:
|
||||
return data
|
||||
|
||||
|
||||
def print_text_report(checks: Sequence[ContractCheck], *, include_valid: bool) -> None:
|
||||
def print_text_report(checks: Sequence[ContractCheck], *, include_unknown: bool, include_valid: bool) -> None:
|
||||
counts = Counter(check.classification for check in checks)
|
||||
sys.stdout.write(
|
||||
"Response contract lint: "
|
||||
@ -601,6 +601,8 @@ def print_text_report(checks: Sequence[ContractCheck], *, include_valid: bool) -
|
||||
|
||||
for classification in ("mismatch", "refactorable", "unknown", "valid"):
|
||||
filtered = [check for check in checks if check.classification == classification]
|
||||
if classification == "unknown" and not include_unknown:
|
||||
continue
|
||||
if classification == "valid" and not include_valid:
|
||||
continue
|
||||
if not filtered:
|
||||
@ -619,6 +621,7 @@ def parse_args() -> argparse.Namespace:
|
||||
nargs="*",
|
||||
help="Files or directories to lint. Defaults to Flask controller directories.",
|
||||
)
|
||||
parser.add_argument("--include-unknown", action="store_true", help="Print unknown route methods in output.")
|
||||
parser.add_argument("--include-valid", action="store_true", help="Print valid route methods in text output.")
|
||||
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON.")
|
||||
parser.add_argument(
|
||||
@ -650,10 +653,16 @@ def main() -> int:
|
||||
if args.json:
|
||||
grouped = defaultdict(list)
|
||||
for check in checks:
|
||||
if check.classification == "unknown" and not args.include_unknown:
|
||||
continue
|
||||
grouped[check.classification].append(as_jsonable(check))
|
||||
sys.stdout.write(f"{json.dumps(grouped, indent=2, sort_keys=True)}\n")
|
||||
else:
|
||||
print_text_report(checks, include_valid=bool(args.include_valid))
|
||||
print_text_report(
|
||||
checks,
|
||||
include_unknown=bool(args.include_unknown),
|
||||
include_valid=bool(args.include_valid),
|
||||
)
|
||||
|
||||
has_mismatch = any(check.classification == "mismatch" for check in checks)
|
||||
has_unknown = any(check.classification == "unknown" for check in checks)
|
||||
|
||||
@ -2,6 +2,8 @@ import importlib.util
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _load_lint_response_contracts_module():
|
||||
api_dir = Path(__file__).parents[3]
|
||||
@ -115,7 +117,7 @@ class StreamApi(Resource):
|
||||
assert {actual.model for actual in checks[0].actual} == {"StreamResponse"}
|
||||
|
||||
|
||||
def test_main_is_report_only_by_default_for_mismatches(tmp_path: Path, monkeypatch):
|
||||
def test_main_is_report_only_by_default_for_mismatches(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
|
||||
module = _load_lint_response_contracts_module()
|
||||
controller_path = tmp_path / "controllers" / "sample.py"
|
||||
controller_path.parent.mkdir()
|
||||
@ -137,6 +139,34 @@ class BadDeleteApi(Resource):
|
||||
assert module.main() == 1
|
||||
|
||||
|
||||
def test_main_hides_unknown_details_by_default(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys):
|
||||
module = _load_lint_response_contracts_module()
|
||||
controller_path = tmp_path / "controllers" / "sample.py"
|
||||
controller_path.parent.mkdir()
|
||||
controller_path.write_text(
|
||||
"""
|
||||
@ns.route("/items")
|
||||
class ItemApi(Resource):
|
||||
@ns.response(200, "OK", ns.models[ItemResponse.__name__])
|
||||
def get(self):
|
||||
return dump_response(ItemResponse, item), status_code
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(sys, "argv", ["lint_response_contracts.py", str(controller_path)])
|
||||
assert module.main() == 0
|
||||
default_output = capsys.readouterr().out
|
||||
assert "1 unknown" in default_output
|
||||
assert "UNKNOWN:" not in default_output
|
||||
|
||||
monkeypatch.setattr(sys, "argv", ["lint_response_contracts.py", "--include-unknown", str(controller_path)])
|
||||
assert module.main() == 0
|
||||
include_unknown_output = capsys.readouterr().out
|
||||
assert "UNKNOWN:" in include_unknown_output
|
||||
assert "non-literal or unsupported status" in include_unknown_output
|
||||
|
||||
|
||||
def test_class_level_route_and_response_docs_apply_to_methods(tmp_path: Path):
|
||||
checks = _checks_for_source(
|
||||
tmp_path,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user