pycoze 0.1.446__py3-none-any.whl → 0.1.448__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.
pycoze/reference/lib.py CHANGED
@@ -9,6 +9,10 @@ import nest_asyncio
9
9
  nest_asyncio.apply()
10
10
 
11
11
  def call_func(func, args=None, kwargs=None):
12
+ """
13
+ args:是一个元组
14
+ kwargs:是一个字典
15
+ """
12
16
  if args is None:
13
17
  args = ()
14
18
  if kwargs is None:
pycoze/utils/__init__.py CHANGED
@@ -2,8 +2,12 @@ from .arg import read_arg
2
2
  from .env import read_params_file, params, read_json_file
3
3
  from .socket import TcpSocket, socket, socket_subscribe
4
4
  from .text_or_file import to_text
5
+ from .process import better_kill, execute_script, execute_script_and_block, execute_script_no_block
5
6
 
6
- __all__ = [read_arg,
7
- read_params_file, params, read_json_file,
8
- TcpSocket, socket, socket_subscribe,
9
- to_text]
7
+ __all__ = [
8
+ read_arg,
9
+ read_params_file, params, read_json_file,
10
+ TcpSocket, socket, socket_subscribe,
11
+ to_text,
12
+ better_kill, execute_script, execute_script_and_block, execute_script_no_block
13
+ ]
@@ -0,0 +1,133 @@
1
+ import asyncio
2
+ import os
3
+ import sys
4
+ import atexit
5
+ import time
6
+ import chardet
7
+
8
+
9
+ def better_kill(process, raiseError: bool):
10
+ """优雅地终止进程,如果超时则强制终止"""
11
+ try:
12
+ process.terminate() # 先尝试优雅终止
13
+ time.sleep(5) # 等待5秒
14
+ except asyncio.TimeoutError:
15
+ try:
16
+ process.kill() # 如果超时,强制终止
17
+ except:
18
+ if raiseError:
19
+ raise
20
+ else:
21
+ pass
22
+ except Exception as e:
23
+ # print(f"Error while terminating process: {e}")
24
+ if raiseError:
25
+ raise
26
+ else:
27
+ pass
28
+
29
+
30
+
31
+ async def read_stream(stream, log, separator=b'\n'):
32
+ def log_func(data):
33
+ try:
34
+ data = data.decode().strip()
35
+ log(data)
36
+ except:
37
+ try:
38
+ encoding = chardet.detect(data)['encoding']
39
+ data = data.decode(encoding).strip()
40
+ finally:
41
+ log(data)
42
+
43
+ while True:
44
+ try:
45
+ line = await stream.readuntil(separator)
46
+ log_func(line)
47
+ except asyncio.IncompleteReadError as e:
48
+ # If the stream ends without a separator, output the remaining content
49
+ if e.partial:
50
+ log_func(e.partial)
51
+ break
52
+ except asyncio.LimitOverrunError as e:
53
+ # If the separator is found but not within the limit, read the chunk
54
+ chunk = await stream.read(e.consumed)
55
+ log_func(chunk)
56
+
57
+
58
+
59
+
60
+ async def execute_script(script_path, *args, cwd=None, env=None):
61
+ cwd = cwd or os.path.dirname(script_path)
62
+ process = await asyncio.create_subprocess_exec(
63
+ sys.executable,
64
+ "-u",
65
+ script_path,
66
+ *args,
67
+ cwd=cwd,
68
+ env=env,
69
+ stdout=asyncio.subprocess.PIPE,
70
+ stderr=asyncio.subprocess.PIPE,
71
+ )
72
+ return process
73
+
74
+
75
+ async def execute_script_and_block(script_path, log, *args, cwd=None, env=None):
76
+ try:
77
+ # 执行脚本
78
+ process = await execute_script(script_path, *args, cwd=cwd, env=env)
79
+ except Exception as e:
80
+ better_kill(process, False)
81
+ raise Exception(f"Failed to execute script: {e}")
82
+
83
+ try:
84
+ # 开始并行读取 stdout 和 stderr
85
+ stdout_task = asyncio.create_task(read_stream(process.stdout, log))
86
+ stderr_task = asyncio.create_task(read_stream(process.stderr, log))
87
+
88
+ # 注册atexit处理程序
89
+ async def cleanup():
90
+ better_kill(process, False)
91
+ stdout_task.cancel()
92
+ stderr_task.cancel()
93
+ atexit.register(cleanup)
94
+
95
+ # 等待进程完成
96
+ return_code = await process.wait()
97
+
98
+ # 等待读取任务完成
99
+ await stdout_task
100
+ await stderr_task
101
+
102
+ except Exception as e:
103
+ better_kill(process, False)
104
+ stdout_task.cancel()
105
+ stderr_task.cancel()
106
+ raise Exception(f"Error during script execution or stream reading: {e}")
107
+
108
+ # 检查返回码
109
+ if return_code != 0:
110
+ better_kill(process, False)
111
+ raise Exception("Error executing script, return code: {}".format(return_code))
112
+
113
+ # 如果一切正常,返回成功
114
+ return "success"
115
+
116
+
117
+
118
+ async def execute_script_no_block(script_path, log, *args, cwd=None, env=None):
119
+ process = await execute_script(script_path, *args, cwd=cwd, env=env)
120
+
121
+ # Start reading stdout and stderr in parallel
122
+ stdout_task = asyncio.create_task(read_stream(process.stdout, log))
123
+ stderr_task = asyncio.create_task(read_stream(process.stderr, log))
124
+
125
+ # Register atexit handler to ensure process cleanup
126
+ def cleanup():
127
+ better_kill(process, False)
128
+ stdout_task.cancel()
129
+ stderr_task.cancel()
130
+
131
+ atexit.register(cleanup)
132
+
133
+ return process, stdout_task, stderr_task
pycoze/utils/socket.py CHANGED
@@ -12,7 +12,8 @@ class TcpSocket:
12
12
  self.is_connected = True
13
13
  self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14
14
  if params is not None:
15
- self.socket.connect(("localhost", int(params["tcpPort"])))
15
+ if "tcpPort" in params:
16
+ self.socket.connect(("localhost", int(params["tcpPort"])))
16
17
 
17
18
  def post(self, subject, message):
18
19
  subject = "python-event:" + subject
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pycoze
3
- Version: 0.1.446
3
+ Version: 0.1.448
4
4
  Summary: Package for pycoze only!
5
5
  Author: Yuan Jie Xiong
6
6
  Author-email: aiqqqqqqq@qq.com
@@ -19,7 +19,7 @@ pycoze/bot/tools.py,sha256=BWMdwvqLzvcyaW38lzxUWtc0K1V-C_qPSEZ3OKlAQvU,11108
19
19
  pycoze/reference/__init__.py,sha256=u25FWJnOBWsDRoL8_O4jzW4tkJrHT3Sqp9EGCxUhS3E,211
20
20
  pycoze/reference/bot.py,sha256=UZK24Qm8kpqpwXJy_zNZeTEEDee05luXdSBeUm0NCt0,2029
21
21
  pycoze/reference/fn.py,sha256=ZXnG2ctbHMgr3quQp-4bpnErIkuT-t2_ToSET5LTLbc,750
22
- pycoze/reference/lib.py,sha256=T-oBOKxkus5dTouc0oDgfRzUyi6aTyY-FF4yX7SzF5M,3755
22
+ pycoze/reference/lib.py,sha256=R-0T2QjxCUSF7K7XQtKaGm2n7uVptW4BnGu8s1QjMe0,3835
23
23
  pycoze/reference/tool.py,sha256=kv5Ww8fZVECNJfE7Ku5M88jqHgSO0yTF0S6eijQu9KE,1104
24
24
  pycoze/reference/workflow.py,sha256=59teXvIM_kOa-rJMLudJaJb9FBumYEmOzMT5jifKqDY,1337
25
25
  pycoze/ui/__init__.py,sha256=uaXet23wUk64TcZjpBX8qOx4aUhwA_ucrmcxy7Q4Qr4,929
@@ -27,13 +27,14 @@ pycoze/ui/base.py,sha256=7drlRZ40zF1nwGIRwLTC3EuZOSENz2qhQEWUM5yd9cg,1081
27
27
  pycoze/ui/color.py,sha256=cT9Ib8uNzkOKxyW0IwVj46o4LwdB1xgNCj1_Rou9d_4,854
28
28
  pycoze/ui/typ.py,sha256=NpT0FrbHvByOszBZMFtroRp7I7pN-38tYz_zPOPejF4,1723
29
29
  pycoze/ui/ui_def.py,sha256=lGWZGpzRoegP34D562PvK0EJHrmVZrlHW1JjsIG9A9Q,4521
30
- pycoze/utils/__init__.py,sha256=H-2KRUsUG47owL0sbD1KwDOuRm-j_0K4RkeNhzr7ISo,319
30
+ pycoze/utils/__init__.py,sha256=yj1LLPIRL7EhYuMzO1-NghW_6OMQgef3ofOeyLMksiA,488
31
31
  pycoze/utils/arg.py,sha256=jop1tBfe5hYkHW1NSpCeaZBEznkgguBscj_7M2dWfrs,503
32
32
  pycoze/utils/env.py,sha256=5pWlXfM1F5ZU9hhv1rHlDEanjEW5wf0nbyez9bNRqqA,559
33
- pycoze/utils/socket.py,sha256=bZbFFRH4mfThzRqt55BAAGQ6eICx_ja4x8UGGrUdAm8,2428
33
+ pycoze/utils/process.py,sha256=U2MURGmxfyWBqdbKfy5UvyV17M40B6HHlNELgWfgrTE,3824
34
+ pycoze/utils/socket.py,sha256=4Wm4LlwdWXC_kAV0NnZbUc0Y3Kc6KRMyFRqSw79u-9w,2468
34
35
  pycoze/utils/text_or_file.py,sha256=gpxZVWt2DW6YiEg_MnMuwg36VNf3TX383QD_1oZNB0Y,551
35
- pycoze-0.1.446.dist-info/LICENSE,sha256=QStd_Qsd0-kAam_-sOesCIp_uKrGWeoKwt9M49NVkNU,1090
36
- pycoze-0.1.446.dist-info/METADATA,sha256=UNb3t7Jo4EnpV95u0f7UDObcUMxJoOIUs0Oj-tdiGbM,854
37
- pycoze-0.1.446.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
38
- pycoze-0.1.446.dist-info/top_level.txt,sha256=76dPeDhKvOCleL3ZC5gl1-y4vdS1tT_U1hxWVAn7sFo,7
39
- pycoze-0.1.446.dist-info/RECORD,,
36
+ pycoze-0.1.448.dist-info/LICENSE,sha256=QStd_Qsd0-kAam_-sOesCIp_uKrGWeoKwt9M49NVkNU,1090
37
+ pycoze-0.1.448.dist-info/METADATA,sha256=pHNdV3nv2i-cfQkJhgLjtD4PYruxtsHYebtkKM-vSgI,854
38
+ pycoze-0.1.448.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
39
+ pycoze-0.1.448.dist-info/top_level.txt,sha256=76dPeDhKvOCleL3ZC5gl1-y4vdS1tT_U1hxWVAn7sFo,7
40
+ pycoze-0.1.448.dist-info/RECORD,,