cloudoll 2.2.23__tar.gz → 2.2.24__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 (44) hide show
  1. {cloudoll-2.2.23 → cloudoll-2.2.24}/PKG-INFO +1 -1
  2. cloudoll-2.2.24/cloudoll/__init__.py +1 -0
  3. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/__init__.py +107 -17
  4. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/base.py +8 -0
  5. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/model.py +65 -11
  6. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/feishu.py +2 -1
  7. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/m2d.py +2 -1
  8. cloudoll-2.2.24/cloudoll/utils/snowflake.py +86 -0
  9. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/PKG-INFO +1 -1
  10. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/SOURCES.txt +1 -0
  11. cloudoll-2.2.23/cloudoll/__init__.py +0 -1
  12. {cloudoll-2.2.23 → cloudoll-2.2.24}/LICENSE +0 -0
  13. {cloudoll-2.2.23 → cloudoll-2.2.24}/README.md +0 -0
  14. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/__main__.py +0 -0
  15. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/cli.py +0 -0
  16. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/error/__init__.py +0 -0
  17. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/error/errors.py +0 -0
  18. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/logging/__init__.py +0 -0
  19. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/mail/__init__.py +0 -0
  20. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/mail/smtp.py +0 -0
  21. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/err.py +0 -0
  22. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/field.py +0 -0
  23. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/mysql.py +0 -0
  24. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/parse.py +0 -0
  25. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/postgres.py +0 -0
  26. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/__init__.py +0 -0
  27. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/dingtalk.py +0 -0
  28. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/slack.py +0 -0
  29. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/__init__.py +0 -0
  30. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/common.py +0 -0
  31. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/patch_loop.py +0 -0
  32. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/watch.py +0 -0
  33. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/__init__.py +0 -0
  34. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/exception.py +0 -0
  35. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/html.py +0 -0
  36. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/http.py +0 -0
  37. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/jwt.py +0 -0
  38. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/settings.py +0 -0
  39. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/dependency_links.txt +0 -0
  40. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/entry_points.txt +0 -0
  41. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/requires.txt +0 -0
  42. {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/top_level.txt +0 -0
  43. {cloudoll-2.2.23 → cloudoll-2.2.24}/setup.cfg +0 -0
  44. {cloudoll-2.2.23 → cloudoll-2.2.24}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudoll
3
- Version: 2.2.23
3
+ Version: 2.2.24
4
4
  Summary: 辅助快速创建可分布的微服务。
5
5
  Home-page: https://gitee.com/chuchur/cloudoll-py
6
6
  Author: chuchur
@@ -0,0 +1 @@
1
+ __version__ = "2.2.24"
@@ -1,13 +1,20 @@
1
1
  from redis import asyncio as aioredis
2
2
  from .parse import parse_coon
3
- import aiopg, aiomysql
4
3
  from .base import MeteBase, QueryTypes
5
4
  from typing import Any
6
5
  from ..logging import print_info, print_error
7
6
  import traceback
7
+ import aiomysql
8
8
  from aiomysql import Pool as MYPool
9
+
10
+ import aiopg as pg
9
11
  from aiopg.pool import Pool as PGPool
10
12
 
13
+ # import asyncpg as pg
14
+ # from asyncpg.pool import Pool as PGPool
15
+
16
+ __ALL__ = "create_engine"
17
+
11
18
 
12
19
  async def create_engine(**kw):
13
20
  url = kw.get("url")
@@ -48,6 +55,65 @@ class Postgres(MeteBase):
48
55
  def __call__(self, *args: Any, **kwds: Any) -> Any:
49
56
  self.__init__(*args, **kwds)
50
57
 
58
+ # async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
59
+ # sql = sql.replace("?", "%s").replace("`", "")
60
+ # print_info("sql", sql, params)
61
+ # if not self.pool:
62
+ # raise ValueError("must be create_engine first.")
63
+ # if self.pool._closing or self.pool._closed:
64
+ # return None
65
+
66
+ # # async with self.pool.acquire() as conn:
67
+ # async with self.pool.acquire() as conn:
68
+ # # current_cursor = getattr(cursor, 'lastrowid', None)
69
+ # if (
70
+ # query_type == QueryTypes.CREATEBATCH
71
+ # or query_type == QueryTypes.UPDATEBATCH
72
+ # ):
73
+ # result = await conn.executemany(sql, params) # aiopg don't support executemany
74
+ # else:
75
+ # result = await conn.execute(sql, params)
76
+
77
+ # # result = None
78
+
79
+ # return result
80
+
81
+ # if query_type == QueryTypes.ALL:
82
+ # columns = [desc[0] for desc in cursor.description]
83
+ # rows = await cursor.fetchall()
84
+ # result = [dict(zip(columns, row)) for row in rows]
85
+ # return result
86
+ # elif query_type == QueryTypes.ONE:
87
+ # columns = [desc[0] for desc in cursor.description]
88
+ # row = await cursor.fetchone()
89
+ # # print("rows_reuslt", rows)
90
+ # result = dict(zip(columns, row)) if row else {}
91
+ # return result
92
+ # elif query_type == QueryTypes.MANY:
93
+ # columns = [desc[0] for desc in cursor.description]
94
+ # rows = await cursor.fetchmany(size)
95
+ # result = [dict(zip(columns, row)) for row in rows]
96
+ # return result
97
+ # elif query_type == QueryTypes.COUNT:
98
+ # rs = await cursor.fetchone()
99
+ # return rs[0] if row else 0
100
+ # elif query_type == QueryTypes.CREATE:
101
+ # result = cursor.rowcount > 0
102
+ # id = cursor.lastrowid
103
+ # return result, id
104
+ # elif query_type == QueryTypes.CREATEBATCH:
105
+ # count = cursor.rowcount
106
+ # id = cursor.lastrowid
107
+ # return count, id
108
+ # elif query_type == QueryTypes.UPDATE:
109
+ # return cursor.rowcount > 0
110
+ # elif query_type == QueryTypes.UPDATEBATCH:
111
+ # return cursor.rowcount
112
+ # elif query_type == QueryTypes.DELETE:
113
+ # return cursor.rowcount > 0
114
+
115
+ # self.pool.release(cursor)
116
+
51
117
  async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
52
118
  sql = sql.replace("?", "%s").replace("`", "")
53
119
  print_info("sql", sql, params)
@@ -55,16 +121,19 @@ class Postgres(MeteBase):
55
121
  raise ValueError("must be create_engine first.")
56
122
  if self.pool._closing or self.pool._closed:
57
123
  return None
124
+
58
125
  async with self.pool.acquire() as conn:
59
126
  async with conn.cursor() as cursor:
60
127
  # current_cursor = getattr(cursor, 'lastrowid', None)
61
- await cursor.execute(sql, params)
128
+ if (
129
+ query_type == QueryTypes.CREATEBATCH
130
+ or query_type == QueryTypes.UPDATEBATCH
131
+ ):
132
+ # aiopg don't support executemany
133
+ await cursor.executemany(sql, params)
134
+ else:
135
+ await cursor.execute(sql, params)
62
136
 
63
- # if query_type.value > 4:
64
- # if self.driver == "mysql":
65
- # print(columns)
66
- # await conn.commit()
67
- # elif self.driver == "postgres":
68
137
  result = None
69
138
 
70
139
  if query_type == QueryTypes.ALL:
@@ -90,12 +159,18 @@ class Postgres(MeteBase):
90
159
  result = cursor.rowcount > 0
91
160
  id = cursor.lastrowid
92
161
  return result, id
162
+ elif query_type == QueryTypes.CREATEBATCH:
163
+ count = cursor.rowcount
164
+ id = cursor.lastrowid
165
+ return count, id
93
166
  elif query_type == QueryTypes.UPDATE:
94
167
  return cursor.rowcount > 0
168
+ elif query_type == QueryTypes.UPDATEBATCH:
169
+ return cursor.rowcount
95
170
  elif query_type == QueryTypes.DELETE:
96
171
  return cursor.rowcount > 0
97
172
 
98
- self.pool.release(conn)
173
+ self.pool.release(cursor)
99
174
 
100
175
  async def create_engine(self, **kw):
101
176
  try:
@@ -104,17 +179,20 @@ class Postgres(MeteBase):
104
179
  user = (kw.get("username"),)
105
180
  password = (str(kw.get("password", "")),)
106
181
  db = (kw.get("db"),)
107
- dsn = f"dbname={db[0]} user={user[0]} password={password[0]} host={host[0]} port={port[0]}"
108
- self.pool = await aiopg.create_pool(
182
+ dsn = f"dbname={db[0]} user={user[0]} password={password[0]} host={host[0]} port={port[0]}" # aiopg
183
+ # dsn = f"postgres://{user[0]}:{password[0]}@{host[0]}:{port[0]}/{db[0]}" #asyncpg
184
+ self.pool = await pg.create_pool(
109
185
  dsn=dsn,
110
186
  timeout=kw.get("timeout"),
111
- echo=kw.get("echo", False),
112
- maxsize=kw.get("maxsize", 10),
113
- minsize=kw.get("pool_size", 5),
187
+ echo=kw.get("echo", False), # aiopg
188
+ # max_size=kw.get("maxsize", 10), #asyncpg
189
+ # min_size=kw.get("minsize", 5), #asyncpg
190
+ maxsize=kw.get("maxsize", 10), # aiopg
191
+ minsize=kw.get("minsize", 5), # aiopg
114
192
  )
115
193
  print_info(f"Database connection successfuly for postgres/{kw.get('db')}")
116
194
  except Exception as e:
117
- # print_error(e)
195
+ print_error(e)
118
196
  # print(traceback.format_exc())
119
197
  print_error(
120
198
  f"Database connection failed,the instance : postgres/{kw.get('db')}"
@@ -148,7 +226,7 @@ class Mysql(MeteBase):
148
226
 
149
227
  async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
150
228
  sql = sql.replace("?", "%s")
151
- print_info("sql", sql, params)
229
+ # print_info("sql", sql, params)
152
230
  if not self.pool:
153
231
  raise ValueError("must be create_engine first.")
154
232
  if self.pool._closing or self.pool._closed:
@@ -156,7 +234,13 @@ class Mysql(MeteBase):
156
234
  async with self.pool.acquire() as conn:
157
235
  async with conn.cursor() as cursor:
158
236
  # current_cursor = getattr(cursor, 'lastrowid', None)
159
- await cursor.execute(sql, params)
237
+ if (
238
+ query_type == QueryTypes.CREATEBATCH
239
+ or query_type == QueryTypes.UPDATEBATCH
240
+ ):
241
+ await cursor.executemany(sql, params)
242
+ else:
243
+ await cursor.execute(sql, params)
160
244
 
161
245
  # if query_type.value > 4:
162
246
  # if self.driver == "mysql":
@@ -180,8 +264,14 @@ class Mysql(MeteBase):
180
264
  result = cursor.rowcount > 0
181
265
  id = cursor.lastrowid
182
266
  return result, id
267
+ elif query_type == QueryTypes.CREATEBATCH:
268
+ count = cursor.rowcount
269
+ id = cursor.lastrowid
270
+ return count, id
183
271
  elif query_type == QueryTypes.UPDATE:
184
272
  return cursor.rowcount > 0
273
+ elif query_type == QueryTypes.UPDATEBATCH:
274
+ return cursor.rowcount
185
275
  elif query_type == QueryTypes.DELETE:
186
276
  return cursor.rowcount > 0
187
277
 
@@ -199,7 +289,7 @@ class Mysql(MeteBase):
199
289
  charset=kw.get("charset", "utf8"),
200
290
  autocommit=False, # kw.get("autocommit", False),
201
291
  maxsize=kw.get("maxsize", 10),
202
- minsize=kw.get("pool_size", 5),
292
+ minsize=kw.get("minsize", 5),
203
293
  cursorclass=AttrDictCursor,
204
294
  loop=loop,
205
295
  )
@@ -9,6 +9,8 @@ class QueryTypes(Enum):
9
9
  CREATE = 5
10
10
  UPDATE = 6
11
11
  DELETE = 7
12
+ CREATEBATCH = 8
13
+ UPDATEBATCH = 9
12
14
 
13
15
 
14
16
  class MeteBase:
@@ -60,9 +62,15 @@ class MeteBase:
60
62
 
61
63
  async def update(self, sql, params):
62
64
  return await self.query(sql, params, QueryTypes.UPDATE)
65
+
66
+ async def update_batch(self, sql, params):
67
+ return await self.query(sql, params, QueryTypes.UPDATEBATCH)
63
68
 
64
69
  async def delete(self, sql, params):
65
70
  return await self.query(sql, params, QueryTypes.DELETE)
66
71
 
67
72
  async def create(self, sql, params):
68
73
  return await self.query(sql, params, QueryTypes.CREATE)
74
+
75
+ async def create_batch(self, sql, params):
76
+ return await self.query(sql, params, QueryTypes.CREATEBATCH)
@@ -7,6 +7,8 @@ import re
7
7
  import datetime
8
8
  from ..utils.common import Object
9
9
 
10
+ __ALL__ = ("models", "Model")
11
+
10
12
 
11
13
  class ModelMetaclass(type):
12
14
  # def __init__(self, **kw):
@@ -197,9 +199,7 @@ class Model(metaclass=ModelMetaclass):
197
199
  if isinstance(f, str):
198
200
  by.append(f)
199
201
  else:
200
- by.append(
201
- f"{f.lhs.name if self.__ispg else f.lhs.full_name} {f.op}"
202
- )
202
+ by.append(f"{f.lhs.name if self.__ispg else f.lhs.full_name} {f.op}")
203
203
  if self.__order_by__ is not None:
204
204
  by = self.__order_by__ + by
205
205
  self.__order_by__ = by
@@ -214,9 +214,8 @@ class Model(metaclass=ModelMetaclass):
214
214
  self.__group_by__ = by
215
215
  return self
216
216
 
217
- def _get_key_args(self, action, args):
217
+ def _format_data(self, action, args):
218
218
  data = dict()
219
- md = None
220
219
  if args is None or not args:
221
220
  for k in self.__fields__:
222
221
  f = getattr(self, k)
@@ -226,15 +225,19 @@ class Model(metaclass=ModelMetaclass):
226
225
  data = args
227
226
  else:
228
227
  for item in args:
229
- md = item
230
228
  if isinstance(item, Model):
231
229
  for k in item.__dict__:
232
- if (action == 'u' and item[k].value) or action == 'i':
230
+ if (action == "u" and item[k].value) or action == "i":
233
231
  data[k] = item[k]
234
232
 
235
233
  else: # for object
236
234
  for k, v in item.items():
237
235
  data[k] = v
236
+
237
+ return data
238
+
239
+ def _get_update_key_args(self, action, args):
240
+ data = self._format_data(action, args)
238
241
  keys = []
239
242
  params = []
240
243
  for k, v in data.items():
@@ -251,7 +254,48 @@ class Model(metaclass=ModelMetaclass):
251
254
  elif v is not None: # fix sql format %s
252
255
  keys.append("`%s`=?" % k)
253
256
  params.append(v)
254
- return ",".join(keys), params, md
257
+ return ",".join(keys), params
258
+
259
+ def _get_insert_key_args(self, action, args):
260
+ data = self._format_data(action, args)
261
+ keys = []
262
+ params = []
263
+ for k, v in data.items():
264
+ if isinstance(v, Field):
265
+ value = v.value
266
+ if value is None:
267
+ if v.created_generated == True or v.update_generated == True:
268
+ value = datetime.datetime.now()
269
+ else:
270
+ value = v.default
271
+ if value is not None:
272
+ keys.append(k)
273
+ params.append(value)
274
+ elif v is not None: # fix sql format %s
275
+ keys.append(k)
276
+ params.append(v)
277
+ return keys, params
278
+
279
+ def _get_batch_keys_values(self, items: list):
280
+ keys = []
281
+ values = []
282
+ item = items[0]
283
+ if isinstance(item, Model):
284
+ keys = item.__dict__.keys()
285
+ elif isinstance(item, dict):
286
+ keys = item.keys()
287
+
288
+ for item in items:
289
+ value = []
290
+ if isinstance(item, Model):
291
+ for k in item.__dict__:
292
+ value.append(item[k].value)
293
+ elif isinstance(item, dict): # for object
294
+ for k, v in item.items():
295
+ value.append(v)
296
+ value = tuple(key for key in value)
297
+ values.append(value)
298
+ return keys, values
255
299
 
256
300
  def _merge_params(self, p):
257
301
  if p is not None:
@@ -343,7 +387,7 @@ class Model(metaclass=ModelMetaclass):
343
387
  # where = self.__where__
344
388
  where = self._literal("WHERE", self.__where__)
345
389
 
346
- keys, params, md = self._get_key_args('u', args or kw)
390
+ keys, params = self._get_update_key_args("u", args or kw)
347
391
 
348
392
  sql = f"update `{table}` set {keys} {where}"
349
393
 
@@ -389,11 +433,21 @@ class Model(metaclass=ModelMetaclass):
389
433
 
390
434
  async def insert(self, *args, **kw):
391
435
  table = self.__table__
392
- keys, params, md = self._get_key_args('i', args or kw)
393
- sql = f"insert into `{table}` set {keys}"
436
+ keys, params = self._get_insert_key_args("i", args or kw)
437
+ sql = f"insert into `{table}` ({','.join(keys)}) values ({','.join(['?' for k in keys])})"
394
438
  self._reset()
439
+ params = tuple(key for key in params)
395
440
  return await self.__pool__.create(sql, params)
396
441
 
442
+ async def insert_batch(self, items: list):
443
+ table = self.__table__
444
+ if len(items) == 0:
445
+ return 0
446
+ keys, params = self._get_batch_keys_values(items)
447
+ sql = f"insert into `{table}` ({','.join(keys)}) values ({','.join(['?' for k in keys])})"
448
+ self._reset()
449
+ return await self.__pool__.create_batch(sql, params)
450
+
397
451
  async def count(self):
398
452
  __where__ = copy.copy(self.__where__)
399
453
  __join__ = copy.copy(self.__join__)
@@ -5,7 +5,8 @@ __author__ = "chuchur/chuchur.com"
5
5
 
6
6
  import hashlib, hmac, time, base64
7
7
  from curl_cffi import requests as http
8
- from ..logging import print_error,print_info
8
+ from ..logging import print_error, print_info
9
+
9
10
 
10
11
  class Client(object):
11
12
  def __init__(self, **kw):
@@ -253,7 +253,8 @@ def get_col_sql(field):
253
253
  if field.primary_key:
254
254
  sql += " PRIMARY KEY"
255
255
  if field.auto_increment:
256
- sql += " AUTO_INCREMENT"
256
+ # todo: postgres SERIAL
257
+ sql += " AUTO_INCREMENT"
257
258
  if field.NOT_NULL:
258
259
  sql += " NOT NULL"
259
260
  if field.default:
@@ -0,0 +1,86 @@
1
+
2
+ import time
3
+ import threading
4
+
5
+
6
+ """
7
+ 雪花算法(全局唯一id)
8
+
9
+ # 最早是Twitter公司在其内部用于分布式环境下生成唯一ID
10
+
11
+ # Twitter's Snowflake algorithm implementation which is used to generate distributed IDs.
12
+
13
+ # https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
14
+ """
15
+
16
+
17
+ class IdWorker:
18
+ def __init__(self, worker_id, datacenter_id, sequence=0):
19
+ # 位移值
20
+ self.worker_id_bits = 5
21
+ self.datacenter_id_bits = 5
22
+ self.sequence_bits = 12
23
+
24
+ self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
25
+ self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
26
+
27
+ # 参数校验
28
+ if worker_id > self.max_worker_id or worker_id < 0:
29
+ raise ValueError(f'worker_id must be between 0 and {self.max_worker_id}')
30
+ if datacenter_id > self.max_datacenter_id or datacenter_id < 0:
31
+ raise ValueError(f'datacenter_id must be between 0 and {self.max_datacenter_id}')
32
+
33
+ self.worker_id = worker_id
34
+ self.datacenter_id = datacenter_id
35
+ self.sequence = sequence
36
+ self.lock = threading.Lock()
37
+
38
+ # Twitter Epoch (2010-11-04 01:42:54 UTC)
39
+ self.twepoch = 1288834974657
40
+
41
+
42
+
43
+
44
+ self.worker_id_shift = self.sequence_bits
45
+ self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
46
+ self.timestamp_left_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
47
+ self.sequence_mask = -1 ^ (-1 << self.sequence_bits)
48
+
49
+ self.last_timestamp = -1
50
+
51
+ def _time_gen(self):
52
+ return int(time.time() * 1000)
53
+
54
+ def _til_next_millis(self, last_timestamp):
55
+ timestamp = self._time_gen()
56
+ while timestamp <= last_timestamp:
57
+ timestamp = self._time_gen()
58
+ return timestamp
59
+
60
+ def next_id(self):
61
+ with self.lock:
62
+ timestamp = self._time_gen()
63
+
64
+ if timestamp < self.last_timestamp:
65
+ raise Exception(f'Clock moved backwards. Refusing to generate id for {self.last_timestamp - timestamp} milliseconds')
66
+
67
+ if self.last_timestamp == timestamp:
68
+ self.sequence = (self.sequence + 1) & self.sequence_mask
69
+ if self.sequence == 0:
70
+ timestamp = self._til_next_millis(self.last_timestamp)
71
+ else:
72
+ self.sequence = 0
73
+
74
+ self.last_timestamp = timestamp
75
+
76
+ id = ((timestamp - self.twepoch) << self.timestamp_left_shift) | \
77
+ (self.datacenter_id << self.datacenter_id_shift) | \
78
+ (self.worker_id << self.worker_id_shift) | \
79
+ self.sequence
80
+
81
+ return id
82
+
83
+
84
+ # 示例使用
85
+ worker = IdWorker(worker_id=1, datacenter_id=1)
86
+ print(worker.next_id())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudoll
3
- Version: 2.2.23
3
+ Version: 2.2.24
4
4
  Summary: 辅助快速创建可分布的微服务。
5
5
  Home-page: https://gitee.com/chuchur/cloudoll-py
6
6
  Author: chuchur
@@ -31,6 +31,7 @@ cloudoll/utils/__init__.py
31
31
  cloudoll/utils/common.py
32
32
  cloudoll/utils/m2d.py
33
33
  cloudoll/utils/patch_loop.py
34
+ cloudoll/utils/snowflake.py
34
35
  cloudoll/utils/watch.py
35
36
  cloudoll/web/__init__.py
36
37
  cloudoll/web/exception.py
@@ -1 +0,0 @@
1
- __version__ = "2.2.23"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes