gomyck-tools 1.4.1__py3-none-any.whl → 1.4.3__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.
Files changed (72) hide show
  1. ctools/__init__.py +21 -0
  2. ctools/ai/env_config.py +18 -1
  3. ctools/ai/llm_chat.py +8 -8
  4. ctools/ai/llm_client.py +26 -24
  5. ctools/ai/mcp/mcp_client.py +33 -17
  6. ctools/ai/tools/json_extract.py +3 -2
  7. ctools/ai/tools/quick_tools.py +71 -22
  8. ctools/ai/tools/tool_use_xml_parse.py +2 -1
  9. ctools/ai/tools/xml_extract.py +3 -0
  10. ctools/application.py +21 -19
  11. ctools/aspect.py +65 -0
  12. ctools/auto/browser_element.py +11 -3
  13. ctools/auto/plan_area.py +2 -2
  14. ctools/auto/pty_process.py +0 -1
  15. ctools/auto/screenshot.py +3 -4
  16. ctools/auto/win_canvas.py +10 -4
  17. ctools/auto/win_control.py +8 -4
  18. ctools/call.py +32 -47
  19. ctools/cdate.py +43 -2
  20. ctools/cid.py +6 -4
  21. ctools/cipher/aes_util.py +2 -2
  22. ctools/cipher/b64.py +2 -0
  23. ctools/cipher/czip.py +3 -1
  24. ctools/cipher/rsa.py +6 -1
  25. ctools/cipher/sign.py +1 -0
  26. ctools/cipher/sm_util.py +3 -0
  27. ctools/cjson.py +5 -0
  28. ctools/cron_lite.py +10 -4
  29. ctools/database/database.py +52 -22
  30. ctools/dict_wrapper.py +1 -0
  31. ctools/ex.py +4 -0
  32. ctools/geo/coord_trans.py +94 -94
  33. ctools/geo/douglas_rarefy.py +13 -9
  34. ctools/metrics.py +6 -0
  35. ctools/office/cword.py +7 -7
  36. ctools/office/word_fill.py +1 -4
  37. ctools/patch.py +88 -0
  38. ctools/path_info.py +29 -0
  39. ctools/pkg/__init__.py +4 -0
  40. ctools/pkg/dynamic_imp.py +38 -0
  41. ctools/pools/process_pool.py +6 -1
  42. ctools/pools/thread_pool.py +6 -2
  43. ctools/similar.py +3 -0
  44. ctools/stream/ckafka.py +11 -5
  45. ctools/stream/credis.py +37 -23
  46. ctools/stream/mqtt_utils.py +2 -2
  47. ctools/sys_info.py +8 -0
  48. ctools/sys_log.py +4 -1
  49. ctools/util/cftp.py +4 -2
  50. ctools/util/cklock.py +118 -0
  51. ctools/util/config_util.py +52 -0
  52. ctools/util/http_util.py +1 -0
  53. ctools/util/image_process.py +8 -0
  54. ctools/util/jb_cut.py +53 -0
  55. ctools/util/snow_id.py +3 -2
  56. ctools/web/__init__.py +2 -2
  57. ctools/web/aio_web_server.py +19 -9
  58. ctools/web/api_result.py +3 -2
  59. ctools/web/bottle_web_base.py +134 -70
  60. ctools/web/bottle_webserver.py +41 -35
  61. ctools/web/bottle_websocket.py +4 -0
  62. ctools/web/ctoken.py +81 -13
  63. ctools/web/download_util.py +1 -1
  64. ctools/web/params_util.py +4 -0
  65. ctools/web/upload_util.py +1 -1
  66. {gomyck_tools-1.4.1.dist-info → gomyck_tools-1.4.3.dist-info}/METADATA +9 -11
  67. gomyck_tools-1.4.3.dist-info/RECORD +88 -0
  68. ctools/auto/pacth.py +0 -74
  69. gomyck_tools-1.4.1.dist-info/RECORD +0 -82
  70. {gomyck_tools-1.4.1.dist-info → gomyck_tools-1.4.3.dist-info}/WHEEL +0 -0
  71. {gomyck_tools-1.4.1.dist-info → gomyck_tools-1.4.3.dist-info}/licenses/LICENSE +0 -0
  72. {gomyck_tools-1.4.1.dist-info → gomyck_tools-1.4.3.dist-info}/top_level.txt +0 -0
ctools/aspect.py ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ __author__ = 'haoyang'
4
+ __date__ = '2025/7/23 08:33'
5
+
6
+ import functools
7
+ import sys
8
+
9
+ from ctools.pools import thread_pool
10
+
11
+ def _ensure_list(funcs):
12
+ if callable(funcs):
13
+ return [funcs]
14
+ if isinstance(funcs, (list, tuple, set)):
15
+ return list(funcs)
16
+ raise TypeError("必须是可调用对象或可迭代对象")
17
+
18
+ def before(before_funcs):
19
+ """
20
+ 用于将无参函数注入目标函数的调用前
21
+ 支持多个函数
22
+ """
23
+ before_funcs = _ensure_list(before_funcs)
24
+ def decorator(func, sync=True):
25
+ @functools.wraps(func)
26
+ def wrapper(*args, **kwargs):
27
+ for bf in before_funcs:
28
+ if callable(bf):
29
+ if sync:
30
+ bf()
31
+ else:
32
+ thread_pool.submit(bf)
33
+ return func(*args, **kwargs)
34
+ _replace_func_binding(func, wrapper)
35
+ return wrapper
36
+ return decorator
37
+
38
+ def after(after_funcs, sync=True):
39
+ """
40
+ 用于将无参函数注入目标函数的调用后
41
+ 支持多个函数
42
+ """
43
+ after_funcs = _ensure_list(after_funcs)
44
+ def decorator(func):
45
+ @functools.wraps(func)
46
+ def wrapper(*args, **kwargs):
47
+ result = func(*args, **kwargs)
48
+ for af in after_funcs:
49
+ if callable(af):
50
+ if sync:
51
+ af()
52
+ else:
53
+ thread_pool.submit(af)
54
+ return result
55
+ _replace_func_binding(func, wrapper)
56
+ return wrapper
57
+ return decorator
58
+
59
+ def _replace_func_binding(old_func, new_func):
60
+ """
61
+ 替换函数在其模块中的绑定,确保所有使用点都生效
62
+ """
63
+ mod = sys.modules.get(old_func.__module__)
64
+ if mod and hasattr(mod, old_func.__name__):
65
+ setattr(mod, old_func.__name__, new_func)
@@ -23,6 +23,7 @@ g_result = []
23
23
  g_quite_flag = False
24
24
  picture_path = ""
25
25
 
26
+
26
27
  def get_hovered_element_html(url, explore, callback):
27
28
  global g_driver, g_callback, g_result
28
29
  g_callback = callback
@@ -73,10 +74,10 @@ def get_hovered_element_html(url, explore, callback):
73
74
  match_dom = page_dom_tree.xpath('//*[@ck-flag="ck"]')
74
75
  for ck_element in match_dom:
75
76
  ck_xpath = page_dom_tree.getpath(ck_element)
76
- #print('XPATH IS {}'.format(ck_xpath))
77
+ # print('XPATH IS {}'.format(ck_xpath))
77
78
  try:
78
79
  ele = driver.find_element(By.XPATH, ck_xpath)
79
- #print('XPATH_HTML: {}'.format(ele.get_attribute('outerHTML')))
80
+ # print('XPATH_HTML: {}'.format(ele.get_attribute('outerHTML')))
80
81
  except Exception:
81
82
  pass
82
83
  g_result.append(ck_xpath)
@@ -99,10 +100,12 @@ def get_hovered_element_html(url, explore, callback):
99
100
  except Exception as e:
100
101
  pass
101
102
 
103
+
102
104
  def break_func():
103
105
  keyboard_listener.stop()
104
106
  g_callback(None)
105
107
 
108
+
106
109
  def on_press(key):
107
110
  global keyboard_listener, ctrl_pressed, g_driver, g_quite_flag, picture_path
108
111
  if key == keyboard.Key.ctrl_l and not ctrl_pressed:
@@ -117,7 +120,7 @@ def on_press(key):
117
120
  if g_result:
118
121
  try:
119
122
  select_element = g_driver.find_element(By.XPATH, g_result[0])
120
- picture_path = "%s.png" % os.path.join(application.Server.screenshotPath, "element-"+cid.get_uuid())
123
+ picture_path = "%s.png" % os.path.join(application.Server.screenshotPath, "element-" + cid.get_uuid())
121
124
  select_element.screenshot(picture_path)
122
125
  except Exception:
123
126
  pass
@@ -126,11 +129,13 @@ def on_press(key):
126
129
  g_quite_flag = True
127
130
  g_callback(g_result)
128
131
 
132
+
129
133
  def on_release(key):
130
134
  global ctrl_pressed
131
135
  if key == keyboard.Key.ctrl_l:
132
136
  ctrl_pressed = False
133
137
 
138
+
134
139
  def start_keyboard_listener():
135
140
  global keyboard_listener
136
141
  keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)
@@ -183,6 +188,7 @@ if (shade) {
183
188
  }
184
189
  """
185
190
 
191
+
186
192
  class IE:
187
193
 
188
194
  @staticmethod
@@ -287,6 +293,7 @@ class Chrome:
287
293
  def callback(xpath):
288
294
  print("Hovered Element XPATH IS :", xpath)
289
295
 
296
+
290
297
  def get_element(url: str = None, explore: str = "chrome"):
291
298
  global keyboard_listener, ctrl_pressed, g_driver, g_callback, g_result, g_quite_flag, picture_path
292
299
  keyboard_listener = None
@@ -309,6 +316,7 @@ def get_element(url: str = None, explore: str = "chrome"):
309
316
 
310
317
  return g_result, picture_path
311
318
 
319
+
312
320
  if __name__ == "__main__":
313
321
  # from explore_record_core import get_hovered_element_html, Chrome
314
322
  g_result, picture_path = get_element("weibo.com")
ctools/auto/plan_area.py CHANGED
@@ -63,8 +63,8 @@ class PlanAreaTools:
63
63
 
64
64
  def mouse_left_move(self, event):
65
65
  self.x, self.y = event.x, event.y
66
- self.xcenter = self.xstart + int((self.x-self.xstart)/2)-2
67
- self.ycenter = self.ystart + int((self.y-self.ystart)/2)-2
66
+ self.xcenter = self.xstart + int((self.x - self.xstart) / 2) - 2
67
+ self.ycenter = self.ystart + int((self.y - self.ystart) / 2) - 2
68
68
 
69
69
  self.pos_label.config(text=self.pos_div_text % (self.x, self.y))
70
70
  self.pos_div.geometry(f"+{self.x + 10}+{self.y + 10}")
@@ -70,4 +70,3 @@ class PtyTools:
70
70
 
71
71
  def close(self):
72
72
  self._process.close(force=True)
73
-
ctools/auto/screenshot.py CHANGED
@@ -65,7 +65,7 @@ class ScreenshotTools:
65
65
  def change_center_point(self, event):
66
66
  offset_x = event.x + self.xstart - self.xcenter - 2
67
67
  offset_y = event.y + self.ystart - self.ycenter - 2
68
- self.center_div.geometry(f"+{self.xstart+event.x-2}+{self.ystart+event.y-2}")
68
+ self.center_div.geometry(f"+{self.xstart + event.x - 2}+{self.ystart + event.y - 2}")
69
69
  self.center_offset = (offset_x, offset_y)
70
70
 
71
71
  def mouse_left_down(self, event):
@@ -86,8 +86,8 @@ class ScreenshotTools:
86
86
 
87
87
  def mouse_left_move(self, event):
88
88
  self.x, self.y = event.x, event.y
89
- self.xcenter = self.xstart + int((self.x-self.xstart)/2)-2
90
- self.ycenter = self.ystart + int((self.y-self.ystart)/2)-2
89
+ self.xcenter = self.xstart + int((self.x - self.xstart) / 2) - 2
90
+ self.ycenter = self.ystart + int((self.y - self.ystart) / 2) - 2
91
91
 
92
92
  self.pos_label.config(text=self.pos_div_text % (self.x, self.y))
93
93
  self.pos_div.geometry(f"+{self.x + 10}+{self.y + 10}")
@@ -125,4 +125,3 @@ def screenshot():
125
125
  st = ScreenshotTools()
126
126
  st.start()
127
127
  return st.screenshot_path, st.center_offset
128
-
ctools/auto/win_canvas.py CHANGED
@@ -4,12 +4,14 @@ from multiprocessing import Process, Queue
4
4
  data_queue: Queue = None
5
5
  canvas_process: Process = None
6
6
 
7
+
7
8
  class MSGType:
8
- BOTTOM = 'bottom' #置于底部
9
- DRAW = 'draw' #绘制矩形
9
+ BOTTOM = 'bottom' # 置于底部
10
+ DRAW = 'draw' # 绘制矩形
11
+
10
12
 
11
13
  class CanvasInfo:
12
- def __init__(self,title: str='', points: list=None, msg_type: MSGType=MSGType.DRAW):
14
+ def __init__(self, title: str = '', points: list = None, msg_type: MSGType = MSGType.DRAW):
13
15
  self.msg_type = msg_type
14
16
  # 标题
15
17
  self.title = title
@@ -17,9 +19,11 @@ class CanvasInfo:
17
19
  # [(100, 100), (200, 100), (200, 150), (100, 150)]
18
20
  self.points = points
19
21
 
22
+
20
23
  def on_ctrl_click(event):
21
24
  print("Ctrl+Left Click detected")
22
25
 
26
+
23
27
  class RecorderTool(tk.Tk):
24
28
  def __init__(self, data: Queue):
25
29
  super().__init__()
@@ -65,10 +69,12 @@ class RecorderTool(tk.Tk):
65
69
  self.draw_red_border(canvas_info)
66
70
  self.after(10, self.check_queue)
67
71
 
72
+
68
73
  def _init_recorder(data):
69
74
  canvas_app = RecorderTool(data)
70
75
  canvas_app.mainloop()
71
76
 
77
+
72
78
  def start():
73
79
  global data_queue, canvas_process
74
80
  data_queue = Queue()
@@ -76,8 +82,8 @@ def start():
76
82
  canvas_process.start()
77
83
  return canvas_process
78
84
 
85
+
79
86
  def stop():
80
87
  canvas_process.terminate()
81
88
  canvas_process.join()
82
89
  data_queue.close()
83
-
@@ -6,9 +6,9 @@ import uiautomation as auto
6
6
  from pynput import keyboard
7
7
 
8
8
  from ctools import application
9
+ from ctools import cid
9
10
  from ctools.auto import win_canvas
10
11
  from ctools.pools import thread_pool
11
- from ctools import cid
12
12
 
13
13
  current_control = None
14
14
  ctrl_pressed = False
@@ -16,13 +16,14 @@ keyboard_listener = None
16
16
  control_json = {}
17
17
  screenshot_path = ""
18
18
 
19
+
19
20
  class ControlInfo:
20
21
  def __init__(self, ControlType, ClassName, AutomationId, Name, Depth):
21
22
  self.ControlType = ControlType
22
23
  self.ClassName = ClassName
23
24
  self.AutomationId = AutomationId
24
25
  self.Name = Name
25
- #self.Depth = Depth
26
+ # self.Depth = Depth
26
27
 
27
28
 
28
29
  def get_control_from_cursor():
@@ -36,10 +37,10 @@ def get_control_from_cursor():
36
37
  print("No control found {}".format(e))
37
38
  return
38
39
  if control:
39
- #当前控件信息
40
+ # 当前控件信息
40
41
  global current_control
41
42
  current_control = control
42
- #绘制矩形
43
+ # 绘制矩形
43
44
  canvas_info = win_canvas.CanvasInfo(control.Name, [
44
45
  (control.BoundingRectangle.left, control.BoundingRectangle.top),
45
46
  (control.BoundingRectangle.right, control.BoundingRectangle.top),
@@ -65,6 +66,7 @@ def get_control_from_cursor():
65
66
  # time.sleep(2)
66
67
  # xx.Click()
67
68
 
69
+
68
70
  def on_press(key):
69
71
  global ctrl_pressed, keyboard_listener
70
72
  if key == keyboard.Key.ctrl_l and not ctrl_pressed:
@@ -78,6 +80,7 @@ def on_press(key):
78
80
  keyboard_listener.stop()
79
81
  # pg.alert('采集成功!')
80
82
 
83
+
81
84
  def on_release(key):
82
85
  global ctrl_pressed
83
86
  if key == keyboard.Key.ctrl_l:
@@ -104,6 +107,7 @@ def get_control_json():
104
107
  time.sleep(0.5)
105
108
  return control_json, screenshot_path
106
109
 
110
+
107
111
  if __name__ == '__main__':
108
112
  a = get_control_json()
109
113
  print(a)
ctools/call.py CHANGED
@@ -1,71 +1,56 @@
1
+ import os
1
2
  import sched
2
3
  import threading
3
4
  import time
4
5
  from functools import wraps
5
6
 
7
+
6
8
  # annotation
9
+ _global_once_cache = {}
7
10
  def once(func):
8
- """
9
- decorator to initialize a function once
10
- :param func: function to be initialized
11
- :return: the real decorator for return the result
12
- """
13
- initialized = False
14
- res = None
15
-
11
+ code = func.__code__
12
+ key = f"{os.path.abspath(code.co_filename)}:{code.co_firstlineno}"
16
13
  def wrapper(*args, **kwargs):
17
- nonlocal initialized, res
18
- if not initialized:
19
- res = func(*args, **kwargs)
20
- initialized = True
21
- return res
22
- else:
23
- return res
24
-
14
+ if key not in _global_once_cache:
15
+ _global_once_cache[key] = func(*args, **kwargs)
16
+ return _global_once_cache[key]
25
17
  return wrapper
26
18
 
27
19
  # annotation
20
+ _cache = {}
28
21
  def init(func):
29
- """
30
- decorator to initialize a function automic
31
- :param func: function to be initialized
32
- :return: the real decorator for return the result
33
- """
34
- res = func()
35
-
22
+ code = func.__code__
23
+ key = f"{os.path.abspath(code.co_filename)}:{code.co_firstlineno}"
24
+ if key not in _cache:
25
+ _cache[key] = func()
36
26
  def wrapper():
37
- return res
38
-
27
+ return _cache[key]
39
28
  return wrapper
40
29
 
41
30
  # annotation
42
- def schd(interval_seconds, start_by_call: bool = False):
43
- start_flag = False
44
- run_flag = False
45
- scheduler = sched.scheduler(time.time, time.sleep)
46
-
31
+ _scheduler_cache = {}
32
+ def schd(interval_seconds, start_by_call=False, run_now=False):
47
33
  def decorator(func):
34
+ key = f"{os.path.abspath(func.__code__.co_filename)}:{func.__code__.co_firstlineno}"
35
+ lock = threading.Lock()
48
36
  @wraps(func)
49
37
  def wrapper(*args, **kwargs):
50
- nonlocal start_flag
51
- if start_by_call and not start_flag:
52
- start_flag = True
53
- threading.Thread(target=wrapper, args=args, kwargs=kwargs, daemon=True).start()
54
- return
55
-
38
+ if key in _scheduler_cache:
39
+ return # 已经调度过
40
+ scheduler = sched.scheduler(time.time, time.sleep)
56
41
  def job():
57
42
  func(*args, **kwargs)
58
43
  scheduler.enter(interval_seconds, 1, job)
59
-
60
- nonlocal run_flag
61
- if not run_flag:
62
- scheduler.enter(interval_seconds, 1, job)
63
- run_flag = True
64
- scheduler.run()
65
- else:
66
- func(*args, **kwargs)
67
-
68
- if not start_by_call: threading.Thread(target=wrapper, daemon=True).start()
44
+ def start_scheduler():
45
+ with lock:
46
+ if _scheduler_cache.get(key): return
47
+ _scheduler_cache[key] = True
48
+ if run_now:
49
+ func(*args, **kwargs)
50
+ scheduler.enter(interval_seconds, 1, job)
51
+ scheduler.run()
52
+ threading.Thread(target=start_scheduler, daemon=True).start()
53
+ if not start_by_call:
54
+ wrapper()
69
55
  return wrapper
70
-
71
56
  return decorator
ctools/cdate.py CHANGED
@@ -1,39 +1,52 @@
1
1
  import time
2
2
  from datetime import datetime, timedelta
3
3
 
4
+ def get_month(date: str=None):
5
+ if date: return time.strftime('%Y-%m', time.strptime(date, '%Y-%m-%d'))
6
+ return time.strftime('%Y-%m', time.localtime(time.time()))
7
+
4
8
  def get_date():
5
9
  return time.strftime('%Y-%m-%d', time.localtime(time.time()))
6
10
 
11
+
7
12
  def get_time():
8
13
  return time.strftime('%H-%M-%S', time.localtime(time.time()))
9
14
 
15
+
10
16
  def get_date_time(fmt="%Y-%m-%d %H:%M:%S"):
11
17
  return time.strftime(fmt, time.localtime(time.time()))
12
18
 
19
+
13
20
  def str_to_datetime(val: str, fmt="%Y-%m-%d %H:%M:%S"):
14
21
  return time.strptime(val, fmt)
15
22
 
23
+
16
24
  def str_to_timestamp(val: str, fmt="%Y-%m-%d %H:%M:%S"):
17
25
  return time.mktime(time.strptime(val, fmt))
18
26
 
19
- def timestamp_to_str(timestamp: int=time.time(), fmt="%Y-%m-%d %H:%M:%S"):
27
+
28
+ def timestamp_to_str(timestamp: int = time.time(), fmt="%Y-%m-%d %H:%M:%S"):
20
29
  return time.strftime(fmt, time.localtime(timestamp))
21
30
 
31
+
22
32
  def get_today_start_end(now: datetime.now()):
23
33
  start = datetime(now.year, now.month, now.day, 0, 0, 0)
24
34
  end = datetime(now.year, now.month, now.day, 23, 59, 59)
25
35
  return start.strftime("%Y-%m-%d %H:%M:%S"), end.strftime("%Y-%m-%d %H:%M:%S")
26
36
 
37
+
27
38
  def get_week_start_end(now: datetime.now()):
28
39
  start = now - timedelta(days=now.weekday()) # 本周一
29
40
  end = start + timedelta(days=6) # 本周日
30
41
  return start.strftime("%Y-%m-%d 00:00:00"), end.strftime("%Y-%m-%d 23:59:59")
31
42
 
32
- def time_diff_in_seconds(sub_head: str=get_date_time(), sub_end: str=get_date_time()):
43
+
44
+ def time_diff_in_seconds(sub_head: str = get_date_time(), sub_end: str = get_date_time()):
33
45
  start_ts = str_to_timestamp(sub_head)
34
46
  end_ts = str_to_timestamp(sub_end)
35
47
  return int(start_ts - end_ts)
36
48
 
49
+
37
50
  def opt_time(base_time=None, days=0, hours=0, minutes=0, seconds=0, weeks=0, fmt="%Y-%m-%d %H:%M:%S"):
38
51
  if base_time is None:
39
52
  base_time = datetime.now()
@@ -41,3 +54,31 @@ def opt_time(base_time=None, days=0, hours=0, minutes=0, seconds=0, weeks=0, fmt
41
54
  base_time = datetime.strptime(base_time, fmt)
42
55
  new_time = base_time + timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds, weeks=weeks)
43
56
  return new_time.strftime(fmt)
57
+
58
+ def get_years_range(start_year: str, end_year: str=datetime.now().strftime("%Y")) -> set[int]:
59
+ if int(start_year) > int(end_year):
60
+ raise ValueError("起始年份不能大于结束年份")
61
+ return list(range(int(start_year), int(end_year) + 1))
62
+
63
+ def get_month_range(start: str, end: str=datetime.now().strftime("%Y-%m")) -> set[str]:
64
+ start_date = datetime.strptime(start, "%Y-%m")
65
+ end_date = datetime.strptime(end, "%Y-%m")
66
+ if start_date > end_date:
67
+ raise ValueError("起始月份不能晚于结束月份")
68
+ result = []
69
+ current = start_date
70
+ while current <= end_date:
71
+ result.append(current.strftime("%Y-%m"))
72
+ if current.month == 12:
73
+ current = current.replace(year=current.year + 1, month=1)
74
+ else:
75
+ current = current.replace(month=current.month + 1)
76
+ return result
77
+
78
+ def get_day_range(start: str, end: str=datetime.now().strftime("%Y-%m-%d")) -> set[str]:
79
+ start_date = datetime.strptime(start, "%Y-%m-%d")
80
+ end_date = datetime.strptime(end, "%Y-%m-%d")
81
+ if start_date > end_date:
82
+ raise ValueError("起始日期不能晚于结束日期")
83
+ delta = end_date - start_date
84
+ return [(start_date + timedelta(days=i)).strftime("%Y-%m-%d") for i in range(delta.days + 1)]
ctools/cid.py CHANGED
@@ -2,17 +2,19 @@ from ctools.util.snow_id import SnowId
2
2
 
3
3
  idWorker = SnowId(1, 2, 0)
4
4
 
5
+
5
6
  def get_snowflake_id():
6
7
  return idWorker.get_id()
7
8
 
9
+
10
+ def get_snowflake_id_str():
11
+ return str(get_snowflake_id())
12
+
8
13
  def get_random_str(size: int = 10) -> str:
9
14
  import random
10
15
  return "".join(random.sample('abcdefghjklmnpqrstuvwxyz123456789', size))
11
16
 
17
+
12
18
  def get_uuid() -> str:
13
19
  import uuid
14
20
  return str(uuid.uuid1()).replace("-", "")
15
-
16
-
17
-
18
-
ctools/cipher/aes_util.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from cryptography.fernet import Fernet
2
2
 
3
+
3
4
  def generate_key():
4
5
  """
5
6
  生成 AES key
@@ -9,6 +10,7 @@ def generate_key():
9
10
  key = Fernet.generate_key()
10
11
  return key.decode()
11
12
 
13
+
12
14
  def aes_encrypt(sec_key, plaintext):
13
15
  """
14
16
  aes加密
@@ -31,5 +33,3 @@ def aes_decrypt(sec_key, ciphertext):
31
33
  cipher = Fernet(sec_key)
32
34
  decrypted_data = cipher.decrypt(ciphertext)
33
35
  return decrypted_data.decode()
34
-
35
-
ctools/cipher/b64.py CHANGED
@@ -1,7 +1,9 @@
1
1
  import base64
2
2
 
3
+
3
4
  def encode(param: str):
4
5
  return base64.b64encode(param.encode('UTF-8')).decode('UTF-8')
5
6
 
7
+
6
8
  def decode(param: str):
7
9
  return base64.b64decode(param.encode('UTF-8')).decode('UTF-8')
ctools/cipher/czip.py CHANGED
@@ -22,6 +22,8 @@ import pyzipper
22
22
  output_directory = '/Users/haoyang/Desktop'
23
23
  compress_specific_files(files_to_compress, output_directory, zip_password, "my_files")
24
24
  """
25
+
26
+
25
27
  def create_zip_with_files(file_dict, password=None) -> io.BytesIO:
26
28
  """Compress multiple files into a single password-protected ZIP archive in memory.
27
29
  Args:
@@ -87,7 +89,7 @@ def process_directory_to_single_zip(root_dir, password=None, zip_name=None):
87
89
  if 'zip_buffer' in locals(): zip_buffer.close()
88
90
 
89
91
 
90
- def compress_specific_files(file_paths:[], output_dir:str, password=None, zip_name=None):
92
+ def compress_specific_files(file_paths: [], output_dir: str, password=None, zip_name=None):
91
93
  """Compress multiple specified files into a single ZIP archive.
92
94
  Args:
93
95
  file_paths: List of absolute file paths to compress
ctools/cipher/rsa.py CHANGED
@@ -10,6 +10,7 @@ from ctools import cjson, path_info
10
10
  ENCRYPT_CHUNK_SIZE = 245
11
11
  decrypt_CHUNK_SIZE = 512
12
12
 
13
+
13
14
  def generate_rsa_keypair(bits=2048):
14
15
  key = RSA.generate(bits)
15
16
  private_key = key.export_key() # 导出私钥
@@ -19,11 +20,13 @@ def generate_rsa_keypair(bits=2048):
19
20
  with open("public_key.pem", "wb") as f:
20
21
  f.write(public_key)
21
22
 
23
+
22
24
  def loadLicenseInfo(auth_code):
23
25
  with open(path_info.get_app_path() + '/keys/license.key', 'r') as pri:
24
26
  decrypt_message = decrypt(auth_code.strip(), pri.read())
25
27
  return cjson.loads(decrypt_message)
26
28
 
29
+
27
30
  # 加密函数
28
31
  def encrypt(msg, public_key):
29
32
  parts = b''
@@ -34,6 +37,7 @@ def encrypt(msg, public_key):
34
37
  encrypted_base64 = base64.b64encode(parts)
35
38
  return encrypted_base64.decode()
36
39
 
40
+
37
41
  # 解密函数
38
42
  def decrypt(msg, private_key):
39
43
  parts = b''
@@ -44,6 +48,7 @@ def decrypt(msg, private_key):
44
48
  parts += cipher.decrypt(encrypted_bytes[i:i + decrypt_CHUNK_SIZE])
45
49
  return parts.decode()
46
50
 
51
+
47
52
  # 验签
48
53
  def verify_sign(msg, public_key, sign):
49
54
  public_key = RSA.import_key(public_key)
@@ -55,6 +60,7 @@ def verify_sign(msg, public_key, sign):
55
60
  print('签名验证失败: {}'.format(e))
56
61
  return False
57
62
 
63
+
58
64
  # 签名
59
65
  def sign_msg(msg, private_key):
60
66
  private_key = RSA.import_key(private_key)
@@ -62,7 +68,6 @@ def sign_msg(msg, private_key):
62
68
  signature = pkcs1_15.new(private_key).sign(hash_message)
63
69
  return base64.b64encode(signature).decode()
64
70
 
65
-
66
71
  # with open(work_path.get_current_path() + '/private_key.pem', 'r') as key:
67
72
  # key = key.read()
68
73
  # sign = sign_msg(key, key)
ctools/cipher/sign.py CHANGED
@@ -14,6 +14,7 @@ def generate_signature(file_path, key: str = global_key):
14
14
  except:
15
15
  return ''
16
16
 
17
+
17
18
  def digest(value: str, key: str = global_key):
18
19
  val_hash = hashlib.sha256(value.encode()).digest()
19
20
  sign_val = hmac.new(key.encode(), val_hash, hashlib.sha256).digest()
ctools/cipher/sm_util.py CHANGED
@@ -5,6 +5,7 @@ from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
5
5
 
6
6
  sm2_crypt: sm2.CryptSM2 = None
7
7
 
8
+
8
9
  def init(private_key: str, public_key: str):
9
10
  global sm2_crypt
10
11
  if sm2_crypt is not None:
@@ -12,6 +13,7 @@ def init(private_key: str, public_key: str):
12
13
  return
13
14
  sm2_crypt = sm2.CryptSM2(private_key=private_key, public_key=public_key, asn1=True, mode=1)
14
15
 
16
+
15
17
  def sign_with_sm2(sign_data: str) -> str:
16
18
  if sm2_crypt is None: raise Exception('sm2 is not init!!!')
17
19
  return sm2_crypt.sign_with_sm3(sign_data.encode('UTF-8'))
@@ -25,6 +27,7 @@ def verify_with_sm2(sign_val: str, sign_data: str) -> bool:
25
27
  print('签名验证失败: {}'.format(e))
26
28
  return False
27
29
 
30
+
28
31
  def encrypt_with_sm2(encrypt_data: str) -> str:
29
32
  if sm2_crypt is None: raise Exception('sm2 is not init!!!')
30
33
  return base64.b64encode(sm2_crypt.encrypt(encrypt_data.encode('UTF-8'))).decode('UTF-8')