sanic-api 0.2.9__py3-none-any.whl → 0.3.0a2__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.
- sanic_api/__init__.py +3 -21
- sanic_api/api/__init__.py +17 -2
- sanic_api/api/model.py +0 -46
- sanic_api/api/request.py +138 -0
- sanic_api/api/response.py +34 -0
- sanic_api/app.py +275 -0
- sanic_api/config/__init__.py +1 -1
- sanic_api/config/setting.py +71 -30
- sanic_api/logger/__init__.py +0 -1
- sanic_api/logger/config.py +99 -77
- sanic_api/logger/extension.py +129 -0
- sanic_api/openapi/__init__.py +0 -7
- sanic_api/openapi/extension.py +41 -0
- {example → sanic_api/utils}/__init__.py +0 -0
- sanic_api/{enum.py → utils/enum.py} +58 -88
- {sanic_api-0.2.9.dist-info → sanic_api-0.3.0a2.dist-info}/METADATA +30 -10
- sanic_api-0.3.0a2.dist-info/RECORD +19 -0
- {sanic_api-0.2.9.dist-info → sanic_api-0.3.0a2.dist-info}/WHEEL +1 -1
- example/__main__.py +0 -19
- example/api/__init__.py +0 -1
- example/api/t1/__init__.py +0 -2
- example/api/t1/t1_1.py +0 -22
- example/api/t1/t1_2.py +0 -9
- example/api/t2/__init__.py +0 -1
- example/api/t2/t2.py +0 -9
- example/api/t2/t3/__init__.py +0 -1
- example/api/t2/t3/t3.py +0 -9
- example/api/user.py +0 -89
- example/api/validator.py +0 -97
- example/app.py +0 -62
- example/settings.py +0 -10
- sanic_api/api/api.py +0 -177
- sanic_api/api/exception.py +0 -46
- sanic_api/api/extend.py +0 -25
- sanic_api/api/handle_exception.py +0 -61
- sanic_api/api/validators.py +0 -76
- sanic_api/config/sanic.py +0 -19
- sanic_api/config/sanic_api.py +0 -11
- sanic_api/logger/extend.py +0 -71
- sanic_api/logger/sanic_http.py +0 -68
- sanic_api/openapi/openapi.py +0 -102
- sanic_api/utils.py +0 -112
- sanic_api-0.2.9.dist-info/RECORD +0 -38
- {sanic_api-0.2.9.dist-info → sanic_api-0.3.0a2.dist-info}/licenses/LICENSE.txt +0 -0
sanic_api/logger/config.py
CHANGED
@@ -1,77 +1,99 @@
|
|
1
|
-
import
|
2
|
-
import logging.config
|
3
|
-
import
|
4
|
-
|
5
|
-
from
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
"""
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
if
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
1
|
+
import inspect
|
2
|
+
import logging.config
|
3
|
+
from logging import LogRecord, StreamHandler
|
4
|
+
|
5
|
+
from loguru import logger
|
6
|
+
from sanic import BadRequest, Request, Sanic
|
7
|
+
|
8
|
+
|
9
|
+
class InterceptHandler(StreamHandler):
|
10
|
+
def emit(self, record: logging.LogRecord):
|
11
|
+
# Get corresponding Loguru level if it exists.
|
12
|
+
level: str | int
|
13
|
+
try:
|
14
|
+
level = logger.level(record.levelname).name
|
15
|
+
except ValueError:
|
16
|
+
level = record.levelno
|
17
|
+
|
18
|
+
# Find caller from where originated the logged message.
|
19
|
+
frame, depth = inspect.currentframe(), 0
|
20
|
+
while frame and (depth == 0 or frame.f_code.co_filename == logging.__file__):
|
21
|
+
frame = frame.f_back
|
22
|
+
depth += 1
|
23
|
+
|
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__}
|
27
|
+
|
28
|
+
# 加入情求ID。用来识别情求链
|
29
|
+
req_id = self._get_req_id()
|
30
|
+
if req_id:
|
31
|
+
etxra_info.update({"req_id": req_id})
|
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
|
50
|
+
@staticmethod
|
51
|
+
def _get_req() -> Request | None:
|
52
|
+
"""
|
53
|
+
获取请求
|
54
|
+
"""
|
55
|
+
|
56
|
+
try:
|
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
|
+
"""
|
67
|
+
|
68
|
+
req = self._get_req()
|
69
|
+
return str(req.id) if req else ""
|
70
|
+
|
71
|
+
def _get_req_body(self) -> dict | None:
|
72
|
+
"""
|
73
|
+
获取请求体数据
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
返回具有 json、query、form参数的json
|
77
|
+
"""
|
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,129 @@
|
|
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.loki_logger_handler import LoguruFormatter, LokiLoggerHandler
|
11
|
+
from sanic import Sanic
|
12
|
+
from sanic.application.constants import Mode
|
13
|
+
from sanic_ext import Extension
|
14
|
+
|
15
|
+
from sanic_api.logger.config import InterceptHandler
|
16
|
+
|
17
|
+
|
18
|
+
class LoggerExtend(Extension):
|
19
|
+
"""
|
20
|
+
处理日志的扩展
|
21
|
+
"""
|
22
|
+
|
23
|
+
name = "LoguruExtend"
|
24
|
+
|
25
|
+
def __init__(
|
26
|
+
self,
|
27
|
+
app: Sanic,
|
28
|
+
*,
|
29
|
+
log_file: str | Path | None = None,
|
30
|
+
rotation: str | None = None,
|
31
|
+
retention: str | None = None,
|
32
|
+
compression: str | None = None,
|
33
|
+
loki_url: str | None = None,
|
34
|
+
loki_labels: dict[str, str] | None = None,
|
35
|
+
):
|
36
|
+
"""
|
37
|
+
Args:
|
38
|
+
app: sanic app
|
39
|
+
log_file: 日志文件的路径
|
40
|
+
rotation: 日志文件自动轮转条件:查看loguru文档:https://loguru.readthedocs.io/en/stable/api/logger.html#file
|
41
|
+
retention: 日志文件保留条件: 查看loguru文档:https://loguru.readthedocs.io/en/stable/api/logger.html#file
|
42
|
+
compression: 日志文件压缩格式: "gz", "bz2", "xz", "lzma", "tar", "tar.gz", "tar.bz2", "tar.xz", "zip"
|
43
|
+
loki_url: 推送loki的url
|
44
|
+
loki_labels:loki推送时的标签
|
45
|
+
|
46
|
+
"""
|
47
|
+
self.app = app
|
48
|
+
self.log_file = log_file
|
49
|
+
self.rotation = rotation
|
50
|
+
self.retention = retention
|
51
|
+
self.compression = compression
|
52
|
+
self.loki_url = loki_url
|
53
|
+
self.loki_labels = loki_labels
|
54
|
+
self.setup()
|
55
|
+
|
56
|
+
def startup(self, bootstrap) -> None:
|
57
|
+
"""
|
58
|
+
扩展在初始化时安装,保留他是为了证明是一个扩展
|
59
|
+
因为要拦截sanic.application.motd:display的日志,所以不能写在这里
|
60
|
+
Args:
|
61
|
+
bootstrap:
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
|
65
|
+
"""
|
66
|
+
|
67
|
+
def setup(self):
|
68
|
+
"""
|
69
|
+
安装扩展
|
70
|
+
Returns:
|
71
|
+
|
72
|
+
"""
|
73
|
+
logger.remove()
|
74
|
+
|
75
|
+
log_format = env(
|
76
|
+
"LOGURU_FORMAT",
|
77
|
+
str,
|
78
|
+
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
79
|
+
"<red>{extra[type]: <10}</red> | "
|
80
|
+
"<level>{level: <8}</level> | "
|
81
|
+
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
|
82
|
+
"<level>{message}</level>{extra[etxra_info]}",
|
83
|
+
)
|
84
|
+
|
85
|
+
# 基本的控制台输出
|
86
|
+
log_handlers = [
|
87
|
+
{"sink": sys.stdout, "format": log_format, "colorize": True},
|
88
|
+
]
|
89
|
+
|
90
|
+
# 日志文件输出
|
91
|
+
if self.log_file:
|
92
|
+
self.log_file = self.log_file if isinstance(self.log_file, Path) else Path(self.log_file)
|
93
|
+
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
94
|
+
log_handlers.append(
|
95
|
+
{
|
96
|
+
"sink": self.log_file,
|
97
|
+
"format": log_format,
|
98
|
+
"colorize": False,
|
99
|
+
"serialize": True,
|
100
|
+
"compression": self.compression,
|
101
|
+
"rotation": self.rotation,
|
102
|
+
"retention": self.retention,
|
103
|
+
}
|
104
|
+
)
|
105
|
+
|
106
|
+
# loki 推送
|
107
|
+
if self.loki_url:
|
108
|
+
loki_handler = LokiLoggerHandler(
|
109
|
+
url=self.loki_url,
|
110
|
+
labels=self.loki_labels or {},
|
111
|
+
labelKeys={},
|
112
|
+
timeout=10,
|
113
|
+
defaultFormatter=LoguruFormatter(),
|
114
|
+
)
|
115
|
+
log_handlers.append(
|
116
|
+
{
|
117
|
+
"sink": loki_handler,
|
118
|
+
"format": log_format,
|
119
|
+
"colorize": False,
|
120
|
+
"serialize": True,
|
121
|
+
}
|
122
|
+
)
|
123
|
+
|
124
|
+
# 配置日志
|
125
|
+
logger.configure(handlers=log_handlers)
|
126
|
+
|
127
|
+
# 接收logging的日志
|
128
|
+
log_level = logging.DEBUG if self.app.state.mode is Mode.DEBUG else logging.INFO
|
129
|
+
logging.basicConfig(handlers=[InterceptHandler()], level=log_level, force=True)
|
sanic_api/openapi/__init__.py
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from sanic import Blueprint
|
4
|
+
from sanic_ext.extensions.openapi.blueprint import blueprint_factory
|
5
|
+
from sanic_ext.extensions.openapi.builders import SpecificationBuilder
|
6
|
+
from sanic_ext.extensions.openapi.extension import OpenAPIExtension as BaseExtension
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from sanic_ext import Extend
|
10
|
+
|
11
|
+
|
12
|
+
class OpenAPIExtension(BaseExtension):
|
13
|
+
name = "openapi"
|
14
|
+
bp: Blueprint
|
15
|
+
|
16
|
+
def startup(self, bootstrap: Extend) -> None:
|
17
|
+
if self.app.config.OAS:
|
18
|
+
self.bp = blueprint_factory(self.app.config)
|
19
|
+
self.app.blueprint(self.bp)
|
20
|
+
bootstrap._openapi = SpecificationBuilder()
|
21
|
+
|
22
|
+
|
23
|
+
"""
|
24
|
+
import inspect
|
25
|
+
import ast
|
26
|
+
|
27
|
+
def build_spec(app, loop):
|
28
|
+
...
|
29
|
+
|
30
|
+
source_code = inspect.getsource(blueprint_factory)
|
31
|
+
ast_tree = ast.parse(source_code)
|
32
|
+
|
33
|
+
my_source_code = inspect.getsource(build_spec)
|
34
|
+
my_func_ast = ast.parse(my_source_code)
|
35
|
+
|
36
|
+
ast_tree.body[0].body[6] = my_func_ast
|
37
|
+
modified_code = compile(ast_tree, filename="<ast>", mode="exec")
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
"""
|
File without changes
|
@@ -1,88 +1,58 @@
|
|
1
|
-
import json
|
2
|
-
from dataclasses import dataclass, field
|
3
|
-
from enum import Enum, auto
|
4
|
-
from types import DynamicClassAttribute
|
5
|
-
from typing import Any
|
6
|
-
|
7
|
-
|
8
|
-
@dataclass
|
9
|
-
class EnumField:
|
10
|
-
"""
|
11
|
-
枚举字段类
|
12
|
-
"""
|
13
|
-
|
14
|
-
value: Any = field(default=auto())
|
15
|
-
desc: str = field(default_factory=str)
|
16
|
-
|
17
|
-
|
18
|
-
class EnumBase(Enum):
|
19
|
-
"""
|
20
|
-
枚举基类
|
21
|
-
"""
|
22
|
-
|
23
|
-
@classmethod
|
24
|
-
def _missing_(cls, value: object) -> Any:
|
25
|
-
result = list(filter(lambda d: d.value == value, cls))
|
26
|
-
return result[0] if result else None
|
27
|
-
|
28
|
-
@DynamicClassAttribute
|
29
|
-
def value(self) -> Any:
|
30
|
-
"""
|
31
|
-
获取枚举的值
|
32
|
-
Returns:
|
33
|
-
|
34
|
-
"""
|
35
|
-
if isinstance(self._value_, EnumField):
|
36
|
-
return self._value_.value
|
37
|
-
return self._value_
|
38
|
-
|
39
|
-
@DynamicClassAttribute
|
40
|
-
def desc(self) -> str:
|
41
|
-
"""
|
42
|
-
获取枚举值的描述
|
43
|
-
Returns:
|
44
|
-
|
45
|
-
"""
|
46
|
-
if isinstance(self._value_, EnumField):
|
47
|
-
return self._value_.desc
|
48
|
-
else:
|
49
|
-
return ""
|
50
|
-
|
51
|
-
@classmethod
|
52
|
-
def list(cls) -> list:
|
53
|
-
return [c.value for c in cls]
|
54
|
-
|
55
|
-
@classmethod
|
56
|
-
def to_desc(cls) -> str:
|
57
|
-
data = {d.value: d.desc for d in cls}
|
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模式启动。")
|
1
|
+
import json
|
2
|
+
from dataclasses import dataclass, field
|
3
|
+
from enum import Enum, auto
|
4
|
+
from types import DynamicClassAttribute
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
|
8
|
+
@dataclass
|
9
|
+
class EnumField:
|
10
|
+
"""
|
11
|
+
枚举字段类
|
12
|
+
"""
|
13
|
+
|
14
|
+
value: Any = field(default=auto())
|
15
|
+
desc: str = field(default_factory=str)
|
16
|
+
|
17
|
+
|
18
|
+
class EnumBase(Enum):
|
19
|
+
"""
|
20
|
+
枚举基类
|
21
|
+
"""
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def _missing_(cls, value: object) -> Any:
|
25
|
+
result = list(filter(lambda d: d.value == value, cls))
|
26
|
+
return result[0] if result else None
|
27
|
+
|
28
|
+
@DynamicClassAttribute
|
29
|
+
def value(self) -> Any:
|
30
|
+
"""
|
31
|
+
获取枚举的值
|
32
|
+
Returns:
|
33
|
+
|
34
|
+
"""
|
35
|
+
if isinstance(self._value_, EnumField):
|
36
|
+
return self._value_.value
|
37
|
+
return self._value_
|
38
|
+
|
39
|
+
@DynamicClassAttribute
|
40
|
+
def desc(self) -> str:
|
41
|
+
"""
|
42
|
+
获取枚举值的描述
|
43
|
+
Returns:
|
44
|
+
|
45
|
+
"""
|
46
|
+
if isinstance(self._value_, EnumField):
|
47
|
+
return self._value_.desc
|
48
|
+
else:
|
49
|
+
return ""
|
50
|
+
|
51
|
+
@classmethod
|
52
|
+
def list(cls) -> list:
|
53
|
+
return [c.value for c in cls]
|
54
|
+
|
55
|
+
@classmethod
|
56
|
+
def to_desc(cls) -> str:
|
57
|
+
data = {d.value: d.desc for d in cls}
|
58
|
+
return json.dumps(data, ensure_ascii=False)
|
@@ -1,16 +1,37 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: sanic-api
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0a2
|
4
4
|
Summary: Sanic 框架实用API工具集,拥有自动生成文档、参数校验、配置的导入、日志功能的优化等功能,更好的助力接口的开发
|
5
|
-
|
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
|
6
8
|
Author-email: 昊色居士 <xhrtxh@gmail.com>
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
License: MIT
|
10
|
+
Keywords: Sanic,Sanic扩展,异步
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
14
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
16
|
+
Classifier: Operating System :: POSIX :: BSD
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
24
|
+
Requires-Python: >=3.10
|
25
|
+
Requires-Dist: hs-config==0.1.3a5
|
26
|
+
Requires-Dist: loguru>=0.7.2
|
27
|
+
Requires-Dist: loki-logger-handler>=0.1.4
|
10
28
|
Requires-Dist: orjson>=3.8.6
|
11
|
-
Requires-Dist:
|
12
|
-
Requires-Dist:
|
13
|
-
Requires-Dist:
|
29
|
+
Requires-Dist: pydantic-settings[toml,yaml]>=2.5.2
|
30
|
+
Requires-Dist: pydantic[dotenv]>=2.9.2
|
31
|
+
Requires-Dist: requests<2.32.dev0,>=2.31.0
|
32
|
+
Requires-Dist: sanic-ext>=23.12.0
|
33
|
+
Requires-Dist: sanic>=23.12.0
|
34
|
+
Requires-Dist: sentry-sdk>=2.17.0
|
14
35
|
Requires-Dist: ujson>=5.7.0
|
15
36
|
Description-Content-Type: text/markdown
|
16
37
|
|
@@ -93,4 +114,3 @@ if __name__ == '__main__':
|
|
93
114
|
## 文档
|
94
115
|
|
95
116
|
[文档](https://linktodocumentation)
|
96
|
-
|
@@ -0,0 +1,19 @@
|
|
1
|
+
sanic_api/__init__.py,sha256=LmrOzKXnPfRurT93l3JJIs56HV_vYnsfKoQlojV8qhA,80
|
2
|
+
sanic_api/app.py,sha256=e5L3pr8MTqmjNh5V-Y276MUb3qw67K55wmhdrE2Sxf4,7386
|
3
|
+
sanic_api/api/__init__.py,sha256=XTYNRtZj3ufh2SaswvHfbNKiUoR5nVzqGSXb766r_Mw,400
|
4
|
+
sanic_api/api/model.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
sanic_api/api/request.py,sha256=y_IE51uo-7cQECxvK7iet0pO8TX-BtiscrnD3DDdtr0,5255
|
6
|
+
sanic_api/api/response.py,sha256=5b4FLPv1Zl1Rjneqt08taHlrXBqwIKwOgZpoBtqbNNI,1337
|
7
|
+
sanic_api/config/__init__.py,sha256=8hFCE2efii1P5URx8nPgFLqB5ys_8QbBAEOLJNUj-y4,81
|
8
|
+
sanic_api/config/setting.py,sha256=-ANpVP9hak7u468zXwXpXYo0do6AFATxpL_ecsw9Cb4,2254
|
9
|
+
sanic_api/logger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
sanic_api/logger/config.py,sha256=0R605TsbF30vsAF6KbcipLkKVpFyZSiSNiTxwK9KEnw,3130
|
11
|
+
sanic_api/logger/extension.py,sha256=HZ9lSg-poSsVFwEuDXvXdbLMcsab0PWwaHlCN78tMBg,4178
|
12
|
+
sanic_api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
sanic_api/openapi/extension.py,sha256=HCrcEgrj63FXOhx6TJyJDaee6mDuVnuSMA5EtdYUVjc,1009
|
14
|
+
sanic_api/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
+
sanic_api/utils/enum.py,sha256=4E1O6W9MLGitfGam9ZTc3GZPP6yiL87v5pJ3lhfIUkg,1298
|
16
|
+
sanic_api-0.3.0a2.dist-info/METADATA,sha256=zfrifrnBGYfTGTsWN9M2Am2yggv_OKta0VF8TOJdhVo,3386
|
17
|
+
sanic_api-0.3.0a2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
18
|
+
sanic_api-0.3.0a2.dist-info/licenses/LICENSE.txt,sha256=T20w-F8AfuFO9CHy2mSk_An6T9eV4X4rGA01i-gp4M4,1090
|
19
|
+
sanic_api-0.3.0a2.dist-info/RECORD,,
|
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
|
example/api/t1/__init__.py
DELETED
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
example/api/t2/__init__.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
from .t2 import t2_blueprint
|
example/api/t2/t2.py
DELETED
example/api/t2/t3/__init__.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
from .t3 import t3_blueprint
|