jit-utils-backend 0.0.1__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.
- jit_utils/__init__.py +152 -0
- jit_utils/apiAuthSign.py +73 -0
- jit_utils/barcode.py +50 -0
- jit_utils/clsTool.py +71 -0
- jit_utils/config/__init__.py +11 -0
- jit_utils/config/case.py +77 -0
- jit_utils/config/config.py +90 -0
- jit_utils/config/exception.py +17 -0
- jit_utils/config/field.py +177 -0
- jit_utils/convert.py +169 -0
- jit_utils/decorator.py +58 -0
- jit_utils/exceptions.py +113 -0
- jit_utils/forwarder.py +113 -0
- jit_utils/matchTool.py +136 -0
- jit_utils/network.py +36 -0
- jit_utils/qrcode.py +60 -0
- jit_utils/signature.py +56 -0
- jit_utils/spaceSender.py +44 -0
- jit_utils/string.py +118 -0
- jit_utils/time.py +701 -0
- jit_utils/validator.py +26 -0
- jit_utils/workday_constants.py +72 -0
- jit_utils_backend-0.0.1.dist-info/METADATA +182 -0
- jit_utils_backend-0.0.1.dist-info/RECORD +32 -0
- jit_utils_backend-0.0.1.dist-info/WHEEL +5 -0
- jit_utils_backend-0.0.1.dist-info/top_level.txt +2 -0
- tests/__init__.py +4 -0
- tests/run_tests.py +102 -0
- tests/test_package_imports.py +199 -0
- tests/test_qrcode_barcode.py +182 -0
- tests/test_string_utils.py +174 -0
- tests/test_time_utils.py +185 -0
jit_utils/__init__.py
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
JIT Utils Backend - 极态后端工具包
|
4
|
+
|
5
|
+
A comprehensive utility package for backend development with JIT.
|
6
|
+
|
7
|
+
主要功能:
|
8
|
+
- 时间处理工具
|
9
|
+
- 字符串处理工具
|
10
|
+
- 二维码和条形码生成
|
11
|
+
- 数据验证
|
12
|
+
- 网络工具
|
13
|
+
- 签名工具
|
14
|
+
等等...
|
15
|
+
"""
|
16
|
+
|
17
|
+
__version__ = '0.0.1'
|
18
|
+
__author__ = 'zangtao'
|
19
|
+
|
20
|
+
# 导入主要的工具类和函数
|
21
|
+
try:
|
22
|
+
from .decorator import forward
|
23
|
+
except ImportError:
|
24
|
+
pass
|
25
|
+
|
26
|
+
# 时间工具
|
27
|
+
try:
|
28
|
+
from . import time as time_utils
|
29
|
+
# 导出一些常用的时间函数
|
30
|
+
from .time import (
|
31
|
+
now, today, get, dayShift,
|
32
|
+
monday, weekShift, monthStart, monthShift,
|
33
|
+
quarterStart, quarterShift, yearStart, yearShift,
|
34
|
+
getTimestamp, timeStampToDateTime, strToTimestamp,
|
35
|
+
formatNow, datetime2string, string2datetime
|
36
|
+
)
|
37
|
+
except ImportError:
|
38
|
+
pass
|
39
|
+
|
40
|
+
# 字符串工具
|
41
|
+
try:
|
42
|
+
from . import string as string_utils
|
43
|
+
from .string import (
|
44
|
+
randomString, randomNum, getUuidStr,
|
45
|
+
md5Bytes, md5Str, getFileMd5,
|
46
|
+
renderTemplateString
|
47
|
+
)
|
48
|
+
except ImportError:
|
49
|
+
pass
|
50
|
+
|
51
|
+
# 二维码工具
|
52
|
+
try:
|
53
|
+
from .qrcode import Qrcode
|
54
|
+
except ImportError:
|
55
|
+
Qrcode = None
|
56
|
+
|
57
|
+
# 条形码工具
|
58
|
+
try:
|
59
|
+
from .barcode import Barcode
|
60
|
+
except ImportError:
|
61
|
+
Barcode = None
|
62
|
+
|
63
|
+
# 验证工具
|
64
|
+
try:
|
65
|
+
from .validator import ParamsValidator
|
66
|
+
except ImportError:
|
67
|
+
ParamsValidator = None
|
68
|
+
|
69
|
+
# 网络工具
|
70
|
+
try:
|
71
|
+
from . import network
|
72
|
+
except ImportError:
|
73
|
+
pass
|
74
|
+
|
75
|
+
# 签名工具
|
76
|
+
try:
|
77
|
+
from . import signature
|
78
|
+
except ImportError:
|
79
|
+
pass
|
80
|
+
|
81
|
+
# 匹配工具
|
82
|
+
try:
|
83
|
+
from . import matchTool
|
84
|
+
except ImportError:
|
85
|
+
pass
|
86
|
+
|
87
|
+
# 类工具
|
88
|
+
try:
|
89
|
+
from . import clsTool
|
90
|
+
except ImportError:
|
91
|
+
pass
|
92
|
+
|
93
|
+
# 转换工具
|
94
|
+
try:
|
95
|
+
from .convert import Converter, MemoryCompiler
|
96
|
+
except ImportError:
|
97
|
+
# 如果导入失败,创建占位符避免 __all__ 报错
|
98
|
+
Converter = None
|
99
|
+
MemoryCompiler = None
|
100
|
+
|
101
|
+
# 异常处理
|
102
|
+
try:
|
103
|
+
from . import exceptions
|
104
|
+
except ImportError:
|
105
|
+
pass
|
106
|
+
|
107
|
+
# 工作日常量
|
108
|
+
try:
|
109
|
+
from . import workday_constants
|
110
|
+
except ImportError:
|
111
|
+
pass
|
112
|
+
|
113
|
+
# 配置相关
|
114
|
+
try:
|
115
|
+
from . import config
|
116
|
+
except ImportError:
|
117
|
+
pass
|
118
|
+
|
119
|
+
# 定义 __all__ 列表,控制 from jit_utils import * 的行为
|
120
|
+
__all__ = [
|
121
|
+
# 版本信息
|
122
|
+
'__version__',
|
123
|
+
'__author__',
|
124
|
+
|
125
|
+
# 装饰器
|
126
|
+
'forward',
|
127
|
+
|
128
|
+
# 时间工具
|
129
|
+
'time_utils',
|
130
|
+
'now', 'today', 'get', 'dayShift',
|
131
|
+
'monday', 'weekShift', 'monthStart', 'monthShift',
|
132
|
+
'quarterStart', 'quarterShift', 'yearStart', 'yearShift',
|
133
|
+
'getTimestamp', 'timeStampToDateTime', 'strToTimestamp',
|
134
|
+
'formatNow', 'datetime2string', 'string2datetime',
|
135
|
+
|
136
|
+
# 字符串工具
|
137
|
+
'string_utils',
|
138
|
+
'randomString', 'randomNum', 'getUuidStr',
|
139
|
+
'md5Bytes', 'md5Str', 'getFileMd5',
|
140
|
+
'renderTemplateString',
|
141
|
+
|
142
|
+
# 二维码和条形码
|
143
|
+
'Qrcode', 'Barcode',
|
144
|
+
|
145
|
+
# 验证工具
|
146
|
+
'ParamsValidator',
|
147
|
+
|
148
|
+
# 其他模块
|
149
|
+
'network', 'signature', 'matchTool',
|
150
|
+
'clsTool', 'exceptions', 'workday_constants',
|
151
|
+
'config', 'Converter', 'MemoryCompiler'
|
152
|
+
]
|
jit_utils/apiAuthSign.py
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2024/11/09
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 默认描述
|
8
|
+
"""
|
9
|
+
|
10
|
+
import base64
|
11
|
+
import hashlib
|
12
|
+
import json
|
13
|
+
import time
|
14
|
+
|
15
|
+
from jit.commons.utils.logger import log
|
16
|
+
|
17
|
+
|
18
|
+
class Sign(object):
|
19
|
+
"""
|
20
|
+
这个签名算法用于认证服务和api授权元素
|
21
|
+
"""
|
22
|
+
|
23
|
+
EXPIRE_TIME = 5 * 60 * 1000
|
24
|
+
# 签名返回的错误信息,如果是错误信息,返回空tuple,兼容原来通过bool方法校验签名是否通过的写法
|
25
|
+
TIME_OUT_ERROR = []
|
26
|
+
SIGN_CHECK_ERROR = []
|
27
|
+
SIGN_CHECK_SUCCESS = [0]
|
28
|
+
|
29
|
+
def __init__(self, secret):
|
30
|
+
self.secret = secret
|
31
|
+
|
32
|
+
def encode(self, args, timestamp, debug=False):
|
33
|
+
return self.getSign({**args, "timestamp": timestamp, "secret": self.secret}, debug=debug)
|
34
|
+
|
35
|
+
@staticmethod
|
36
|
+
def getSign(args, debug=False):
|
37
|
+
nArgs = {}
|
38
|
+
for k, v in args.items():
|
39
|
+
nArgs[k.lower()] = v
|
40
|
+
sortedKeys = sorted(nArgs.keys())
|
41
|
+
params = []
|
42
|
+
for key in sortedKeys:
|
43
|
+
value = nArgs[key]
|
44
|
+
if not isinstance(value, str):
|
45
|
+
value = json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
|
46
|
+
params.append(f"{key}={value}")
|
47
|
+
if debug:
|
48
|
+
# 隐藏secret
|
49
|
+
for idx, param in enumerate(params):
|
50
|
+
if param.split("=")[0] == "secret":
|
51
|
+
params[idx] = "secret=*********************"
|
52
|
+
|
53
|
+
paramStr = "&".join(params)
|
54
|
+
|
55
|
+
apiAuthDebug = {
|
56
|
+
"paramStr": paramStr,
|
57
|
+
}
|
58
|
+
log.debug(",".join("{k}:{v}".format(k=k, v=v) for k, v in apiAuthDebug.items()))
|
59
|
+
if hasattr(app.request, "respExtraData"):
|
60
|
+
app.request.respExtraData["apiAuthDebug"] = apiAuthDebug
|
61
|
+
return hashlib.sha1(base64.b64encode("&".join(params).encode("utf-8"))).hexdigest()
|
62
|
+
|
63
|
+
def verify(self, args):
|
64
|
+
args = args.copy()
|
65
|
+
timestamp = args.pop("timestamp")
|
66
|
+
if abs(int(time.time() * 1000) - int(timestamp)) > self.EXPIRE_TIME:
|
67
|
+
return self.TIME_OUT_ERROR
|
68
|
+
signature = args.pop("accessSign")
|
69
|
+
debug = app.request.headers.get("debug") == "1"
|
70
|
+
if signature == self.encode(args, timestamp, debug=debug):
|
71
|
+
return self.SIGN_CHECK_SUCCESS
|
72
|
+
else:
|
73
|
+
return self.SIGN_CHECK_ERROR
|
jit_utils/barcode.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2025/02/10
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 默认描述
|
8
|
+
"""
|
9
|
+
import base64
|
10
|
+
import io
|
11
|
+
|
12
|
+
import barcode
|
13
|
+
from barcode.errors import BarcodeError
|
14
|
+
from barcode.writer import ImageWriter
|
15
|
+
|
16
|
+
|
17
|
+
class Barcode(object):
|
18
|
+
"""
|
19
|
+
二维码模块,暂用于文件渲染
|
20
|
+
"""
|
21
|
+
|
22
|
+
def __init__(self, value: str, codeType="code128"):
|
23
|
+
self.value = value
|
24
|
+
self.codeType = codeType
|
25
|
+
|
26
|
+
def toByte(self):
|
27
|
+
file = self.toFile()
|
28
|
+
data = file.read()
|
29
|
+
return data
|
30
|
+
|
31
|
+
def toFile(self):
|
32
|
+
obj = barcode.get(self.codeType, self.value, writer=ImageWriter())
|
33
|
+
# 保存条形码为图像文件
|
34
|
+
imageBuffer = io.BytesIO()
|
35
|
+
obj.write(fp=imageBuffer)
|
36
|
+
imageBuffer.seek(0)
|
37
|
+
return imageBuffer
|
38
|
+
|
39
|
+
def toStr(self):
|
40
|
+
if not self.value:
|
41
|
+
return ""
|
42
|
+
try:
|
43
|
+
b64Code = base64.b64encode(self.toByte()).decode("utf-8")
|
44
|
+
except BarcodeError as e:
|
45
|
+
return "ERROR:{}".format(str(e))
|
46
|
+
|
47
|
+
return "<image:{}>".format(b64Code)
|
48
|
+
|
49
|
+
def __str__(self):
|
50
|
+
return self.toStr()
|
jit_utils/clsTool.py
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2024/09/29
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 因为框架打包不重启的时候会出现isinstance方法和issubclass函数出现问题,
|
8
|
+
所以重新实现这两个方法,通过类名来确定是否为子类,而不是通过对象ID。
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
def issubclassByName(cls, class_or_tuple: type | tuple):
|
13
|
+
if isinstance(class_or_tuple, tuple):
|
14
|
+
for cls_name in class_or_tuple:
|
15
|
+
if issubclassByName(cls, cls_name):
|
16
|
+
return True
|
17
|
+
else:
|
18
|
+
return False
|
19
|
+
|
20
|
+
if not isinstance(cls, type):
|
21
|
+
raise TypeError("issubclassByName() arg 0 must be a class")
|
22
|
+
|
23
|
+
if not isinstance(class_or_tuple, type):
|
24
|
+
raise TypeError("isinstanceByName() arg 1 must be a class or tuple with class")
|
25
|
+
|
26
|
+
__className = class_or_tuple.__name__
|
27
|
+
if cls is type:
|
28
|
+
# 特殊情况
|
29
|
+
mroNames = [item.__name__ for item in type.mro(type)]
|
30
|
+
else:
|
31
|
+
mroNames = [item.__name__ for item in cls.mro()]
|
32
|
+
if __className in mroNames:
|
33
|
+
return True
|
34
|
+
else:
|
35
|
+
return False
|
36
|
+
|
37
|
+
|
38
|
+
def isinstanceByName(obj, class_or_tuple: type | tuple):
|
39
|
+
if isinstance(class_or_tuple, tuple):
|
40
|
+
for cls_name in class_or_tuple:
|
41
|
+
if isinstanceByName(obj, cls_name):
|
42
|
+
return True
|
43
|
+
else:
|
44
|
+
return False
|
45
|
+
|
46
|
+
if not isinstance(obj, object):
|
47
|
+
raise TypeError("isinstanceByName() arg 0 must be an object")
|
48
|
+
|
49
|
+
if not isinstance(class_or_tuple, type):
|
50
|
+
raise TypeError("isinstanceByName() arg 1 must be a class or tuple with class")
|
51
|
+
|
52
|
+
cls = type(obj)
|
53
|
+
if cls.__name__ == class_or_tuple.__name__:
|
54
|
+
return True
|
55
|
+
return issubclassByName(cls, class_or_tuple)
|
56
|
+
|
57
|
+
|
58
|
+
if __name__ == "__main__":
|
59
|
+
A = type("A", (object,), {})
|
60
|
+
B = type("B", (A,), {})
|
61
|
+
|
62
|
+
a = A()
|
63
|
+
b = B()
|
64
|
+
|
65
|
+
print("class B is subclass of A: ", issubclassByName(B, A))
|
66
|
+
print("object b is instance of A: ", isinstanceByName(b, A))
|
67
|
+
print("object b is instance of B: ", isinstanceByName(b, B))
|
68
|
+
print("object b is instance of B or A: ", isinstanceByName(b, (B, A)))
|
69
|
+
print("object a is instance of object: ", isinstanceByName(a, object))
|
70
|
+
print("class A is instance of type: ", isinstanceByName(A, type))
|
71
|
+
print("object a is not instance of type: ", not isinstanceByName(a, type))
|
jit_utils/config/case.py
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2023/10/23
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 默认描述
|
8
|
+
"""
|
9
|
+
from commons.utils.config.config import TlConfig
|
10
|
+
from commons.utils.config.field import IntField, StringField
|
11
|
+
|
12
|
+
|
13
|
+
class TlConfigCase(object):
|
14
|
+
def normal(self):
|
15
|
+
"""这是一个普通使用的例子"""
|
16
|
+
|
17
|
+
class IDCardConfig(TlConfig):
|
18
|
+
name = StringField(maxLen=8, minLen=2, required=True)
|
19
|
+
age = IntField(maxNum=200, minNum=0, default=18)
|
20
|
+
|
21
|
+
config = IDCardConfig(name="张三", age=18)
|
22
|
+
print("normal case: config.name -> {}".format(config.name))
|
23
|
+
print("normal case: config.age -> {}".format(config.age))
|
24
|
+
print("normal case: config.toDict -> {}".format(config.value))
|
25
|
+
|
26
|
+
# 如果没有传入会使用默认值
|
27
|
+
config2 = IDCardConfig(name="李四")
|
28
|
+
print("normal case: config2.age -> {}".format(config2.age))
|
29
|
+
|
30
|
+
try:
|
31
|
+
IDCardConfig(age=21)
|
32
|
+
except Exception as e:
|
33
|
+
print("normal case: error -> {}".format(e))
|
34
|
+
|
35
|
+
def transform(self):
|
36
|
+
class IDCardConfig(TlConfig):
|
37
|
+
name = StringField(maxLen=8, minLen=2)
|
38
|
+
age = IntField(maxNum=200, minNum=0)
|
39
|
+
|
40
|
+
config = IDCardConfig(name="张三", age="18")
|
41
|
+
print("transform case: config.age -> {}".format(config.age))
|
42
|
+
print("transform case: config.age type -> {}".format(type(config.age)))
|
43
|
+
|
44
|
+
def customTransform(self):
|
45
|
+
# 通过自定义的字段来自定义转换方式
|
46
|
+
class DoubleIntField(IntField):
|
47
|
+
def __init__(self, *args, **kwargs):
|
48
|
+
super(DoubleIntField, self).__init__(*args, **kwargs)
|
49
|
+
|
50
|
+
self.transformFunc = self.toDouble
|
51
|
+
|
52
|
+
@staticmethod
|
53
|
+
def toDouble(value):
|
54
|
+
return value * 2
|
55
|
+
|
56
|
+
class MyConfig(TlConfig):
|
57
|
+
# 使用自定义的转换方法
|
58
|
+
double = DoubleIntField(maxNum=200)
|
59
|
+
|
60
|
+
config = MyConfig(double=100)
|
61
|
+
|
62
|
+
# 输出的值变成了输入的两倍
|
63
|
+
print("transform case: config.double -> {}".format(config.double))
|
64
|
+
|
65
|
+
config.double = 20
|
66
|
+
|
67
|
+
# 如果是后面赋值,也会及时校验和转换
|
68
|
+
print("transform case: config.double -> {}".format(config.double))
|
69
|
+
# 检测会在转换后进行检测合法性,这里输入101,通过转换后变成202,超过了字段设置的最大值,所以会触发报错
|
70
|
+
try:
|
71
|
+
config.double = 101
|
72
|
+
except Exception as e:
|
73
|
+
print("transform case: errmsg -> {}".format(e))
|
74
|
+
|
75
|
+
|
76
|
+
if __name__ == "__main__":
|
77
|
+
TlConfigCase().normal()
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2023/10/23
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 默认描述
|
8
|
+
"""
|
9
|
+
from commons.utils.config.field import Field, NoneType
|
10
|
+
|
11
|
+
__all__ = ["TlConfig"]
|
12
|
+
|
13
|
+
|
14
|
+
class TlConfigMeta(type):
|
15
|
+
def __new__(mcs, name, bases, attrs):
|
16
|
+
_fieldMap = {}
|
17
|
+
_newAttrs = {"_fieldMap": _fieldMap}
|
18
|
+
|
19
|
+
for key, value in attrs.items():
|
20
|
+
if isinstance(value, Field):
|
21
|
+
# 字段名写入到字段对象中
|
22
|
+
value.name = key
|
23
|
+
_fieldMap[key] = value
|
24
|
+
else:
|
25
|
+
_newAttrs[key] = value
|
26
|
+
|
27
|
+
_cls = super(TlConfigMeta, mcs).__new__(mcs, name, bases, _newAttrs)
|
28
|
+
return _cls
|
29
|
+
|
30
|
+
|
31
|
+
class TlConfig(metaclass=TlConfigMeta):
|
32
|
+
_autoCheck = True
|
33
|
+
|
34
|
+
def __init__(self, **kwargs):
|
35
|
+
self._originData = kwargs
|
36
|
+
self._transformData = {}
|
37
|
+
self._isTransform = False
|
38
|
+
for key, value in self._fieldMap.items():
|
39
|
+
super(TlConfig, self).__setattr__(key, NoneType)
|
40
|
+
if self._autoCheck:
|
41
|
+
self.check()
|
42
|
+
|
43
|
+
def check(self):
|
44
|
+
if not self._isTransform:
|
45
|
+
for fieldKey, field in self._fieldMap.items():
|
46
|
+
value = self._originData.get(fieldKey, NoneType)
|
47
|
+
setattr(self, fieldKey, value)
|
48
|
+
self._isTransform = True
|
49
|
+
|
50
|
+
def checkOne(self, field, value):
|
51
|
+
value = field.transform(value)
|
52
|
+
if value is NoneType and field.default is not NoneType:
|
53
|
+
value = field.default
|
54
|
+
field.check(value)
|
55
|
+
self._transformData[field.name] = value
|
56
|
+
super(TlConfig, self).__setattr__(field.name, value)
|
57
|
+
|
58
|
+
return value
|
59
|
+
|
60
|
+
def toDict(self):
|
61
|
+
if not self._isTransform:
|
62
|
+
print("警告,该配置没有经过校验和转换,请先调用 self.check()")
|
63
|
+
return self._transformData
|
64
|
+
|
65
|
+
def __setattr__(self, key, value):
|
66
|
+
if not self._autoCheck:
|
67
|
+
super(TlConfig, self).__setattr__("_isTransform", False)
|
68
|
+
if key in self._fieldMap:
|
69
|
+
self._originData[key] = value
|
70
|
+
if self._autoCheck:
|
71
|
+
field = self._fieldMap[key]
|
72
|
+
self.checkOne(field, value)
|
73
|
+
else:
|
74
|
+
super(TlConfig, self).__setattr__(key, value)
|
75
|
+
|
76
|
+
@classmethod
|
77
|
+
def getParamInfo(cls):
|
78
|
+
return list(cls._fieldMap.keys())
|
79
|
+
|
80
|
+
def __getattribute__(self, item):
|
81
|
+
"""
|
82
|
+
DEBUG 代码排查模式,尽快删除
|
83
|
+
:param item:
|
84
|
+
:return:
|
85
|
+
"""
|
86
|
+
value = super(TlConfig, self).__getattribute__(item)
|
87
|
+
if item.startswith("__"):
|
88
|
+
return value
|
89
|
+
# log.debug("DEBUG MODE: CLS:{}, KEY:{}, VALUE:{}".format(self.__class__.__name__, item, str(value)))
|
90
|
+
return value
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2023/10/23
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 默认描述
|
8
|
+
"""
|
9
|
+
|
10
|
+
from jit.errcode import Code
|
11
|
+
|
12
|
+
|
13
|
+
class TlConfigException(Code):
|
14
|
+
DEFAULT_RESULT = "配置信息错误"
|
15
|
+
|
16
|
+
def __init__(self, reason=DEFAULT_RESULT, code=-2, msg=None, solution=None):
|
17
|
+
super(TlConfigException, self).__init__(code=code, reason=reason, msg=msg, solution=solution)
|