_utils.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. from __future__ import annotations
  2. import math
  3. from typing import Any, Dict, Tuple
  4. from ._const import LongArticlesMcpConst
  5. class LongArticlesMcpUtils(LongArticlesMcpConst):
  6. """MCP 工具层:参数解析、校验、分页计算与统一响应构造。"""
  7. # ---------- 分页计算 ----------
  8. @staticmethod
  9. def normalize_pagination(page: int | None, page_size: int | None) -> Tuple[int, int]:
  10. page = page or LongArticlesMcpConst.DEFAULT_PAGE
  11. page = max(page, 1)
  12. page_size = page_size or LongArticlesMcpConst.DEFAULT_PAGE_SIZE
  13. page_size = max(1, min(page_size, LongArticlesMcpConst.MAX_PAGE_SIZE))
  14. return page, page_size
  15. @staticmethod
  16. def calc_total_pages(total: int, page_size: int) -> int:
  17. if total <= 0:
  18. return 0
  19. return math.ceil(total / page_size)
  20. # ---------- 参数解析 ----------
  21. @classmethod
  22. def parse_pagination(cls, params: Dict[str, Any]) -> Tuple[int, int]:
  23. page_raw = params.get("page")
  24. page_size_raw = params.get("page_size")
  25. try:
  26. page = int(page_raw) if page_raw is not None else None
  27. page_size = int(page_size_raw) if page_size_raw is not None else None
  28. except (TypeError, ValueError) as exc:
  29. raise ValueError("page and page_size must be integers") from exc
  30. return cls.normalize_pagination(page, page_size)
  31. @classmethod
  32. def parse_sort(cls, params: Dict[str, Any]) -> Tuple[str | None, str | None]:
  33. sort_by = params.get("sort_by")
  34. sort_order = params.get("sort_order")
  35. if sort_by is not None:
  36. if sort_by not in cls.SORT_FIELDS:
  37. raise ValueError(f"invalid sort_by: {sort_by}")
  38. if sort_order is not None:
  39. sort_order = str(sort_order).lower()
  40. if sort_order not in cls.SORT_ORDERS:
  41. raise ValueError(f"invalid sort_order: {sort_order}")
  42. return sort_by, sort_order
  43. # ---------- 响应构造 ----------
  44. @staticmethod
  45. def build_success(data: Any) -> Dict[str, Any]:
  46. return {
  47. "code": 0,
  48. "message": "success",
  49. "data": data,
  50. }
  51. @staticmethod
  52. def build_error(code: int, message: str, errors: list[str] | None = None) -> Dict[str, Any]:
  53. body: Dict[str, Any] = {
  54. "code": code,
  55. "message": message,
  56. "data": None,
  57. }
  58. if errors is not None:
  59. body["errors"] = errors
  60. return body
  61. __all__ = ["LongArticlesMcpUtils"]