ygo 1.0.1__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.
Potentially problematic release.
This version of ygo might be problematic. Click here for more details.
- ygo-1.0.1/LICENSE +21 -0
- ygo-1.0.1/PKG-INFO +95 -0
- ygo-1.0.1/README.md +73 -0
- ygo-1.0.1/pyproject.toml +32 -0
- ygo-1.0.1/setup.cfg +4 -0
- ygo-1.0.1/ycat/__init__.py +22 -0
- ygo-1.0.1/ycat/client.py +157 -0
- ygo-1.0.1/ycat/dtype.py +389 -0
- ygo-1.0.1/ycat/parse.py +66 -0
- ygo-1.0.1/ycat/yck.py +87 -0
- ygo-1.0.1/ygo/__init__.py +10 -0
- ygo-1.0.1/ygo/exceptions.py +13 -0
- ygo-1.0.1/ygo/ygo.py +372 -0
- ygo-1.0.1/ygo.egg-info/PKG-INFO +95 -0
- ygo-1.0.1/ygo.egg-info/SOURCES.txt +18 -0
- ygo-1.0.1/ygo.egg-info/dependency_links.txt +1 -0
- ygo-1.0.1/ygo.egg-info/requires.txt +12 -0
- ygo-1.0.1/ygo.egg-info/top_level.txt +3 -0
- ygo-1.0.1/ylog/__init__.py +20 -0
- ygo-1.0.1/ylog/core.py +226 -0
ygo-1.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 link-yundi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ygo-1.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ygo
|
|
3
|
+
Version: 1.0.1
|
|
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: duckdb>=1.2.2
|
|
11
|
+
Requires-Dist: dynaconf>=3.2.11
|
|
12
|
+
Requires-Dist: joblib>=1.4.2
|
|
13
|
+
Requires-Dist: loguru>=0.7.3
|
|
14
|
+
Requires-Dist: pandas>=2.0.3
|
|
15
|
+
Requires-Dist: polars>=1.8.2
|
|
16
|
+
Requires-Dist: pyarrow>=17.0.0
|
|
17
|
+
Requires-Dist: pymysql>=1.1.1
|
|
18
|
+
Requires-Dist: sqlalchemy>=2.0.40
|
|
19
|
+
Requires-Dist: sqlparse>=0.5.3
|
|
20
|
+
Requires-Dist: tqdm>=4.67.1
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# ygo
|
|
24
|
+
并发执行(加入进度条)以及延迟调用(基于joblib),以及获取对应函数的相关信息
|
|
25
|
+
|
|
26
|
+
### 安装
|
|
27
|
+
```shell
|
|
28
|
+
pip install -U git+https://github.com/link-yundi/ygo.git
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 示例
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
├── a
|
|
35
|
+
│ ├── __init__.py
|
|
36
|
+
│ └── b
|
|
37
|
+
│ ├── __init__.py
|
|
38
|
+
│ └── c.py
|
|
39
|
+
└── test.py
|
|
40
|
+
|
|
41
|
+
c.py 中定义了目标函数
|
|
42
|
+
def test_fn(a, b=2):
|
|
43
|
+
return a+b
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### 场景1: 并发
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import ygo
|
|
50
|
+
import ylog
|
|
51
|
+
from a.b.c import test_fn
|
|
52
|
+
|
|
53
|
+
with ygo.pool(job_name="test parallel", show_progress=True) as go:
|
|
54
|
+
for i in range(10):
|
|
55
|
+
go.submit(test_fn)(a=i, b=2*i)
|
|
56
|
+
for res in go.do():
|
|
57
|
+
ylog.info(res)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### 场景2: 延迟调用
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
>>> fn = delay(test_fn)(a=1, b=2)
|
|
64
|
+
>>> fn()
|
|
65
|
+
3
|
|
66
|
+
>>> # 逐步传递参数
|
|
67
|
+
>>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
|
|
68
|
+
>>> fn2 = delay(fn1)(b=2)
|
|
69
|
+
>>> fn2(c=3)
|
|
70
|
+
6
|
|
71
|
+
>>> # 参数更改
|
|
72
|
+
>>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
|
|
73
|
+
>>> fn2 = delay(fn1)(c=3, b=5)
|
|
74
|
+
>>> fn2()
|
|
75
|
+
9
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### 场景3: 获取目标函数信息
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
>>> ygo.fn_info(test_fn)
|
|
82
|
+
=============================================================
|
|
83
|
+
a.b.c.test_fn(a, b=2)
|
|
84
|
+
=============================================================
|
|
85
|
+
def test_fn(a, b=2):
|
|
86
|
+
return a+b
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### 场景4: 通过字符串解析函数并执行
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
>>> ygo.fn_from_str("a.b.c.test_fn")(a=1, b=5)
|
|
93
|
+
6
|
|
94
|
+
```
|
|
95
|
+
|
ygo-1.0.1/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ygo
|
|
2
|
+
并发执行(加入进度条)以及延迟调用(基于joblib),以及获取对应函数的相关信息
|
|
3
|
+
|
|
4
|
+
### 安装
|
|
5
|
+
```shell
|
|
6
|
+
pip install -U git+https://github.com/link-yundi/ygo.git
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
### 示例
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
├── a
|
|
13
|
+
│ ├── __init__.py
|
|
14
|
+
│ └── b
|
|
15
|
+
│ ├── __init__.py
|
|
16
|
+
│ └── c.py
|
|
17
|
+
└── test.py
|
|
18
|
+
|
|
19
|
+
c.py 中定义了目标函数
|
|
20
|
+
def test_fn(a, b=2):
|
|
21
|
+
return a+b
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### 场景1: 并发
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import ygo
|
|
28
|
+
import ylog
|
|
29
|
+
from a.b.c import test_fn
|
|
30
|
+
|
|
31
|
+
with ygo.pool(job_name="test parallel", show_progress=True) as go:
|
|
32
|
+
for i in range(10):
|
|
33
|
+
go.submit(test_fn)(a=i, b=2*i)
|
|
34
|
+
for res in go.do():
|
|
35
|
+
ylog.info(res)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### 场景2: 延迟调用
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
>>> fn = delay(test_fn)(a=1, b=2)
|
|
42
|
+
>>> fn()
|
|
43
|
+
3
|
|
44
|
+
>>> # 逐步传递参数
|
|
45
|
+
>>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
|
|
46
|
+
>>> fn2 = delay(fn1)(b=2)
|
|
47
|
+
>>> fn2(c=3)
|
|
48
|
+
6
|
|
49
|
+
>>> # 参数更改
|
|
50
|
+
>>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
|
|
51
|
+
>>> fn2 = delay(fn1)(c=3, b=5)
|
|
52
|
+
>>> fn2()
|
|
53
|
+
9
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### 场景3: 获取目标函数信息
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
>>> ygo.fn_info(test_fn)
|
|
60
|
+
=============================================================
|
|
61
|
+
a.b.c.test_fn(a, b=2)
|
|
62
|
+
=============================================================
|
|
63
|
+
def test_fn(a, b=2):
|
|
64
|
+
return a+b
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### 场景4: 通过字符串解析函数并执行
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
>>> ygo.fn_from_str("a.b.c.test_fn")(a=1, b=5)
|
|
71
|
+
6
|
|
72
|
+
```
|
|
73
|
+
|
ygo-1.0.1/pyproject.toml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ygo"
|
|
7
|
+
version = "1.0.1"
|
|
8
|
+
description = ""
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"clickhouse-driver>=0.2.9",
|
|
13
|
+
"duckdb>=1.2.2",
|
|
14
|
+
"dynaconf>=3.2.11",
|
|
15
|
+
"joblib>=1.4.2",
|
|
16
|
+
"loguru>=0.7.3",
|
|
17
|
+
"pandas>=2.0.3",
|
|
18
|
+
"polars>=1.8.2",
|
|
19
|
+
"pyarrow>=17.0.0",
|
|
20
|
+
"pymysql>=1.1.1",
|
|
21
|
+
"sqlalchemy>=2.0.40",
|
|
22
|
+
"sqlparse>=0.5.3",
|
|
23
|
+
"tqdm>=4.67.1",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
where = ["."]
|
|
28
|
+
include = ["ygo", "ygo.*", "ylog", "ylog.*", "ycat", "ycat.*"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
homepage = "https://github.com/link-yundi/ygo"
|
|
32
|
+
repository = "https://github.com/link-yundi/ygo"
|
ygo-1.0.1/setup.cfg
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
---------------------------------------------
|
|
4
|
+
Created on 2025/5/14 18:29
|
|
5
|
+
@author: ZhangYundi
|
|
6
|
+
@email: yundi.xxii@outlook.com
|
|
7
|
+
---------------------------------------------
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .client import HOME, CATDB, SETTINGS, sql, put, create_engine_ck, create_engine_mysql, read_mysql, read_ck
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"HOME",
|
|
14
|
+
"CATDB",
|
|
15
|
+
"SETTINGS",
|
|
16
|
+
"sql",
|
|
17
|
+
"put",
|
|
18
|
+
"create_engine_ck",
|
|
19
|
+
"create_engine_mysql",
|
|
20
|
+
"read_mysql",
|
|
21
|
+
"read_ck",
|
|
22
|
+
]
|
ygo-1.0.1/ycat/client.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
---------------------------------------------
|
|
4
|
+
Created on 2024/7/1 09:44
|
|
5
|
+
@author: ZhangYundi
|
|
6
|
+
@email: yundi.xxii@outlook.com
|
|
7
|
+
---------------------------------------------
|
|
8
|
+
"""
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
from typing import Optional
|
|
12
|
+
from .yck import connect, query_polars
|
|
13
|
+
|
|
14
|
+
import duckdb
|
|
15
|
+
import polars as pl
|
|
16
|
+
import ylog
|
|
17
|
+
from dynaconf import Dynaconf
|
|
18
|
+
from sqlalchemy import create_engine
|
|
19
|
+
from functools import partial
|
|
20
|
+
|
|
21
|
+
from .parse import extract_table_names_from_sql
|
|
22
|
+
|
|
23
|
+
# 配置文件在 “~/.catdb/setting.toml”
|
|
24
|
+
USERHOME = os.path.expanduser('~') # 用户家目录
|
|
25
|
+
CONFIG_PATH = os.path.join(USERHOME, ".catdb", "settings.toml")
|
|
26
|
+
if not os.path.exists(CONFIG_PATH):
|
|
27
|
+
try:
|
|
28
|
+
os.makedirs(os.path.dirname(CONFIG_PATH))
|
|
29
|
+
except FileExistsError as e:
|
|
30
|
+
...
|
|
31
|
+
except Exception as e:
|
|
32
|
+
ylog.error(f"配置文件生成失败: {e}")
|
|
33
|
+
catdb_path = os.path.join(USERHOME, "catdb")
|
|
34
|
+
template_content = f"""[paths]
|
|
35
|
+
catdb="{catdb_path}" # 本地数据库,默认家目录
|
|
36
|
+
|
|
37
|
+
## 数据库配置:
|
|
38
|
+
[database]
|
|
39
|
+
[database.ck]
|
|
40
|
+
# urls=["<host1>:<port1>", "<host2>:<port2>",]
|
|
41
|
+
# user="xxx"
|
|
42
|
+
# password="xxxxxx"
|
|
43
|
+
[database.jy]
|
|
44
|
+
# url="<host>:<port>"
|
|
45
|
+
# user="xxxx"
|
|
46
|
+
# password="xxxxxx"
|
|
47
|
+
|
|
48
|
+
## 视情况自由增加其他配置
|
|
49
|
+
"""
|
|
50
|
+
with open(CONFIG_PATH, "w") as f:
|
|
51
|
+
f.write(template_content)
|
|
52
|
+
ylog.info(f"生成配置文件: {CONFIG_PATH}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_settings():
|
|
56
|
+
try:
|
|
57
|
+
return Dynaconf(settings_files=[CONFIG_PATH])
|
|
58
|
+
except:
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
HOME = USERHOME
|
|
63
|
+
CATDB = os.path.join(HOME, "catdb")
|
|
64
|
+
# 读取配置文件覆盖
|
|
65
|
+
SETTINGS = get_settings()
|
|
66
|
+
if SETTINGS is not None:
|
|
67
|
+
CATDB = SETTINGS.paths.catdb
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ======================== 本地数据库 catdb ========================
|
|
71
|
+
def tb_path(tb_name: str) -> str:
|
|
72
|
+
"""
|
|
73
|
+
返回指定表名 完整的本地路径
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
tb_name: str
|
|
77
|
+
表名,路径写法: a/b/c
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
full_abs_path: str
|
|
81
|
+
完整的本地绝对路径 $HOME/catdb/a/b/c
|
|
82
|
+
"""
|
|
83
|
+
return os.path.join(CATDB, tb_name)
|
|
84
|
+
|
|
85
|
+
def put(df: pl.DataFrame, tb_name: str, partitions: Optional[list[str]] = None):
|
|
86
|
+
"""
|
|
87
|
+
将数据写入duck_db支持的parquet格式文件
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
df: pandas.DataFrame | pandas.Series | polars.DataFrame
|
|
91
|
+
写入的数据
|
|
92
|
+
tb_name: str
|
|
93
|
+
表名,支持路径写法, a/b/c
|
|
94
|
+
partitions: Optional[List[str]]
|
|
95
|
+
根据哪些字段进行分区,默认不分区
|
|
96
|
+
"""
|
|
97
|
+
tbpath = tb_path(tb_name)
|
|
98
|
+
if not os.path.exists(tbpath):
|
|
99
|
+
try:
|
|
100
|
+
os.makedirs(tbpath)
|
|
101
|
+
except FileExistsError as e:
|
|
102
|
+
pass
|
|
103
|
+
if partitions is not None:
|
|
104
|
+
for field in partitions:
|
|
105
|
+
assert field in df.columns, f'dataframe must have Field `{field}`'
|
|
106
|
+
df.write_parquet(tbpath, partition_by=partitions)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def sql(query: str):
|
|
110
|
+
"""
|
|
111
|
+
从duckdb中读取数据, query语法与mysql一致,特殊语法请查duckdb官网: https://duckdb.org/docs/sql/query_syntax/select
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
query: str
|
|
115
|
+
查询语句
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
result: duckdb.DuckDBPyRelation
|
|
119
|
+
查询结果
|
|
120
|
+
"""
|
|
121
|
+
tbs = extract_table_names_from_sql(query)
|
|
122
|
+
convertor = dict()
|
|
123
|
+
for tb in tbs:
|
|
124
|
+
db_path = tb_path(tb)
|
|
125
|
+
format_tb = f"read_parquet('{db_path}/**/*.parquet', hive_partitioning = true)"
|
|
126
|
+
convertor[tb] = format_tb
|
|
127
|
+
pattern = re.compile("|".join(re.escape(k) for k in convertor.keys()))
|
|
128
|
+
new_query = pattern.sub(lambda m: convertor[m.group(0)], query)
|
|
129
|
+
conn = duckdb.connect()
|
|
130
|
+
conn.execute("PRAGMA disable_progress_bar;")
|
|
131
|
+
conn.execute("PRAGMA threads=1;")
|
|
132
|
+
res = conn.execute(new_query).fetch_arrow_table()
|
|
133
|
+
res = pl.from_arrow(res)
|
|
134
|
+
conn.close()
|
|
135
|
+
return res
|
|
136
|
+
|
|
137
|
+
def create_engine_ck(urls: list[str], user: str, password: str):
|
|
138
|
+
return partial(connect, urls, user, password)
|
|
139
|
+
|
|
140
|
+
def read_ck(sql, eng)->pl.DataFrame:
|
|
141
|
+
with eng() as conn:
|
|
142
|
+
return query_polars(sql, conn)
|
|
143
|
+
|
|
144
|
+
def create_engine_mysql(url, user, password, database):
|
|
145
|
+
"""
|
|
146
|
+
:param url: <host>:<port>
|
|
147
|
+
:param user:
|
|
148
|
+
:param password:
|
|
149
|
+
:param database:
|
|
150
|
+
:return:
|
|
151
|
+
"""
|
|
152
|
+
engine = create_engine(f"mysql+pymysql://{user}:{password}@{url}/{database}")
|
|
153
|
+
return engine
|
|
154
|
+
|
|
155
|
+
def read_mysql(sql, eng) -> pl.DataFrame:
|
|
156
|
+
with eng.connect() as conn:
|
|
157
|
+
return pl.read_database(sql, conn)
|