ygo 1.0.2__py3-none-any.whl → 1.2.12__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.
ygo/ygo.py DELETED
@@ -1,372 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- ---------------------------------------------
4
- Created on 2024/11/4 下午2:10
5
- @author: ZhangYundi
6
- @email: yundi.xxii@outlook.com
7
- ---------------------------------------------
8
- """
9
- import functools
10
- import importlib
11
- import inspect
12
- import multiprocessing
13
- import os
14
- import threading
15
- import warnings
16
- from pathlib import Path
17
-
18
- from joblib import Parallel, delayed
19
-
20
- import ylog
21
- from .exceptions import WarnException
22
-
23
- with warnings.catch_warnings():
24
- warnings.simplefilter("ignore")
25
- from tqdm.auto import tqdm
26
-
27
-
28
- class DelayedFunction:
29
-
30
- def __init__(self, func):
31
- self.func = func
32
- self._fn_params_k = inspect.signature(self.func).parameters.keys()
33
- self.stored_kwargs = self._get_default_args(func)
34
- if hasattr(func, 'stored_kwargs'):
35
- self.stored_kwargs.update(func.stored_kwargs)
36
-
37
- def _get_default_args(self, func):
38
- signature = inspect.signature(func)
39
- return {
40
- k: v.default
41
- for k, v in signature.parameters.items()
42
- if v.default is not inspect.Parameter.empty
43
- }
44
-
45
- def __call__(self, *args, **kwargs):
46
- def delayed(*args, **_kwargs):
47
- new_kwargs = {k: v for k, v in self.stored_kwargs.items()}
48
- for k, v in _kwargs.items():
49
- if k not in self._fn_params_k:
50
- continue
51
- new_kwargs[k] = v
52
- return self.func(*args, **new_kwargs)
53
-
54
- self._stored_kwargs(**kwargs)
55
- new_fn = functools.wraps(self.func)(delayed)
56
- new_fn.stored_kwargs = self.stored_kwargs
57
- return new_fn
58
-
59
- def _stored_kwargs(self, **kwargs):
60
- for k, v in kwargs.items():
61
- if k not in self._fn_params_k:
62
- continue
63
- self.stored_kwargs[k] = v
64
-
65
-
66
- def delay(func):
67
- """
68
- 延迟执行
69
- Parameters
70
- ----------
71
- func: Callable
72
- 需要延迟执行的对象, 必须是一个Callable对象
73
-
74
- Returns
75
- -------
76
- DelayedFunction
77
- 将预先设置好的参数包装进原始的Callable对象中
78
-
79
- Examples
80
- --------
81
-
82
- 场景1:基本使用
83
-
84
- >>> fn = delay(lambda a, b: a+b)(a=1, b=2)
85
- >>> fn()
86
- 3
87
-
88
- 场景2: 逐步传递参数
89
-
90
- >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
91
- >>> fn2 = delay(fn1)(b=2)
92
- >>> fn2(c=3)
93
- 6
94
-
95
- 场景3: 参数更改
96
-
97
- >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
98
- >>> fn2 = delay(fn1)(c=3, b=5)
99
- >>> fn2()
100
- 9
101
- """
102
- return DelayedFunction(func)
103
-
104
-
105
- def fn_params(func: callable):
106
- """
107
- 获取fn的参数
108
- Parameters
109
- ----------
110
- func: callable
111
- 需要获取参数的callable对象
112
- Returns
113
- -------
114
- list[tuple]
115
-
116
- """
117
- # signatured = sorted(list(inspect.signature(func).parameters.keys()))
118
- # stored = delay(func)().stored_kwargs
119
- # return [(param, stored.get(param)) for param in signatured]
120
- stored = delay(func)().stored_kwargs.items()
121
- return sorted(stored)
122
-
123
- def fn_signature_params(func: callable):
124
- """获取fn所有定义的参数"""
125
- return sorted(list(inspect.signature(func).parameters.keys()))
126
-
127
- def fn_path(fn: callable) -> str:
128
- """
129
- 获取func所在的模块层级结构
130
- Parameters
131
- ----------
132
- fn: callable
133
- 需要获取结构的callable对象
134
- Returns
135
- -------
136
- str
137
- 用 `.` 连接各级层级
138
- """
139
- module = fn.__module__
140
- # 检查模块是否有 __file__ 属性
141
- if module.startswith('__main__'):
142
- if hasattr(module, '__file__'):
143
- module = module.__file__
144
- else:
145
- # 如果在交互式环境中,返回 None 或者一个默认值
146
- module = "<interactive environment>"
147
- if module.endswith('.py'):
148
- module = module.split('.py')[0].split(str(Path(__file__).parent.parent.absolute()))[-1]
149
- module = '.'.join(module.strip(os.sep).split(os.sep))
150
- return module
151
-
152
-
153
- def fn_code(fn: callable) -> str:
154
- """
155
- 返回fn具体的定义代码
156
-
157
- Parameters
158
- ----------
159
- fn: callable
160
- 需要获取具体定义代码的callable对象
161
-
162
- Returns
163
- -------
164
- str
165
- 以字符串封装定义代码
166
-
167
- Examples
168
- --------
169
-
170
- >>> def test_fn(a, b=2):
171
- >>> return a+b
172
- >>> print(fn_code())
173
- def test_fn(a, b=2):
174
- return a+b
175
- """
176
- return inspect.getsource(fn)
177
-
178
-
179
- def fn_info(fn: callable) -> str:
180
- """获取函数的fn_mod, params, code"""
181
- # mod = fn_path(fn)
182
- params = fn_params(fn)
183
- code = fn_code(fn)
184
- all_define_params = sorted(list(inspect.signature(fn).parameters.keys()))
185
-
186
- default_params = {k: v for k, v in params}
187
- params_infos = list()
188
- for p in all_define_params:
189
- if p in default_params:
190
- params_infos.append(f'{p}={default_params[p]}')
191
- else:
192
- params_infos.append(p)
193
- params_infos = ', '.join(params_infos)
194
-
195
- s = f"""
196
- =============================================================
197
- {fn.__name__}({params_infos})
198
- =============================================================
199
- {code}
200
- """
201
- return s
202
-
203
-
204
- def fn_from_str(s):
205
- """
206
- 字符串导入对应fn
207
- s: a.b.c.func
208
- Parameters
209
- ----------
210
- s: str
211
- 模块的路径,分隔符 `.`
212
- """
213
- *m_path, func = s.split(".")
214
- m_path = ".".join(m_path)
215
- mod = importlib.import_module(m_path)
216
- _callable = getattr(mod, func)
217
- return _callable
218
-
219
-
220
- def module_from_str(s):
221
- """字符串导入模块"""
222
- m_path = ".".join(s.split('.'))
223
- mod = importlib.import_module(m_path)
224
- return mod
225
-
226
- def run_job(job, task_id, queue):
227
- """执行任务并更新队列"""
228
- try:
229
- result = job()
230
- except WarnException as e:
231
- warn_msg = f"""
232
- =============================================================
233
- {job.task_name}: {job.task_id}
234
- {e}
235
- =============================================================
236
- """
237
- ylog.warning(warn_msg)
238
- result = None
239
- except Exception as e:
240
- error_msg = f"""
241
- =============================================================
242
- {job.task_name}: {job.task_id}
243
- {e}
244
- =============================================================
245
- """
246
- ylog.error(error_msg)
247
- result = None
248
- queue.put((task_id, 1))
249
- return result
250
-
251
-
252
- def update_progress_bars(tqdm_objects: list[tqdm],
253
- task_ids,
254
- queue: multiprocessing.Queue,
255
- num_tasks: int,
256
- task_counts: dict):
257
- """根据队列中的消息更新 tqdm 进度条"""
258
- completed_tasks = 0
259
- completed_task_jobs = {id_: 0 for id_ in task_ids}
260
- while completed_tasks < num_tasks:
261
- task_id, progress_value = queue.get() # 从队列获取进度更新
262
- completed_task_jobs[task_id] += 1
263
- if completed_task_jobs[task_id] >= task_counts[task_id]:
264
- completed_tasks += 1
265
- tqdm_objects[task_id].update(progress_value)
266
- [tqdm_object.close() for tqdm_object in tqdm_objects]
267
-
268
-
269
- class pool:
270
- """
271
- 每个fn运行一次算一个job,每个job需要指定job_name, 如果没有job_name, 则默认分配 TaskDefault
272
- 相同 job_name 的fn归到同一个task, 同时该task命名为job_name
273
- 即一个task中包含了多个需要运行的 job fn
274
- task1 <job_fn1, job_fn2, ...>
275
- task2 <job_fn3, job_fn4, ...>
276
- 所有的job_fn都会通过joblib并行运行
277
- """
278
-
279
- def __init__(self, n_jobs=5, show_progress=True, backend='loky', ):
280
- """backend: loky/threading/multiprocessing"""
281
- self.show_progress = show_progress
282
- self._n_jobs = n_jobs
283
- self._parallel = Parallel(n_jobs=self._n_jobs, verbose=0, backend=backend) if self._n_jobs > 0 else None
284
- self._default_task_name = "TaskDefault"
285
- self._all_jobs = list() # list[job]
286
- self._all_tasks = list() # list[task_name]
287
- self._task_ids = dict() # {task_name1: 0, task_name2: 1, ...}
288
- self._task_counts = dict()
289
- self._id_counts = dict()
290
-
291
- def submit(self, fn, job_name=""):
292
- """
293
- 提交并行任务
294
- Parameters
295
- ----------
296
- fn: callable
297
- 需要并行的callable对象
298
- job_name: str
299
- 提交到的任务名, 不同的任务对应不同的进度条
300
- Returns
301
- -------
302
- """
303
-
304
- # 提交任务,对任务进行分类,提交到对应的task id中,并且封装新的功能:使其在运行完毕后将任务进度更新放入队列
305
- @functools.wraps(fn)
306
- def collect(**kwargs):
307
- """归集所有的job到对应的task"""
308
- with warnings.catch_warnings():
309
- warnings.simplefilter('ignore')
310
- job = delay(fn)(**kwargs)
311
- task_name = self._default_task_name if not job_name else job_name
312
- if task_name not in self._task_ids:
313
- self._task_ids[task_name] = len(self._all_tasks)
314
- self._task_counts[task_name] = 0
315
- self._all_tasks.append(task_name)
316
- self._id_counts[self._task_ids[task_name]] = 0
317
- self._task_counts[task_name] += 1
318
- self._id_counts[self._task_ids[task_name]] += 1
319
- job.task_id = self._task_ids[task_name]
320
- job.job_id = self._task_counts[task_name]
321
- job.task_name = task_name
322
- self._all_jobs.append(job)
323
- return job
324
-
325
- return collect
326
-
327
- def do(self, *args, **kwargs):
328
- if self.show_progress:
329
- # if job_name is not None:
330
- # ylog.info(f"{job_name} Start")
331
- # 消息队列进行通信
332
- manager = multiprocessing.Manager()
333
- queue = manager.Queue()
334
- tqdm_bars = [tqdm(total=self._task_counts[task_name],
335
- desc=f"{str(task_name)}", leave=False) for task_name in
336
- self._all_tasks]
337
- # 初始化多个任务的进度条,每个任务一个
338
- task_ids = [task_id for task_id in range(len(self._all_tasks))]
339
- # 创建并启动用于更新进度条的线程
340
- progress_thread = threading.Thread(target=update_progress_bars, args=(
341
- tqdm_bars, task_ids, queue, len(self._all_tasks), self._id_counts))
342
- progress_thread.start()
343
- if self._parallel is not None:
344
- # 执行并行任务
345
- result = self._parallel(delayed(run_job)(job=job,
346
- task_id=job.task_id,
347
- queue=queue) for job in self._all_jobs)
348
- else:
349
- result = [run_job(job=job, task_id=job.task_id, queue=queue) for job in self._all_jobs]
350
- # time.sleep(.3)
351
- # 等待进度更新线程执行完毕
352
- progress_thread.join()
353
- # if job_name is not None:
354
- # ylog.info(f"{job_name} Done")
355
- else:
356
- if self._parallel is not None:
357
- result = self._parallel(delayed(job)() for job in self._all_jobs)
358
- else:
359
- result = [job() for job in self._all_jobs]
360
- self._all_jobs = list() # list[job]
361
- self._all_tasks = list() # list[task_name]
362
- self._task_ids = dict() # {task_name1: 0, task_name2: 1, ...}
363
- self._task_counts = dict()
364
- self._id_counts = dict()
365
- return result
366
-
367
- def __enter__(self):
368
- return self
369
-
370
- def __exit__(self, exc_type, exc_val, exc_tb):
371
- # 释放进程
372
- pass
@@ -1,94 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: ygo
3
- Version: 1.0.2
4
- Project-URL: homepage, https://github.com/link-yundi/ygo
5
- Project-URL: repository, https://github.com/link-yundi/ygo
6
- Requires-Python: >=3.8
7
- Description-Content-Type: text/markdown
8
- License-File: LICENSE
9
- Requires-Dist: clickhouse-driver>=0.2.9
10
- Requires-Dist: dynaconf>=3.2.11
11
- Requires-Dist: joblib>=1.4.2
12
- Requires-Dist: loguru>=0.7.3
13
- Requires-Dist: pandas>=2.0.3
14
- Requires-Dist: polars>=1.8.2
15
- Requires-Dist: pyarrow>=17.0.0
16
- Requires-Dist: pymysql>=1.1.1
17
- Requires-Dist: sqlalchemy>=2.0.40
18
- Requires-Dist: sqlparse>=0.5.3
19
- Requires-Dist: tqdm>=4.67.1
20
- Dynamic: license-file
21
-
22
- # ygo
23
- 并发执行(加入进度条)以及延迟调用(基于joblib),以及获取对应函数的相关信息
24
-
25
- ### 安装
26
- ```shell
27
- pip install -U git+https://github.com/link-yundi/ygo.git
28
- ```
29
-
30
- ### 示例
31
-
32
- ```
33
- ├── a
34
- │   ├── __init__.py
35
- │   └── b
36
- │   ├── __init__.py
37
- │   └── c.py
38
- └── test.py
39
-
40
- c.py 中定义了目标函数
41
- def test_fn(a, b=2):
42
- return a+b
43
- ```
44
-
45
- #### 场景1: 并发
46
-
47
- ```python
48
- import ygo
49
- import ylog
50
- from a.b.c import test_fn
51
-
52
- with ygo.pool(job_name="test parallel", show_progress=True) as go:
53
- for i in range(10):
54
- go.submit(test_fn)(a=i, b=2*i)
55
- for res in go.do():
56
- ylog.info(res)
57
- ```
58
-
59
- #### 场景2: 延迟调用
60
-
61
- ```
62
- >>> fn = delay(test_fn)(a=1, b=2)
63
- >>> fn()
64
- 3
65
- >>> # 逐步传递参数
66
- >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
67
- >>> fn2 = delay(fn1)(b=2)
68
- >>> fn2(c=3)
69
- 6
70
- >>> # 参数更改
71
- >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
72
- >>> fn2 = delay(fn1)(c=3, b=5)
73
- >>> fn2()
74
- 9
75
- ```
76
-
77
- #### 场景3: 获取目标函数信息
78
-
79
- ```
80
- >>> ygo.fn_info(test_fn)
81
- =============================================================
82
- a.b.c.test_fn(a, b=2)
83
- =============================================================
84
- def test_fn(a, b=2):
85
- return a+b
86
- ```
87
-
88
- #### 场景4: 通过字符串解析函数并执行
89
-
90
- ```
91
- >>> ygo.fn_from_str("a.b.c.test_fn")(a=1, b=5)
92
- 6
93
- ```
94
-
@@ -1,15 +0,0 @@
1
- ycat/__init__.py,sha256=zBMOFStzKSt_5jw4af6YFtPD5Svr8fJlZkP_AdUjCoA,554
2
- ycat/client.py,sha256=tsrJUeoy_cFiHjX7hnh0dtnO_3njhtMLrQcAfi0TYgQ,3796
3
- ycat/dtype.py,sha256=mRGLDe_Ho6-tDsoj5wwrAzozEoIYCAHGKdpRqgBfUcI,12577
4
- ycat/parse.py,sha256=9Kgr33nHYC96TGpZs98PAu0cbK-FrR0pfuf8lfD647I,2289
5
- ycat/yck.py,sha256=FlGMBuKEngB4TwFXMp4P3dLg9IfFmUg3eDqXzQ0kQoI,2738
6
- ygo/__init__.py,sha256=FMN06Tfa8_oV26eklBZCtGTyHZ6MghHxHj4PS_FSXCA,222
7
- ygo/exceptions.py,sha256=4Kd92kpwpsXHJJkSv4OqcN--PEEvIGGvDDgOOsk68gg,385
8
- ygo/ygo.py,sha256=vCMUur_41yY0QB4gj8K5wBZHql_cbmANhI8QwPRCTmo,11613
9
- ygo-1.0.2.dist-info/licenses/LICENSE,sha256=6AKUWQ1xe-jwPSFv_H6FMQLNNWb7AYqzuEUTwlP2S8M,1067
10
- ylog/__init__.py,sha256=2sIp4PHNoQMCi0QtIarTI4raACd7SdRHNY7fY5hKYwc,397
11
- ylog/core.py,sha256=uO_r5wDrBN5edV_TDHUNzcqRs6DMDDrrjfyqYZhak4w,7716
12
- ygo-1.0.2.dist-info/METADATA,sha256=fpdhSXCKLch-zfRbgYMasR5HsPaF--CBMsPtSKzN9ss,1980
13
- ygo-1.0.2.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
14
- ygo-1.0.2.dist-info/top_level.txt,sha256=jEbfiz5fX4iSzDg8_Npdv5SIC_Kphmb1m3vuyD9ZC1E,14
15
- ygo-1.0.2.dist-info/RECORD,,
@@ -1,3 +0,0 @@
1
- ycat
2
- ygo
3
- ylog
ylog/__init__.py DELETED
@@ -1,20 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- ---------------------------------------------
4
- Created on 2025/5/14 15:37
5
- @author: ZhangYundi
6
- @email: yundi.xxii@outlook.com
7
- ---------------------------------------------
8
- """
9
-
10
- from .core import trace, debug, info, warning, error, critical, update_config
11
-
12
- __all__ = [
13
- "trace",
14
- "debug",
15
- "info",
16
- "warning",
17
- "error",
18
- "critical",
19
- "update_config"
20
- ]