cloudoll 2.2.16__tar.gz → 2.2.18__tar.gz

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 (43) hide show
  1. {cloudoll-2.2.16 → cloudoll-2.2.18}/PKG-INFO +1 -1
  2. cloudoll-2.2.18/cloudoll/__init__.py +1 -0
  3. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/cli.py +1 -1
  4. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/field.py +67 -1
  5. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/model.py +8 -5
  6. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/web/__init__.py +36 -62
  7. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/web/settings.py +1 -1
  8. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll.egg-info/PKG-INFO +1 -1
  9. cloudoll-2.2.16/cloudoll/__init__.py +0 -1
  10. {cloudoll-2.2.16 → cloudoll-2.2.18}/LICENSE +0 -0
  11. {cloudoll-2.2.16 → cloudoll-2.2.18}/README.md +0 -0
  12. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/__main__.py +0 -0
  13. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/error/__init__.py +0 -0
  14. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/error/errors.py +0 -0
  15. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/logging/__init__.py +0 -0
  16. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/mail/__init__.py +0 -0
  17. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/mail/smtp.py +0 -0
  18. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/__init__.py +0 -0
  19. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/base.py +0 -0
  20. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/err.py +0 -0
  21. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/mysql.py +0 -0
  22. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/parse.py +0 -0
  23. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/orm/postgres.py +0 -0
  24. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/robot/__init__.py +0 -0
  25. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/robot/dingtalk.py +0 -0
  26. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/robot/feishu.py +0 -0
  27. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/robot/slack.py +0 -0
  28. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/utils/__init__.py +0 -0
  29. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/utils/common.py +0 -0
  30. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/utils/m2d.py +0 -0
  31. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/utils/patch_loop.py +0 -0
  32. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/utils/watch.py +0 -0
  33. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/web/exception.py +0 -0
  34. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/web/html.py +0 -0
  35. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/web/http.py +0 -0
  36. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll/web/jwt.py +0 -0
  37. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll.egg-info/SOURCES.txt +0 -0
  38. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll.egg-info/dependency_links.txt +0 -0
  39. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll.egg-info/entry_points.txt +0 -0
  40. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll.egg-info/requires.txt +0 -0
  41. {cloudoll-2.2.16 → cloudoll-2.2.18}/cloudoll.egg-info/top_level.txt +0 -0
  42. {cloudoll-2.2.16 → cloudoll-2.2.18}/setup.cfg +0 -0
  43. {cloudoll-2.2.16 → cloudoll-2.2.18}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudoll
3
- Version: 2.2.16
3
+ Version: 2.2.18
4
4
  Summary: 辅助快速创建可分布的微服务。
5
5
  Home-page: https://gitee.com/chuchur/cloudoll-py
6
6
  Author: chuchur
@@ -0,0 +1 @@
1
+ __version__ = "2.2.18"
@@ -116,7 +116,7 @@ def start(environment, host, port, mode, path, entry) -> None:
116
116
  sys.exit(0)
117
117
  except Exception as e:
118
118
  # print_error(e)
119
- print_error(traceback.format_exc())
119
+ # print_error(traceback.format_exc())
120
120
  sys.exit(0)
121
121
 
122
122
 
@@ -31,6 +31,17 @@ OP = objdict(
31
31
  AVG="AVG",
32
32
  AS="AS",
33
33
  SUM="SUM",
34
+ IS_TODAY="IS_TODAY",
35
+ IS_THIS_WEEK="THIS_WEEK",
36
+ IS_THIS_MONTH="THIS_MONTH",
37
+ IS_THIS_YEAR="THIS_YEAR",
38
+ BEFORE_DAYS="BEFORE_DAYS",
39
+ BEFORE_HOURS="BEFORE_HOURS",
40
+ BEFORE_MINUTES="BEFORE_MINUTES",
41
+ BEFORE_YEARS="BEFORE_YEARS",
42
+ AFTER_YEARS="AFTER_YEARS",
43
+ AFTER_MONTHS="AFTER_MONTHS",
44
+ BEFORE_MONTHS="BEFORE_MONTHS",
34
45
  DATE_FORMAT="DATE_FORMAT",
35
46
  JSON_CONTAINS_OBJECT="JSON_CONTAINS_OBJECT",
36
47
  JSON_CONTAINS_ARRAY="JSON_CONTAINS_ARRAY",
@@ -115,6 +126,39 @@ class FieldBase(object):
115
126
  def date_format(self, args):
116
127
  return Function(self, OP.DATE_FORMAT, args)
117
128
 
129
+ def is_today(self):
130
+ return Function(self, OP.IS_TODAY)
131
+
132
+ def is_this_week(self):
133
+ return Function(self, OP.IS_THIS_WEEK)
134
+
135
+ def is_this_month(self):
136
+ return Function(self, OP.IS_THIS_MONTH)
137
+
138
+ def is_this_year(self):
139
+ return Function(self, OP.IS_THIS_YEAR)
140
+
141
+ def before_days(self, args):
142
+ return Function(self, OP.BEFORE_DAYS, args)
143
+
144
+ def before_hours(self, args):
145
+ return Function(self, OP.BEFORE_HOURS, args)
146
+
147
+ def before_minutes(self, args):
148
+ return Function(self, OP.BEFORE_MINUTES, args)
149
+
150
+ def before_years(self, args):
151
+ return Function(self, OP.BEFORE_YEARS, args)
152
+
153
+ def before_months(self, args):
154
+ return Function(self, OP.BEFORE_MONTHS, args)
155
+
156
+ def after_months(self, args):
157
+ return Function(self, OP.AFTER_MONTHS, args)
158
+
159
+ def after_years(self, args):
160
+ return Function(self, OP.AFTER_YEARS, args)
161
+
118
162
  def json_contains_object(self, key, value):
119
163
  return Function(self, OP.JSON_CONTAINS_OBJECT, (key, value))
120
164
 
@@ -186,6 +230,28 @@ class Function(FieldBase):
186
230
  # todo:
187
231
  if op == OP.DATE_FORMAT:
188
232
  return f"{op}({col_name},?)", [self.rpt]
233
+ elif op == OP.IS_TODAY:
234
+ return f"DATE({col_name}) = CURDATE()", None
235
+ elif op == OP.IS_THIS_WEEK:
236
+ return f"WEEK({col_name}, 1) = WEEK(CURDATE(), 1)", None
237
+ elif op == OP.IS_THIS_MONTH:
238
+ return f"MONTH({col_name}) = MONTH(CURDATE())", None
239
+ elif op == OP.IS_THIS_YEAR:
240
+ return f"YEAR({col_name}) = YEAR(CURDATE())", None
241
+ elif op == OP.BEFORE_DAYS:
242
+ return f"DATE({col_name}) >= CURDATE() - INTERVAL {self.rpt} DAY", None
243
+ elif op == OP.BEFORE_HOURS:
244
+ return f"{col_name} >= NOW() - INTERVAL {self.rpt} HOUR", None
245
+ elif op == OP.BEFORE_MINUTES:
246
+ return f"{col_name} >= NOW() - INTERVAL {self.rpt} MINUTE", None
247
+ elif op == OP.BEFORE_YEARS:
248
+ return f"{col_name} >= DATE_SUB(NOW(), INTERVAL {self.rpt} YEAR)", None
249
+ elif op == OP.BEFORE_MONTHS:
250
+ return f"{col_name} >= DATE_SUB(NOW(), INTERVAL {self.rpt} MONTH)", None
251
+ elif op == OP.AFTER_YEARS:
252
+ return f"{col_name} < DATE_SUB(NOW(), INTERVAL {self.rpt} YEAR)", None
253
+ elif op == OP.AFTER_MONTHS:
254
+ return f"{col_name} < DATE_SUB(NOW(), INTERVAL {self.rpt} MONTH)", None
189
255
  elif op == OP.JSON_CONTAINS_OBJECT:
190
256
  _k, _v = self.rpt
191
257
  key = _k.full_name if isinstance(_k, Field) else f"'{_k}'"
@@ -328,4 +394,4 @@ class Field(FieldBase):
328
394
 
329
395
  @value.setter
330
396
  def value(self, value):
331
- self._value = value
397
+ self._value = value
@@ -233,10 +233,13 @@ class Model(metaclass=ModelMetaclass):
233
233
  params = []
234
234
  for k, v in data.items():
235
235
  if isinstance(v, Field):
236
- value = v.value or v.default
237
- if value is not None:
238
- if "CURRENT_TIMESTAMP" in str(value):
236
+ value = v.value
237
+ if value is None:
238
+ if v.created_generated == True or v.update_generated == True:
239
239
  value = datetime.datetime.now()
240
+ else:
241
+ value = v.default
242
+ if value is not None:
240
243
  keys.append("`%s`=?" % k)
241
244
  params.append(value)
242
245
  elif v is not None: # fix sql format %s
@@ -314,7 +317,7 @@ class Model(metaclass=ModelMetaclass):
314
317
 
315
318
  sql = f"update `{table}` set {keys} {where}"
316
319
 
317
- if where is not None and where != '':
320
+ if where is not None and where != "":
318
321
  params += self.__params__
319
322
  else:
320
323
  pk, pkv = self._get_primary()
@@ -342,7 +345,7 @@ class Model(metaclass=ModelMetaclass):
342
345
  args = self.__params__
343
346
  sql = f"delete from `{table}` {where}"
344
347
 
345
- if where is None or where == '':
348
+ if where is None or where == "":
346
349
  pk, pkv = self._get_primary()
347
350
  if pkv is not None:
348
351
  sql += f" where `{pk}`=?"
@@ -12,8 +12,6 @@ import importlib
12
12
  import inspect
13
13
  import json
14
14
  from errno import EADDRINUSE
15
- import pkgutil
16
- import sys
17
15
  from urllib import parse
18
16
  from aiohttp import web
19
17
  from aiohttp.web import Response
@@ -37,6 +35,7 @@ from decimal import Decimal
37
35
  from datetime import datetime, date
38
36
  from ..utils.common import chainMap, Object
39
37
  from ..orm import create_engine, parse_coon
38
+ import uuid
40
39
 
41
40
  # from ..orm.mysql import Mysql
42
41
  from typing import Optional, Iterable
@@ -59,7 +58,7 @@ __ALL__ = (
59
58
  )
60
59
 
61
60
 
62
- class _Handler(object):
61
+ class RequestHandler(object):
63
62
  def __init__(self, cls, fn):
64
63
  self.cls = cls
65
64
  self.fn = fn
@@ -69,12 +68,12 @@ class _Handler(object):
69
68
  # 获取函数参数的名称和默认值
70
69
  props = inspect.getfullargspec(self.fn)
71
70
  if len(props.args) == 2 and content_type == "multipart/form-data":
72
- await _set_session_route(request)
71
+ await set_session_route(request)
73
72
  multipart = await request.multipart()
74
73
  field = await multipart.next()
75
74
  result = await self.fn(request, field)
76
75
  elif len(props.args) == 1:
77
- await _set_session_route(request)
76
+ await set_session_route(request)
78
77
  if content_type == "multipart/form-data":
79
78
  data = await request.post()
80
79
  elif content_type == "application/json":
@@ -109,7 +108,7 @@ class _Handler(object):
109
108
  return render_json(result)
110
109
 
111
110
 
112
- async def _set_session_route(request):
111
+ async def set_session_route(request):
113
112
  params = dict()
114
113
  # match
115
114
  rt = request.match_info
@@ -121,29 +120,6 @@ async def _set_session_route(request):
121
120
  request.session = session
122
121
 
123
122
 
124
- def _get_modules(fd):
125
- modules = set()
126
- temp = os.path.join(os.path.abspath("."), fd)
127
- if not os.path.exists(temp):
128
- print_info("Routers not detected")
129
- return modules
130
- s = find_packages(temp)
131
- for pkg in s:
132
- # modules.add(pkg)
133
- pkg_path = temp + "/" + pkg.replace(".", "/")
134
- if sys.version_info.major == 2 or (
135
- sys.version_info.major == 3 and sys.version_info.minor < 6
136
- ):
137
- for _, name, ispkg in pkgutil.iter_modules([pkg_path]):
138
- if not ispkg:
139
- modules.add(f".{pkg}.{name}")
140
- else:
141
- for info in pkgutil.iter_modules([pkg_path]):
142
- if not info.ispkg:
143
- modules.add(f".{pkg}.{info.name}")
144
- return modules
145
-
146
-
147
123
  async def check_port_open(port: int, delay: float = 1) -> None:
148
124
  loop = asyncio.get_running_loop()
149
125
  # the "s = socket.socket; s.bind" approach sometimes says a port is in use when it's not
@@ -165,21 +141,27 @@ async def check_port_open(port: int, delay: float = 1) -> None:
165
141
  raise Exception("The port {} is already is use".format(port))
166
142
 
167
143
 
168
- def _reg_middleware():
169
- root = "middlewares"
170
- mid_dir = os.path.join(os.path.abspath("."), root)
171
- # print(mid_dir)
172
- if not os.path.exists(mid_dir):
173
- print_info("Middlewares not detected")
144
+ def auto_reg_module(module_dir: str):
145
+ module_path = os.path.join(os.path.abspath("."), module_dir)
146
+ if not os.path.exists(module_path):
147
+ print_info(f"{module_dir} not detected")
174
148
  return
175
- for f in os.listdir(mid_dir):
176
- if not f.startswith("__"):
177
- module_name = f"{root}.{os.path.basename(f)[:-3]}"
178
- # print(module_name, root)
179
- importlib.import_module(module_name, root)
149
+ for filename in os.listdir(module_dir):
150
+ if filename.startswith("__") or filename.startswith("."):
151
+ continue
152
+ full_path = os.path.join(os.path.abspath("."), module_dir, filename)
153
+ if os.path.isdir(full_path):
154
+ auto_reg_module(module_dir + os.sep + filename)
155
+ elif filename.endswith(".py"):
156
+ module_name = (
157
+ module_dir.replace(os.sep, ".")
158
+ + "."
159
+ + filename[:-3].replace(os.sep, ".")
160
+ )
161
+ importlib.import_module(module_name)
180
162
 
181
163
 
182
- def _int(num):
164
+ def parse_int(num):
183
165
  return eval(num) if isinstance(num, str) else num
184
166
 
185
167
 
@@ -234,7 +216,7 @@ class Application(object):
234
216
  self.config = config
235
217
 
236
218
  # middlewares
237
- _reg_middleware()
219
+ auto_reg_module("middlewares")
238
220
 
239
221
  conf_server = config.get("server")
240
222
  client_max_size = 1024**2 * 2
@@ -244,7 +226,7 @@ class Application(object):
244
226
  logger=None,
245
227
  loop=loop,
246
228
  middlewares=self._middleware,
247
- client_max_size=_int(client_max_size),
229
+ client_max_size=parse_int(client_max_size),
248
230
  )
249
231
  # database
250
232
  self.app.db = Object()
@@ -257,10 +239,11 @@ class Application(object):
257
239
  self.app.on_startup.append(self._init_session)
258
240
  # self._init_session()
259
241
  # router:
260
- self._reg_router()
242
+ auto_reg_module("controllers")
243
+ self.app.add_routes(self._route_table)
261
244
 
262
245
  # load life
263
- entry = conf_server.get('entry',entry_model)
246
+ entry = conf_server.get("entry", entry_model)
264
247
  self._load_life_cycle(entry)
265
248
 
266
249
  # static
@@ -333,7 +316,7 @@ class Application(object):
333
316
  storage = redis_storage.RedisStorage(
334
317
  redis,
335
318
  cookie_name=cookie_name,
336
- max_age=_int(max_age),
319
+ max_age=parse_int(max_age),
337
320
  httponly=httponly,
338
321
  secure=secure,
339
322
  )
@@ -348,7 +331,7 @@ class Application(object):
348
331
  storage = memcached_storage.MemcachedStorage(
349
332
  mc,
350
333
  cookie_name=cookie_name,
351
- max_age=_int(max_age),
334
+ max_age=parse_int(max_age),
352
335
  httponly=httponly,
353
336
  secure=secure,
354
337
  )
@@ -365,23 +348,12 @@ class Application(object):
365
348
  storage = cookie_storage.EncryptedCookieStorage(
366
349
  secret_key,
367
350
  cookie_name=cookie_name,
368
- max_age=_int(max_age),
351
+ max_age=parse_int(max_age),
369
352
  httponly=httponly,
370
353
  )
371
354
  setup(apps, storage)
372
355
  print_info("start local cookie.")
373
356
 
374
- def _reg_router(self):
375
- fd = "controllers"
376
- modules = _get_modules(fd)
377
- for module in modules:
378
- # print(module)
379
- importlib.import_module(module, fd)
380
-
381
- self.app.add_routes(self._route_table)
382
- # for route in self._routes:
383
- # self.app.router.add_route(**route)
384
-
385
357
  def run(self, **kw):
386
358
  """
387
359
  run app
@@ -417,7 +389,7 @@ class Application(object):
417
389
 
418
390
  def add_router(self, path, method, name):
419
391
  def inner(handler):
420
- handler = _Handler(self, handler)
392
+ handler = RequestHandler(self, handler)
421
393
  self.app.router.add_route(method, path, handler, name=name)
422
394
  return handler
423
395
 
@@ -478,6 +450,8 @@ class JsonEncoder(json.JSONEncoder):
478
450
  return list(obj)
479
451
  elif isinstance(obj, Model):
480
452
  return obj.__dict__
453
+ elif isinstance(obj, uuid.UUID):
454
+ return str(obj)
481
455
  else:
482
456
  return super(JsonEncoder, self).default(obj)
483
457
 
@@ -556,8 +530,8 @@ def render_json(data, **kw) -> Response:
556
530
  res["data"] = data
557
531
  status = kw.get("status", 200)
558
532
  if status == 200:
559
- res["message"] = "OK"
560
- res["code"] = 200
533
+ res["message"] = kw.get("message", "OK")
534
+ res["code"] = kw.get("code", 200)
561
535
 
562
536
  res["timestamp"] = int(datetime.now().timestamp() * 1000)
563
537
  text = json.dumps(res, ensure_ascii=False, cls=JsonEncoder)
@@ -11,6 +11,6 @@ def get_config(env):
11
11
  if not os.path.exists(conf_path):
12
12
  print_error(f"Configuration file does not exist: {conf_path}")
13
13
  return {}
14
- with open(conf_path,'r',encoding='utf-8') as f:
14
+ with open(conf_path, "r", encoding="utf-8") as f:
15
15
  config = yaml.safe_load(f)
16
16
  return config or {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudoll
3
- Version: 2.2.16
3
+ Version: 2.2.18
4
4
  Summary: 辅助快速创建可分布的微服务。
5
5
  Home-page: https://gitee.com/chuchur/cloudoll-py
6
6
  Author: chuchur
@@ -1 +0,0 @@
1
- __version__ = "2.2.16"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes