cloudoll 2.4.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.
- cloudoll/__init__.py +1 -0
- cloudoll/__main__.py +4 -0
- cloudoll/cli.py +76 -0
- cloudoll/error/__init__.py +0 -0
- cloudoll/error/errors.py +48 -0
- cloudoll/logging/__init__.py +188 -0
- cloudoll/mail/__init__.py +0 -0
- cloudoll/mail/smtp.py +197 -0
- cloudoll/orm/__init__.py +252 -0
- cloudoll/orm/base.py +80 -0
- cloudoll/orm/err.py +2 -0
- cloudoll/orm/field.py +522 -0
- cloudoll/orm/model.py +806 -0
- cloudoll/orm/mysql.py +84 -0
- cloudoll/orm/parse.py +139 -0
- cloudoll/orm/postgres.py +70 -0
- cloudoll/robot/__init__.py +0 -0
- cloudoll/robot/dingtalk.py +209 -0
- cloudoll/robot/feishu.py +102 -0
- cloudoll/robot/slack.py +115 -0
- cloudoll/utils/__init__.py +0 -0
- cloudoll/utils/cli_main.py +72 -0
- cloudoll/utils/cli_mian.py +74 -0
- cloudoll/utils/common.py +57 -0
- cloudoll/utils/m2d.py +311 -0
- cloudoll/utils/patch_loop.py +222 -0
- cloudoll/utils/snowflake.py +86 -0
- cloudoll/utils/watch.py +194 -0
- cloudoll/web/__init__.py +53 -0
- cloudoll/web/core.py +557 -0
- cloudoll/web/exception.py +63 -0
- cloudoll/web/html.py +93 -0
- cloudoll/web/http.py +79 -0
- cloudoll/web/jwt.py +40 -0
- cloudoll/web/requests.py +161 -0
- cloudoll/web/settings.py +22 -0
- cloudoll-2.4.0.dist-info/METADATA +414 -0
- cloudoll-2.4.0.dist-info/RECORD +42 -0
- cloudoll-2.4.0.dist-info/WHEEL +6 -0
- cloudoll-2.4.0.dist-info/entry_points.txt +2 -0
- cloudoll-2.4.0.dist-info/licenses/LICENSE +21 -0
- cloudoll-2.4.0.dist-info/top_level.txt +1 -0
cloudoll/orm/__init__.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
from redis import asyncio as aioredis
|
|
2
|
+
from .parse import parse_coon
|
|
3
|
+
from .base import MeteBase, QueryTypes
|
|
4
|
+
from typing import Any
|
|
5
|
+
from ..logging import print_info, print_error
|
|
6
|
+
import traceback
|
|
7
|
+
import aiomysql
|
|
8
|
+
from aiomysql import Pool as MYPool
|
|
9
|
+
|
|
10
|
+
import aiopg as pg
|
|
11
|
+
from aiopg.pool import Pool as PGPool
|
|
12
|
+
|
|
13
|
+
__ALL__ = "create_engine"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def create_engine(**kw):
|
|
17
|
+
url = kw.get("url")
|
|
18
|
+
driver = None
|
|
19
|
+
configs = {}
|
|
20
|
+
query = {}
|
|
21
|
+
|
|
22
|
+
if url is not None:
|
|
23
|
+
configs, query = parse_coon(url)
|
|
24
|
+
driver = configs["type"]
|
|
25
|
+
else:
|
|
26
|
+
driver = kw.get("type")
|
|
27
|
+
configs = kw
|
|
28
|
+
|
|
29
|
+
# print_info("DB Config:", configs, query)
|
|
30
|
+
|
|
31
|
+
if driver == "mysql":
|
|
32
|
+
return await Mysql().create_engine(**configs, **query)
|
|
33
|
+
elif driver == "postgres" or driver == "postgressql":
|
|
34
|
+
return await Postgres().create_engine(**configs, **query)
|
|
35
|
+
elif driver == "redis" or driver == "rediss":
|
|
36
|
+
"""
|
|
37
|
+
redis://[[username]:[password]]@localhost:6379/0
|
|
38
|
+
rediss://[[username]:[password]]@localhost:6379/0
|
|
39
|
+
"""
|
|
40
|
+
if url is None:
|
|
41
|
+
url = f"{driver}://{configs['username']}:{configs['password']}@{configs['host']}:{configs['port']}/{configs['db']}"
|
|
42
|
+
return await aioredis.from_url(url, **query)
|
|
43
|
+
else:
|
|
44
|
+
raise "Not suport this database type."
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Postgres(MeteBase):
|
|
48
|
+
def __init__(self, pool=None):
|
|
49
|
+
self.pool: PGPool = pool
|
|
50
|
+
self.driver = "postgres"
|
|
51
|
+
|
|
52
|
+
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
53
|
+
self.__init__(*args, **kwds)
|
|
54
|
+
|
|
55
|
+
async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
|
|
56
|
+
sql = sql.replace("?", "%s").replace("`", '"')
|
|
57
|
+
if not self.pool:
|
|
58
|
+
raise ValueError("must be create_engine first.")
|
|
59
|
+
if self.pool._closing or self.pool._closed:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
async with self.pool.acquire() as conn:
|
|
63
|
+
if conn.echo:
|
|
64
|
+
print_info("sql", sql, params)
|
|
65
|
+
|
|
66
|
+
async with conn.cursor() as cursor:
|
|
67
|
+
# current_cursor = getattr(cursor, 'lastrowid', None)
|
|
68
|
+
if (
|
|
69
|
+
query_type == QueryTypes.CREATEBATCH
|
|
70
|
+
or query_type == QueryTypes.UPDATEBATCH
|
|
71
|
+
):
|
|
72
|
+
# aiopg don't support executemany
|
|
73
|
+
raise RuntimeError("postgres don't support executemany")
|
|
74
|
+
else:
|
|
75
|
+
await cursor.execute(sql, params)
|
|
76
|
+
|
|
77
|
+
result = None
|
|
78
|
+
|
|
79
|
+
if query_type == QueryTypes.ALL:
|
|
80
|
+
columns = [desc[0] for desc in cursor.description]
|
|
81
|
+
rows = await cursor.fetchall()
|
|
82
|
+
result = [dict(zip(columns, row)) for row in rows]
|
|
83
|
+
return result
|
|
84
|
+
elif query_type == QueryTypes.ONE:
|
|
85
|
+
columns = [desc[0] for desc in cursor.description]
|
|
86
|
+
row = await cursor.fetchone()
|
|
87
|
+
result = dict(zip(columns, row)) if row else {}
|
|
88
|
+
return result
|
|
89
|
+
elif query_type == QueryTypes.MANY:
|
|
90
|
+
columns = [desc[0] for desc in cursor.description]
|
|
91
|
+
rows = await cursor.fetchmany(size)
|
|
92
|
+
result = [dict(zip(columns, row)) for row in rows]
|
|
93
|
+
return result
|
|
94
|
+
elif query_type == QueryTypes.COUNT:
|
|
95
|
+
result = await cursor.fetchone()
|
|
96
|
+
count = 0
|
|
97
|
+
if rows is None:
|
|
98
|
+
return count
|
|
99
|
+
for row in rows:
|
|
100
|
+
count = rows[row]
|
|
101
|
+
return count
|
|
102
|
+
elif query_type == QueryTypes.GROUP_COUNT:
|
|
103
|
+
result = await cursor.fetchall()
|
|
104
|
+
return 0 if not result else len(result)
|
|
105
|
+
elif query_type == QueryTypes.CREATE:
|
|
106
|
+
result = cursor.rowcount > 0
|
|
107
|
+
id = cursor.lastrowid
|
|
108
|
+
return result, id
|
|
109
|
+
elif query_type == QueryTypes.CREATEBATCH:
|
|
110
|
+
count = cursor.rowcount
|
|
111
|
+
id = cursor.lastrowid
|
|
112
|
+
return count, id
|
|
113
|
+
elif query_type == QueryTypes.UPDATE:
|
|
114
|
+
return cursor.rowcount > 0
|
|
115
|
+
elif query_type == QueryTypes.UPDATEBATCH:
|
|
116
|
+
return cursor.rowcount
|
|
117
|
+
elif query_type == QueryTypes.DELETE:
|
|
118
|
+
return cursor.rowcount > 0
|
|
119
|
+
|
|
120
|
+
self.pool.release(cursor)
|
|
121
|
+
|
|
122
|
+
async def create_engine(self, **kw):
|
|
123
|
+
try:
|
|
124
|
+
host = (kw.get("host", "localhost"),)
|
|
125
|
+
port = (kw.get("port", 5432),)
|
|
126
|
+
user = (kw.get("username"),)
|
|
127
|
+
password = (str(kw.get("password", "")),)
|
|
128
|
+
db = (kw.get("db"),)
|
|
129
|
+
dsn = f"dbname={db[0]} user={user[0]} password={password[0]} host={host[0]} port={port[0]}" # aiopg
|
|
130
|
+
# dsn = f"postgres://{user[0]}:{password[0]}@{host[0]}:{port[0]}/{db[0]}" # asyncpg
|
|
131
|
+
self.pool = await pg.create_pool(
|
|
132
|
+
dsn=dsn,
|
|
133
|
+
timeout=kw.get("timeout"),
|
|
134
|
+
echo=kw.get("echo", False), # aiopg
|
|
135
|
+
# max_size=kw.get("maxsize", 10), # asyncpg
|
|
136
|
+
# min_size=kw.get("minsize", 5), # asyncpg
|
|
137
|
+
maxsize=kw.get("maxsize", 10), # aiopg
|
|
138
|
+
minsize=kw.get("minsize", 5), # aiopg
|
|
139
|
+
)
|
|
140
|
+
print_info(f"Database connection successfuly for postgres/{kw.get('db')}")
|
|
141
|
+
except Exception as e:
|
|
142
|
+
print_error(e)
|
|
143
|
+
# print(traceback.format_exc())
|
|
144
|
+
print_error(
|
|
145
|
+
f"Database connection failed,the instance : postgres/{kw.get('db')}"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return self
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class AttrDict(dict):
|
|
152
|
+
"""Dict that can get attribute by dot, and doesn't raise KeyError"""
|
|
153
|
+
|
|
154
|
+
def __getattr__(self, name):
|
|
155
|
+
try:
|
|
156
|
+
return self[name]
|
|
157
|
+
except KeyError:
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class AttrDictCursor(aiomysql.DictCursor):
|
|
162
|
+
dict_type = AttrDict
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class Mysql(MeteBase):
|
|
166
|
+
def __init__(self, pool=None):
|
|
167
|
+
self.pool: MYPool = pool
|
|
168
|
+
self.driver = "mysql"
|
|
169
|
+
|
|
170
|
+
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
171
|
+
self.__init__(*args, **kwds)
|
|
172
|
+
return self
|
|
173
|
+
|
|
174
|
+
async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
|
|
175
|
+
sql = sql.replace("?", "%s")
|
|
176
|
+
if not self.pool:
|
|
177
|
+
raise ValueError("must be create_engine first.")
|
|
178
|
+
if self.pool._closing or self.pool._closed:
|
|
179
|
+
return None
|
|
180
|
+
async with self.pool.acquire() as conn:
|
|
181
|
+
if conn.echo:
|
|
182
|
+
print_info("sql", sql, params)
|
|
183
|
+
|
|
184
|
+
async with conn.cursor() as cursor:
|
|
185
|
+
# current_cursor = getattr(cursor, 'lastrowid', None)
|
|
186
|
+
if (
|
|
187
|
+
query_type == QueryTypes.CREATEBATCH
|
|
188
|
+
or query_type == QueryTypes.UPDATEBATCH
|
|
189
|
+
):
|
|
190
|
+
await cursor.executemany(sql, params)
|
|
191
|
+
else:
|
|
192
|
+
await cursor.execute(sql, params)
|
|
193
|
+
|
|
194
|
+
await conn.commit()
|
|
195
|
+
|
|
196
|
+
if query_type == QueryTypes.ALL:
|
|
197
|
+
return await cursor.fetchall()
|
|
198
|
+
elif query_type == QueryTypes.ONE:
|
|
199
|
+
return await cursor.fetchone()
|
|
200
|
+
elif query_type == QueryTypes.MANY:
|
|
201
|
+
return await cursor.fetchmany(size)
|
|
202
|
+
elif query_type == QueryTypes.COUNT:
|
|
203
|
+
rows = await cursor.fetchone()
|
|
204
|
+
count = 0
|
|
205
|
+
if rows is None:
|
|
206
|
+
return count
|
|
207
|
+
for row in rows:
|
|
208
|
+
count = rows[row]
|
|
209
|
+
return count
|
|
210
|
+
elif query_type == QueryTypes.GROUP_COUNT:
|
|
211
|
+
result = await cursor.fetchall()
|
|
212
|
+
return 0 if not result else len(result)
|
|
213
|
+
elif query_type == QueryTypes.CREATE:
|
|
214
|
+
result = cursor.rowcount > 0
|
|
215
|
+
id = cursor.lastrowid
|
|
216
|
+
return result, id
|
|
217
|
+
elif query_type == QueryTypes.CREATEBATCH:
|
|
218
|
+
count = cursor.rowcount
|
|
219
|
+
id = cursor.lastrowid
|
|
220
|
+
return count, id
|
|
221
|
+
elif query_type == QueryTypes.UPDATE:
|
|
222
|
+
return cursor.rowcount > 0
|
|
223
|
+
elif query_type == QueryTypes.UPDATEBATCH:
|
|
224
|
+
return cursor.rowcount
|
|
225
|
+
elif query_type == QueryTypes.DELETE:
|
|
226
|
+
return cursor.rowcount > 0
|
|
227
|
+
|
|
228
|
+
self.pool.release(conn)
|
|
229
|
+
|
|
230
|
+
async def create_engine(self, loop=None, **kw):
|
|
231
|
+
try:
|
|
232
|
+
self.pool = await aiomysql.create_pool(
|
|
233
|
+
host=kw.get("host", "localhost"),
|
|
234
|
+
port=kw.get("port", 3306),
|
|
235
|
+
user=kw.get("username"),
|
|
236
|
+
password=str(kw.get("password", "")),
|
|
237
|
+
db=kw.get("db"),
|
|
238
|
+
echo=kw.get("echo", False),
|
|
239
|
+
charset=kw.get("charset", "utf8"),
|
|
240
|
+
autocommit=False, # kw.get("autocommit", False),
|
|
241
|
+
maxsize=kw.get("maxsize", 10),
|
|
242
|
+
minsize=kw.get("minsize", 5),
|
|
243
|
+
cursorclass=AttrDictCursor,
|
|
244
|
+
loop=loop,
|
|
245
|
+
)
|
|
246
|
+
print_info(f"Database connection successfuly for mysql/{kw.get('db')}.")
|
|
247
|
+
except Exception as e:
|
|
248
|
+
# print(traceback.format_exc())
|
|
249
|
+
print_error(
|
|
250
|
+
f"Database connection failed,the instance : mysql/{kw.get('db')}"
|
|
251
|
+
)
|
|
252
|
+
return self
|
cloudoll/orm/base.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Tuple
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class QueryTypes(Enum):
|
|
6
|
+
ALL = 1
|
|
7
|
+
ONE = 2
|
|
8
|
+
MANY = 3
|
|
9
|
+
COUNT = 4
|
|
10
|
+
CREATE = 5
|
|
11
|
+
UPDATE = 6
|
|
12
|
+
DELETE = 7
|
|
13
|
+
CREATEBATCH = 8
|
|
14
|
+
UPDATEBATCH = 9
|
|
15
|
+
GROUP_COUNT = 10
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MeteBase:
|
|
19
|
+
|
|
20
|
+
async def __aexit__(self):
|
|
21
|
+
await self.close()
|
|
22
|
+
|
|
23
|
+
async def close(self):
|
|
24
|
+
if self.pool:
|
|
25
|
+
self.pool.close()
|
|
26
|
+
await self.pool.wait_closed()
|
|
27
|
+
|
|
28
|
+
# async def begin_transaction(self):
|
|
29
|
+
# conn = await self._set_conn()
|
|
30
|
+
# await conn.begin()
|
|
31
|
+
# return conn
|
|
32
|
+
|
|
33
|
+
# async def begin_transaction_scope(self, fun):
|
|
34
|
+
# conn = await self._set_conn()
|
|
35
|
+
# await conn.begin()
|
|
36
|
+
# cursor = None
|
|
37
|
+
# if isfunction(fun):
|
|
38
|
+
# try:
|
|
39
|
+
# cursor = await conn.cursor()
|
|
40
|
+
# await fun(cursor)
|
|
41
|
+
# await conn.commit()
|
|
42
|
+
# except Exception as e:
|
|
43
|
+
# print_error(e)
|
|
44
|
+
# await conn.rollback()
|
|
45
|
+
# finally:
|
|
46
|
+
# if cursor:
|
|
47
|
+
# await cursor.close()
|
|
48
|
+
# self.pool.release(conn)
|
|
49
|
+
async def query(
|
|
50
|
+
self, sql, params=None, query_type: QueryTypes = 2, size: int = 10
|
|
51
|
+
): ...
|
|
52
|
+
|
|
53
|
+
async def all(self, sql, params):
|
|
54
|
+
return await self.query(sql, params, QueryTypes.ALL)
|
|
55
|
+
|
|
56
|
+
async def one(self, sql, params):
|
|
57
|
+
return await self.query(sql, params, QueryTypes.ONE)
|
|
58
|
+
|
|
59
|
+
async def many(self, sql, params, size: int):
|
|
60
|
+
return await self.query(sql, params, QueryTypes.MANY, size)
|
|
61
|
+
|
|
62
|
+
async def count(self, sql, params):
|
|
63
|
+
return await self.query(sql, params, QueryTypes.COUNT)
|
|
64
|
+
async def group_count(self, sql, params):
|
|
65
|
+
return await self.query(sql, params, QueryTypes.GROUP_COUNT)
|
|
66
|
+
|
|
67
|
+
async def update(self, sql, params):
|
|
68
|
+
return await self.query(sql, params, QueryTypes.UPDATE)
|
|
69
|
+
|
|
70
|
+
async def update_batch(self, sql, params):
|
|
71
|
+
return await self.query(sql, params, QueryTypes.UPDATEBATCH)
|
|
72
|
+
|
|
73
|
+
async def delete(self, sql, params):
|
|
74
|
+
return await self.query(sql, params, QueryTypes.DELETE)
|
|
75
|
+
|
|
76
|
+
async def create(self, sql, params) -> Tuple[bool, int]:
|
|
77
|
+
return await self.query(sql, params, QueryTypes.CREATE)
|
|
78
|
+
|
|
79
|
+
async def create_batch(self, sql, params):
|
|
80
|
+
return await self.query(sql, params, QueryTypes.CREATEBATCH)
|
cloudoll/orm/err.py
ADDED