sanic-api 0.2.9__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. sanic_api/__init__.py +2 -20
  2. sanic_api/api/__init__.py +17 -2
  3. sanic_api/api/model.py +0 -46
  4. sanic_api/api/request.py +157 -0
  5. sanic_api/api/response.py +34 -0
  6. sanic_api/app.py +306 -0
  7. sanic_api/config/__init__.py +1 -1
  8. sanic_api/config/setting.py +69 -14
  9. sanic_api/logger/__init__.py +0 -1
  10. sanic_api/logger/config.py +74 -52
  11. sanic_api/logger/extension.py +130 -0
  12. sanic_api/openapi/__init__.py +0 -7
  13. sanic_api/utils/__init__.py +0 -0
  14. sanic_api/{enum.py → utils/enum.py} +1 -31
  15. sanic_api-0.3.0.dist-info/METADATA +160 -0
  16. sanic_api-0.3.0.dist-info/RECORD +19 -0
  17. {sanic_api-0.2.9.dist-info → sanic_api-0.3.0.dist-info}/WHEEL +1 -1
  18. example/__main__.py +0 -19
  19. example/api/__init__.py +0 -1
  20. example/api/t1/__init__.py +0 -2
  21. example/api/t1/t1_1.py +0 -22
  22. example/api/t1/t1_2.py +0 -9
  23. example/api/t2/__init__.py +0 -1
  24. example/api/t2/t2.py +0 -9
  25. example/api/t2/t3/__init__.py +0 -1
  26. example/api/t2/t3/t3.py +0 -9
  27. example/api/user.py +0 -89
  28. example/api/validator.py +0 -97
  29. example/app.py +0 -62
  30. example/settings.py +0 -10
  31. sanic_api/api/api.py +0 -177
  32. sanic_api/api/exception.py +0 -46
  33. sanic_api/api/extend.py +0 -25
  34. sanic_api/api/handle_exception.py +0 -61
  35. sanic_api/api/validators.py +0 -76
  36. sanic_api/config/sanic.py +0 -19
  37. sanic_api/config/sanic_api.py +0 -11
  38. sanic_api/logger/extend.py +0 -71
  39. sanic_api/logger/sanic_http.py +0 -68
  40. sanic_api/openapi/openapi.py +0 -102
  41. sanic_api/utils.py +0 -112
  42. sanic_api-0.2.9.dist-info/METADATA +0 -96
  43. sanic_api-0.2.9.dist-info/RECORD +0 -38
  44. /example/__init__.py → /sanic_api/openapi/extension.py +0 -0
  45. {sanic_api-0.2.9.dist-info → sanic_api-0.3.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,77 +1,99 @@
1
- import logging
1
+ import inspect
2
2
  import logging.config
3
- import sys
4
- from types import FrameType
5
- from typing import Optional, Union
3
+ from logging import LogRecord, StreamHandler
6
4
 
7
- import sanic.exceptions
8
5
  from loguru import logger
9
- from pygments import highlight
10
- from pygments.formatters.terminal import TerminalFormatter
11
- from pygments.lexers.sql import PostgresLexer
12
- from sanic import Request
6
+ from sanic import BadRequest, Request, Sanic
13
7
 
14
8
 
15
- class InterceptHandler(logging.StreamHandler):
9
+ class InterceptHandler(StreamHandler):
16
10
  def emit(self, record: logging.LogRecord):
17
- # Get corresponding Loguru level if it exists
11
+ # Get corresponding Loguru level if it exists.
12
+ level: str | int
18
13
  try:
19
- level: Union[int, str] = logger.level(record.levelname).name
14
+ level = logger.level(record.levelname).name
20
15
  except ValueError:
21
16
  level = record.levelno
22
17
 
23
18
  # Find caller from where originated the logged message.
24
- # noinspection PyProtectedMember,PyUnresolvedReferences
25
- frame: Optional[FrameType] = sys._getframe(6)
26
- depth: int = 6
27
- while frame and frame.f_code.co_filename == logging.__file__:
19
+ frame, depth = inspect.currentframe(), 0
20
+ while frame and (depth == 0 or frame.f_code.co_filename == logging.__file__):
28
21
  frame = frame.f_back
29
22
  depth += 1
30
23
 
31
- fmt = "%(message)s"
32
- sanic_access_fmt = "[%(host)s]: %(request)s %(message)s %(status)d %(byte)s %(time)s%(req_args)s"
33
- fmt = fmt if record.name != "sanic.access" else sanic_access_fmt
34
- formatter = logging.Formatter(fmt=fmt)
35
- msg = formatter.format(record)
36
- msg = self.highlight_sql(record, msg)
37
- req_id = self.get_req_id()
24
+ # 获取标准日志的扩展信息
25
+ default_record = LogRecord("", 0, "", 0, "", None, None, "")
26
+ etxra_info = {key: value for key, value in record.__dict__.items() if key not in default_record.__dict__}
38
27
 
39
- if "Dispatching signal" not in msg:
40
- etxra_data = {"type": record.name, "req_id": req_id}
41
- logger.bind(**etxra_data).opt(depth=depth, exception=record.exc_info).log(level, msg)
28
+ # 加入情求ID。用来识别情求链
29
+ req_id = self._get_req_id()
30
+ if req_id:
31
+ etxra_info.update({"req_id": req_id})
42
32
 
33
+ # 给访问日志里面加入情求体数据
34
+ if record.name == "sanic.access":
35
+ req_body = self._get_req_body()
36
+ etxra_info.update({"req_body": req_body})
37
+
38
+ # 如果没有扩展信息,则为空字符串
39
+ etxra_info = etxra_info if etxra_info else ""
40
+
41
+ # 如果有扩展信息,则在信息后面加个空格
42
+ src_msg = record.getMessage()
43
+ msg = f"{src_msg} " if etxra_info and src_msg else src_msg
44
+
45
+ # 把标准日志的名字加入到loguru日志的type字段
46
+ etxra_data = {"type": record.name, "etxra_info": etxra_info}
47
+ logger.bind(**etxra_data).opt(depth=depth, exception=record.exc_info).log(level, msg)
48
+
49
+ # noinspection PyUnresolvedReferences,PyBroadException
43
50
  @staticmethod
44
- def get_req_id():
51
+ def _get_req() -> Request | None:
45
52
  """
46
- 获取请求ID
53
+ 获取请求
47
54
  """
55
+
48
56
  try:
49
- req = Request.get_current()
50
- req_id = f" [{req.id}] "
51
- except sanic.exceptions.ServerError:
52
- req_id = " "
53
- return req_id
57
+ app = Sanic.get_app()
58
+ req = app.request_class.get_current()
59
+ except Exception:
60
+ req = None
61
+ return req
62
+
63
+ def _get_req_id(self) -> str:
64
+ """
65
+ 获取请求ID
66
+ """
54
67
 
55
- def highlight_sql(self, record: logging.LogRecord, message: str):
68
+ req = self._get_req()
69
+ return str(req.id) if req else ""
70
+
71
+ def _get_req_body(self) -> dict | None:
56
72
  """
57
- 打印日志时高亮SQl
58
- Args:
59
- record: 日志记录
60
- message: 日志消息
73
+ 获取请求体数据
61
74
 
62
75
  Returns:
63
-
76
+ 返回具有 json、query、form参数的json
64
77
  """
65
- name = record.name
66
- postgres = PostgresLexer()
67
- terminal_formatter = TerminalFormatter()
68
-
69
- if name == "tortoise.db_client":
70
- if (
71
- record.levelname == "DEBUG"
72
- and not message.startswith("Created connection pool")
73
- and not message.startswith("Closed connection pool")
74
- ):
75
- message = highlight(message, postgres, terminal_formatter).rstrip()
76
-
77
- return message
78
+ req = self._get_req()
79
+ if not req:
80
+ return None
81
+
82
+ data = {}
83
+ for attr in ["args", "form"]:
84
+ attr_data = {}
85
+ for k, v in getattr(req, attr).items():
86
+ if isinstance(v, list) and len(v) == 1:
87
+ attr_data[k] = v[0]
88
+ else:
89
+ attr_data[k] = v
90
+ if attr_data:
91
+ data[attr] = attr_data
92
+
93
+ try:
94
+ if req.json:
95
+ data["json"] = req.json
96
+ except BadRequest:
97
+ ...
98
+
99
+ return data
@@ -0,0 +1,130 @@
1
+ import logging
2
+ import logging.config
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from loguru import logger
7
+
8
+ # noinspection PyProtectedMember
9
+ from loguru._defaults import env
10
+ from loki_logger_handler.formatters.loguru_formatter import LoguruFormatter
11
+ from loki_logger_handler.loki_logger_handler import LokiLoggerHandler
12
+ from sanic import Sanic
13
+ from sanic.application.constants import Mode
14
+ from sanic_ext import Extension
15
+
16
+ from sanic_api.logger.config import InterceptHandler
17
+
18
+
19
+ class LoggerExtend(Extension):
20
+ """
21
+ 处理日志的扩展
22
+ """
23
+
24
+ name = "LoguruExtend"
25
+
26
+ def __init__(
27
+ self,
28
+ app: Sanic,
29
+ *,
30
+ log_file: str | Path | None = None,
31
+ rotation: str | None = None,
32
+ retention: str | None = None,
33
+ compression: str | None = None,
34
+ loki_url: str | None = None,
35
+ loki_labels: dict[str, str] | None = None,
36
+ ):
37
+ """
38
+ Args:
39
+ app: sanic app
40
+ log_file: 日志文件的路径
41
+ rotation: 日志文件自动轮转条件:查看loguru文档:https://loguru.readthedocs.io/en/stable/api/logger.html#file
42
+ retention: 日志文件保留条件: 查看loguru文档:https://loguru.readthedocs.io/en/stable/api/logger.html#file
43
+ compression: 日志文件压缩格式: "gz", "bz2", "xz", "lzma", "tar", "tar.gz", "tar.bz2", "tar.xz", "zip"
44
+ loki_url: 推送loki的url
45
+ loki_labels:loki推送时的标签
46
+
47
+ """
48
+ self.app = app
49
+ self.log_file = log_file
50
+ self.rotation = rotation
51
+ self.retention = retention
52
+ self.compression = compression
53
+ self.loki_url = loki_url
54
+ self.loki_labels = loki_labels
55
+ self.setup()
56
+
57
+ def startup(self, bootstrap) -> None:
58
+ """
59
+ 扩展在初始化时安装,保留他是为了证明是一个扩展
60
+ 因为要拦截sanic.application.motd:display的日志,所以不能写在这里
61
+ Args:
62
+ bootstrap:
63
+
64
+ Returns:
65
+
66
+ """
67
+
68
+ def setup(self):
69
+ """
70
+ 安装扩展
71
+ Returns:
72
+
73
+ """
74
+ logger.remove()
75
+
76
+ log_format = env(
77
+ "LOGURU_FORMAT",
78
+ str,
79
+ "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
80
+ "<red>{extra[type]: <10}</red> | "
81
+ "<level>{level: <8}</level> | "
82
+ "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
83
+ "<level>{message}</level>{extra[etxra_info]}",
84
+ )
85
+
86
+ # 基本的控制台输出
87
+ log_handlers = [
88
+ {"sink": sys.stdout, "format": log_format, "colorize": True},
89
+ ]
90
+
91
+ # 日志文件输出
92
+ if self.log_file:
93
+ self.log_file = self.log_file if isinstance(self.log_file, Path) else Path(self.log_file)
94
+ self.log_file.parent.mkdir(parents=True, exist_ok=True)
95
+ log_handlers.append(
96
+ {
97
+ "sink": self.log_file,
98
+ "format": log_format,
99
+ "colorize": False,
100
+ "serialize": True,
101
+ "compression": self.compression,
102
+ "rotation": self.rotation,
103
+ "retention": self.retention,
104
+ }
105
+ )
106
+
107
+ # loki 推送
108
+ if self.loki_url:
109
+ loki_handler = LokiLoggerHandler(
110
+ url=self.loki_url,
111
+ labels=self.loki_labels or {},
112
+ labelKeys={},
113
+ timeout=10,
114
+ defaultFormatter=LoguruFormatter(),
115
+ )
116
+ log_handlers.append(
117
+ {
118
+ "sink": loki_handler,
119
+ "format": log_format,
120
+ "colorize": False,
121
+ "serialize": True,
122
+ }
123
+ )
124
+
125
+ # 配置日志
126
+ logger.configure(handlers=log_handlers)
127
+
128
+ # 接收logging的日志
129
+ log_level = logging.DEBUG if self.app.state.mode is Mode.DEBUG else logging.INFO
130
+ logging.basicConfig(handlers=[InterceptHandler()], level=log_level, force=True)
@@ -1,7 +0,0 @@
1
- from sanic import Sanic
2
-
3
- from sanic_api.openapi.openapi import auto_doc
4
-
5
-
6
- def init(sanic_app: Sanic):
7
- sanic_app.before_server_start(auto_doc)
File without changes
@@ -22,7 +22,7 @@ class EnumBase(Enum):
22
22
 
23
23
  @classmethod
24
24
  def _missing_(cls, value: object) -> Any:
25
- result = list(filter(lambda d: d.value == value, cls)) # type: ignore
25
+ result = list(filter(lambda d: d.value == value, cls))
26
26
  return result[0] if result else None
27
27
 
28
28
  @DynamicClassAttribute
@@ -56,33 +56,3 @@ class EnumBase(Enum):
56
56
  def to_desc(cls) -> str:
57
57
  data = {d.value: d.desc for d in cls}
58
58
  return json.dumps(data, ensure_ascii=False)
59
-
60
-
61
- class RespCodeEnum(EnumBase):
62
- """
63
- 响应码枚举
64
- """
65
-
66
- SUCCESS = EnumField(10000, desc="成功")
67
- FAILED = EnumField(40000, desc="失败")
68
- PARAM_FAILED = EnumField(40001, desc="参数校验失败")
69
-
70
-
71
- class ParamEnum(EnumBase):
72
- """
73
- 参数位置
74
- """
75
-
76
- JSON = EnumField("json")
77
- FORM = EnumField("form")
78
- QUERY = EnumField("query")
79
-
80
-
81
- class RunModeEnum(EnumBase):
82
- """
83
- 运行模式
84
- """
85
-
86
- DEV = EnumField("dev", desc="开发模式。相当于debug模式加自动重载")
87
- DEBUG = EnumField("debug", desc="调试模式。单workers启动。输出将更加详细,并将禁用多个运行时优化")
88
- PRODUCTION = EnumField("production", desc="生产模式。如未指定workers数量,则自动使用fast模式启动。")
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.4
2
+ Name: sanic-api
3
+ Version: 0.3.0
4
+ Summary: Sanic 框架实用API工具集,拥有自动生成文档、参数校验、配置的导入、日志功能的优化等功能,更好的助力接口的开发
5
+ Project-URL: homepage, https://github.com/x-haose/sanic-api
6
+ Project-URL: repository, https://github.com/x-haose/sanic-api
7
+ Project-URL: documentation, https://github.com/x-haose/sanic-api
8
+ Author-email: 昊色居士 <xhrtxh@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE.txt
11
+ Keywords: Sanic,Sanic扩展,异步
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: MacOS :: MacOS X
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: POSIX :: BSD
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: hs-config==0.1.3
27
+ Requires-Dist: loguru>=0.7.2
28
+ Requires-Dist: loki-logger-handler>=0.1.4
29
+ Requires-Dist: orjson>=3.8.6
30
+ Requires-Dist: requests>=2.32.0
31
+ Requires-Dist: sanic-ext>=23.12.0
32
+ Requires-Dist: sanic>=24.12.0
33
+ Requires-Dist: sentry-sdk>=2.17.0
34
+ Requires-Dist: ujson>=5.7.0
35
+ Description-Content-Type: text/markdown
36
+
37
+ [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/)
38
+ [![Python](https://img.shields.io/badge/Python-3.10+-yellow.svg?logo=python)]()
39
+ [![Sanic](https://img.shields.io/badge/framework-Sanic-Server.svg)](http://www.gnu.org/licenses/agpl-3.0)
40
+
41
+ # Sanic-API
42
+
43
+ 让您的sanic服务程序更好的支持API文档、参数校验、日志打印、响应规范等
44
+
45
+ ## 特性
46
+
47
+ - 无需任何多余改动,全自动生成openapi文档,使用更加方便 (新版方案正在积极优化开发中)
48
+
49
+ - 基于`pydantic`的参数校验器,让接口的请求及响应更符合你的预期,使用更方便
50
+
51
+ - 使用`loguru`库代替官方`logging`日志库,并对访问日志进行扩展,支持写入文件及推送loki
52
+
53
+ - 使用了基于`pydantic-settings`的项目配置方案,支持json、yml、ini、.env等多种格式
54
+
55
+ - 对sanic的启动进行了简单的封装,可快速启动项目
56
+
57
+
58
+ ## 截图
59
+
60
+ ## 路线图
61
+
62
+ - 全自动生成openapi文档
63
+
64
+ - 编写详细文档
65
+
66
+ ## 安装
67
+
68
+ 使用 pip 安装 sanic-api
69
+
70
+ ```bash
71
+ pip install sanic-api
72
+ ```
73
+
74
+ ## 使用方法/示例
75
+
76
+ ### 最小示例
77
+ ```python
78
+ from sanic_api.app import BaseApp
79
+
80
+
81
+ class App(BaseApp):
82
+ """
83
+ 最小的sanic服务示例
84
+ """
85
+
86
+
87
+ if __name__ == "__main__":
88
+ App.run()
89
+ ```
90
+
91
+ ### 带参数校验的示例
92
+ ```python
93
+ from pydantic import BaseModel, Field
94
+ from sanic import Blueprint, Sanic, json
95
+ from sanic.log import logger
96
+
97
+ from sanic_api.api import BaseRespTml, Request
98
+ from sanic_api.app import BaseApp
99
+
100
+ user_blueprint = Blueprint("user", "/user")
101
+
102
+
103
+ class UserInfoModel(BaseModel):
104
+ user_id: int = Field(title="用户ID")
105
+
106
+
107
+ class UserInfoResponse(BaseRespTml):
108
+ user_name: str = Field(title="用户名")
109
+
110
+
111
+ class UseLoginRequest(Request):
112
+ form_data: UserInfoModel
113
+
114
+
115
+ @user_blueprint.post("info")
116
+ async def user_info(request: Request, json_data: UserInfoModel):
117
+ """
118
+ 获取用户信息
119
+ """
120
+ logger.info(f"data: {json_data}")
121
+ info = UserInfoResponse(user_name="张三")
122
+ info.temp_data.code = "0000"
123
+ info.temp_data.msg = "查询成功"
124
+ return info.resp()
125
+
126
+
127
+ @user_blueprint.post("login")
128
+ async def user_login(request: UseLoginRequest):
129
+ """
130
+ 用户登录
131
+ """
132
+ logger.info(f"user_id: {request.form_data.user_id}")
133
+ return json(request.form_data.model_dump())
134
+
135
+
136
+ class App(BaseApp):
137
+ """
138
+ 服务示例
139
+ """
140
+
141
+ async def setup_route(self, app: Sanic):
142
+ api = Blueprint.group(url_prefix="api")
143
+ api.append(user_blueprint)
144
+ app.blueprint(api)
145
+
146
+
147
+ if __name__ == "__main__":
148
+ App.run()
149
+ ```
150
+
151
+ ## 开发
152
+
153
+ 要部署这个项目,请先安装rye
154
+
155
+ ```bash
156
+ rye sync
157
+ ```
158
+
159
+ ## 文档
160
+ 正在编写中,敬请期待
@@ -0,0 +1,19 @@
1
+ sanic_api/__init__.py,sha256=QKQ2Q7WcHp48T7FBPeWyNxrbWYd6hGMHtc90Lxbsdys,75
2
+ sanic_api/app.py,sha256=_hSbX7SZQSxWDO3nP1gVOv7tlZtS6CCNOGTHZocqPYU,7948
3
+ sanic_api/api/__init__.py,sha256=tlfFmLNwI_Y5uQD4EN6h-XRr1YmoAktqEsjlo48kvX0,383
4
+ sanic_api/api/model.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ sanic_api/api/request.py,sha256=PN6_PEQRfM_-SkndTmAqNHawzPph8uN3QpkM5Mdegvs,5735
6
+ sanic_api/api/response.py,sha256=stQ6sVF_YiWM8cp4vr79w4HSD81zCHUxV8xAcx5Sk2o,1303
7
+ sanic_api/config/__init__.py,sha256=DVqXHMXANl_xUwBsLVYisr7ZPdX2ubA2_WH3GUZC-Bs,80
8
+ sanic_api/config/setting.py,sha256=_WS_vACxrac7enD4ghFC8GD6d_r13TumCWSLbpbk-5Y,2583
9
+ sanic_api/logger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ sanic_api/logger/config.py,sha256=5C-kYrE13_cgw7vNxBwBLi4F8BijHakOKs6YSzxsEMA,3031
11
+ sanic_api/logger/extension.py,sha256=xj8DjGW3jN2M7MTu4mk65H1Qs-j5VwvgO0LGahoeQRU,4108
12
+ sanic_api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ sanic_api/openapi/extension.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ sanic_api/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ sanic_api/utils/enum.py,sha256=JGFh8o8kovcR4LF3ekuWJIiZINQspfeYrvVhmFvYK-I,1240
16
+ sanic_api-0.3.0.dist-info/METADATA,sha256=Knr3_58TA6jQFgWrSzbq4HHc1Vf4bK3P5Rv5HvrFumA,4285
17
+ sanic_api-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ sanic_api-0.3.0.dist-info/licenses/LICENSE.txt,sha256=T20w-F8AfuFO9CHy2mSk_An6T9eV4X4rGA01i-gp4M4,1090
19
+ sanic_api-0.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-pep517 1.1.4
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
example/__main__.py DELETED
@@ -1,19 +0,0 @@
1
- from sanic import Sanic
2
- from sanic.worker.loader import AppLoader
3
-
4
- from example.app import app_factory
5
- from example.settings import settings
6
- from sanic_api.enum import RunModeEnum
7
-
8
- if __name__ == "__main__":
9
- loader = AppLoader(factory=app_factory)
10
- app = loader.load()
11
- app.prepare(
12
- host=settings.host,
13
- port=settings.port,
14
- debug=settings.mode == RunModeEnum.DEBUG,
15
- dev=settings.mode == RunModeEnum.DEV,
16
- workers=settings.workers,
17
- fast=settings.mode == RunModeEnum.PRODUCTION and settings.workers == 1,
18
- )
19
- Sanic.serve(app, app_loader=loader)
example/api/__init__.py DELETED
@@ -1 +0,0 @@
1
- from .user import users_blueprint
@@ -1,2 +0,0 @@
1
- from .t1_1 import t1_1_blueprint
2
- from .t1_2 import t1_2_blueprint
example/api/t1/t1_1.py DELETED
@@ -1,22 +0,0 @@
1
- from sanic import Blueprint, Request, text
2
-
3
- from sanic_api.api.exception import ServerException
4
-
5
- t1_1_blueprint = Blueprint("t1_1_blueprint", url_prefix="/t1_1")
6
- t1_1_blueprint.ctx.desc = "测试蓝图1_1"
7
-
8
-
9
- @t1_1_blueprint.route("/test", methods=["GET", "POST"])
10
- async def hello(request):
11
- return text("Hello world!")
12
-
13
-
14
- @t1_1_blueprint.route("/error", methods=["GET", "POST"])
15
- async def error(request):
16
- raise ServerException(message="Error")
17
-
18
-
19
- @t1_1_blueprint.route("/restart", methods=["GET", "POST"])
20
- async def restart(request: Request):
21
- request.app.m.restart(all_workers=True, zero_downtime=True)
22
- return text("ok")
example/api/t1/t1_2.py DELETED
@@ -1,9 +0,0 @@
1
- from sanic import Blueprint, text
2
-
3
- t1_2_blueprint = Blueprint("t1_2_blueprint", url_prefix="/t1_2")
4
- t1_2_blueprint.ctx.desc = "测试蓝图1_2"
5
-
6
-
7
- @t1_2_blueprint.get("/test")
8
- async def hello(request):
9
- return text("Hello world!")
@@ -1 +0,0 @@
1
- from .t2 import t2_blueprint
example/api/t2/t2.py DELETED
@@ -1,9 +0,0 @@
1
- from sanic import Blueprint, text
2
-
3
- t2_blueprint = Blueprint("t2_blueprint", url_prefix="/t2")
4
- t2_blueprint.ctx.desc = "测试蓝图2"
5
-
6
-
7
- @t2_blueprint.route("/test", methods=["GET", "POST"])
8
- async def hello(request):
9
- return text("Hello world!")
@@ -1 +0,0 @@
1
- from .t3 import t3_blueprint
example/api/t2/t3/t3.py DELETED
@@ -1,9 +0,0 @@
1
- from sanic import Blueprint, text
2
-
3
- t3_blueprint = Blueprint("t3_blueprint", url_prefix="/t3")
4
- t3_blueprint.ctx.desc = "测试蓝图3"
5
-
6
-
7
- @t3_blueprint.route("/test", methods=["GET", "POST"])
8
- async def hello(request):
9
- return text("Hello world!")