funcguard 0.2.48__tar.gz → 0.2.50__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.
- {funcguard-0.2.48 → funcguard-0.2.50}/PKG-INFO +14 -5
- {funcguard-0.2.48 → funcguard-0.2.50}/README.md +13 -4
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/core.py +17 -12
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/mask_utils.py +6 -4
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/PKG-INFO +14 -5
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/SOURCES.txt +2 -1
- {funcguard-0.2.48 → funcguard-0.2.50}/setup.py +1 -1
- funcguard-0.2.50/tests/test_pd_filter_empty.py +34 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/LICENSE +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/__init__.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/calculate.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/data_models/__init__.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/data_models/request_models.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/ip_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/log_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/__init__.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/convert_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/date_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/fill_round.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/filter.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/json_utils/__init__.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/json_utils/json_parser.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/__init__.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/agg_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/count_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/df_statistics.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/printer.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/time_utils.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/tools.py +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/dependency_links.txt +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/not-zip-safe +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/requires.txt +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/top_level.txt +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/setup.cfg +0 -0
- {funcguard-0.2.48 → funcguard-0.2.50}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: funcguard
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.50
|
|
4
4
|
Summary: FuncGuard是一个Python库,提供函数执行超时控制、重试机制、HTTP请求封装和格式化打印工具。
|
|
5
5
|
Home-page: https://github.com/tinycen/funcguard
|
|
6
6
|
Author: tinycen
|
|
@@ -102,12 +102,12 @@ except Exception as e:
|
|
|
102
102
|
```python
|
|
103
103
|
from funcguard import ask_select
|
|
104
104
|
|
|
105
|
-
# 基础用法 -
|
|
105
|
+
# 基础用法 - 选择属性填写模式(默认超时10秒)
|
|
106
106
|
result = ask_select(
|
|
107
107
|
options={True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
|
|
108
108
|
default_key="all",
|
|
109
109
|
prompt="请选择属性填写模式",
|
|
110
|
-
timeout=
|
|
110
|
+
timeout=10
|
|
111
111
|
)
|
|
112
112
|
print(f"用户选择: {result}") # 返回 True, False 或 "all"
|
|
113
113
|
|
|
@@ -116,7 +116,7 @@ env = ask_select(
|
|
|
116
116
|
options={"dev": "开发环境", "test": "测试环境", "prod": "生产环境"},
|
|
117
117
|
default_key="dev",
|
|
118
118
|
prompt="请选择部署环境",
|
|
119
|
-
timeout=
|
|
119
|
+
timeout=10
|
|
120
120
|
)
|
|
121
121
|
print(f"当前环境: {env}")
|
|
122
122
|
|
|
@@ -125,7 +125,16 @@ count = ask_select(
|
|
|
125
125
|
options={10: "10条", 50: "50条", 100: "100条"},
|
|
126
126
|
default_key=50,
|
|
127
127
|
prompt="查询数量",
|
|
128
|
-
timeout=
|
|
128
|
+
timeout=10
|
|
129
|
+
)
|
|
130
|
+
print(f"查询 {count} 条数据")
|
|
131
|
+
|
|
132
|
+
# 无超时模式 - 一直等待用户输入
|
|
133
|
+
count = ask_select(
|
|
134
|
+
options={10: "10条", 50: "50条", 100: "100条"},
|
|
135
|
+
default_key=50,
|
|
136
|
+
prompt="查询数量",
|
|
137
|
+
timeout=None
|
|
129
138
|
)
|
|
130
139
|
print(f"查询 {count} 条数据")
|
|
131
140
|
```
|
|
@@ -75,12 +75,12 @@ except Exception as e:
|
|
|
75
75
|
```python
|
|
76
76
|
from funcguard import ask_select
|
|
77
77
|
|
|
78
|
-
# 基础用法 -
|
|
78
|
+
# 基础用法 - 选择属性填写模式(默认超时10秒)
|
|
79
79
|
result = ask_select(
|
|
80
80
|
options={True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
|
|
81
81
|
default_key="all",
|
|
82
82
|
prompt="请选择属性填写模式",
|
|
83
|
-
timeout=
|
|
83
|
+
timeout=10
|
|
84
84
|
)
|
|
85
85
|
print(f"用户选择: {result}") # 返回 True, False 或 "all"
|
|
86
86
|
|
|
@@ -89,7 +89,7 @@ env = ask_select(
|
|
|
89
89
|
options={"dev": "开发环境", "test": "测试环境", "prod": "生产环境"},
|
|
90
90
|
default_key="dev",
|
|
91
91
|
prompt="请选择部署环境",
|
|
92
|
-
timeout=
|
|
92
|
+
timeout=10
|
|
93
93
|
)
|
|
94
94
|
print(f"当前环境: {env}")
|
|
95
95
|
|
|
@@ -98,7 +98,16 @@ count = ask_select(
|
|
|
98
98
|
options={10: "10条", 50: "50条", 100: "100条"},
|
|
99
99
|
default_key=50,
|
|
100
100
|
prompt="查询数量",
|
|
101
|
-
timeout=
|
|
101
|
+
timeout=10
|
|
102
|
+
)
|
|
103
|
+
print(f"查询 {count} 条数据")
|
|
104
|
+
|
|
105
|
+
# 无超时模式 - 一直等待用户输入
|
|
106
|
+
count = ask_select(
|
|
107
|
+
options={10: "10条", 50: "50条", 100: "100条"},
|
|
108
|
+
default_key=50,
|
|
109
|
+
prompt="查询数量",
|
|
110
|
+
timeout=None
|
|
102
111
|
)
|
|
103
112
|
print(f"查询 {count} 条数据")
|
|
104
113
|
```
|
|
@@ -95,7 +95,7 @@ def ask_select(
|
|
|
95
95
|
options: dict,
|
|
96
96
|
default_key = None,
|
|
97
97
|
prompt: str = "请选择",
|
|
98
|
-
timeout: int =
|
|
98
|
+
timeout: int | None = 10,
|
|
99
99
|
):
|
|
100
100
|
"""
|
|
101
101
|
显示一个数字选择菜单,接受用户输入,超时自动返回默认值。
|
|
@@ -105,7 +105,7 @@ def ask_select(
|
|
|
105
105
|
例如: {True: "需要填写属性", False: "不需要填写属性", "all": "不限制"}
|
|
106
106
|
default_key: 超时或输入无效时的默认返回值,若为None则使用最后一个选项的键
|
|
107
107
|
prompt: 提示语前缀
|
|
108
|
-
timeout: 超时时间(秒),默认
|
|
108
|
+
timeout: 超时时间(秒),默认10秒;若为None则不设置超时,一直等待用户输入
|
|
109
109
|
|
|
110
110
|
返回:
|
|
111
111
|
用户选择的选项键(options中的某个键),或default_key
|
|
@@ -115,7 +115,7 @@ def ask_select(
|
|
|
115
115
|
... {True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
|
|
116
116
|
... default_key="all",
|
|
117
117
|
... prompt="请选择属性填写模式",
|
|
118
|
-
... timeout=
|
|
118
|
+
... timeout=10,
|
|
119
119
|
... )
|
|
120
120
|
"""
|
|
121
121
|
# 确保选项非空
|
|
@@ -149,12 +149,17 @@ def ask_select(
|
|
|
149
149
|
thread = Thread(target=input_thread, daemon=True)
|
|
150
150
|
thread.start()
|
|
151
151
|
|
|
152
|
-
#
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
# 倒计时显示(仅当设置了timeout时)
|
|
153
|
+
if timeout is not None:
|
|
154
|
+
remaining = timeout
|
|
155
|
+
while remaining > 0 and thread.is_alive():
|
|
156
|
+
print(f"\r{prompt} ({option_lines}),{remaining} 秒后自动选择[{default_label}]: ", end="", flush=True)
|
|
157
|
+
time.sleep(1)
|
|
158
|
+
remaining -= 1
|
|
159
|
+
else:
|
|
160
|
+
# 无超时,直接显示提示并等待用户输入
|
|
161
|
+
print(f"{prompt} ({option_lines}): ", end="", flush=True)
|
|
162
|
+
thread.join()
|
|
158
163
|
|
|
159
164
|
# 等待线程结束(如果用户已输入)或超时
|
|
160
165
|
thread.join(0)
|
|
@@ -164,18 +169,18 @@ def ask_select(
|
|
|
164
169
|
except Empty:
|
|
165
170
|
user_input = None
|
|
166
171
|
|
|
167
|
-
if user_input is None:
|
|
172
|
+
if user_input is None and timeout is not None:
|
|
168
173
|
print(f"\n超时,自动选择[{default_label}]")
|
|
169
174
|
return default_key
|
|
170
175
|
|
|
171
176
|
# 验证输入
|
|
172
177
|
try:
|
|
173
|
-
choice = int(user_input)
|
|
178
|
+
choice = int(user_input) # pyright: ignore[reportArgumentType]
|
|
174
179
|
if 0 <= choice < len(items):
|
|
175
180
|
selected_key, selected_label = items[choice]
|
|
176
181
|
print(f"\n已选择 {choice}:{selected_label}")
|
|
177
182
|
return selected_key
|
|
178
|
-
except ValueError:
|
|
183
|
+
except (ValueError, TypeError):
|
|
179
184
|
pass
|
|
180
185
|
|
|
181
186
|
# 输入无效,返回默认值
|
|
@@ -9,6 +9,9 @@ def _is_empty(x):
|
|
|
9
9
|
# 处理 numpy/pandas 数组类型(0维数组也会被isinstance识别)
|
|
10
10
|
if isinstance(x, (np.ndarray, pd.Series)):
|
|
11
11
|
return x.size == 0
|
|
12
|
+
# 原生容器优先按长度判断,避免 pd.isna([]) 返回空数组引发歧义
|
|
13
|
+
if isinstance(x, (str, list, tuple, dict, set)):
|
|
14
|
+
return len(x) == 0
|
|
12
15
|
# 使用 try-except 避免 pd.isna() 在某些类型上的歧义
|
|
13
16
|
try:
|
|
14
17
|
if pd.isna(x):
|
|
@@ -16,8 +19,6 @@ def _is_empty(x):
|
|
|
16
19
|
except ValueError:
|
|
17
20
|
# pd.isna() 返回数组或产生歧义时,说明不是空值
|
|
18
21
|
pass
|
|
19
|
-
if isinstance(x, (str, list, tuple, dict, set)):
|
|
20
|
-
return len(x) == 0
|
|
21
22
|
return False
|
|
22
23
|
|
|
23
24
|
|
|
@@ -26,6 +27,9 @@ def _is_not_empty(x):
|
|
|
26
27
|
# 处理 numpy/pandas 数组类型
|
|
27
28
|
if isinstance(x, (np.ndarray, pd.Series)):
|
|
28
29
|
return x.size > 0
|
|
30
|
+
# 原生容器优先按长度判断,避免 pd.isna([]) 返回空数组引发歧义
|
|
31
|
+
if isinstance(x, (str, list, tuple, dict, set)):
|
|
32
|
+
return len(x) > 0
|
|
29
33
|
# 使用 try-except 避免 pd.isna() 在某些类型上的歧义
|
|
30
34
|
try:
|
|
31
35
|
if pd.isna(x):
|
|
@@ -33,8 +37,6 @@ def _is_not_empty(x):
|
|
|
33
37
|
except ValueError:
|
|
34
38
|
# pd.isna() 返回数组或产生歧义时,说明有值
|
|
35
39
|
return True
|
|
36
|
-
if isinstance(x, (str, list, tuple, dict, set)):
|
|
37
|
-
return len(x) > 0
|
|
38
40
|
return True
|
|
39
41
|
|
|
40
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: funcguard
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.50
|
|
4
4
|
Summary: FuncGuard是一个Python库,提供函数执行超时控制、重试机制、HTTP请求封装和格式化打印工具。
|
|
5
5
|
Home-page: https://github.com/tinycen/funcguard
|
|
6
6
|
Author: tinycen
|
|
@@ -102,12 +102,12 @@ except Exception as e:
|
|
|
102
102
|
```python
|
|
103
103
|
from funcguard import ask_select
|
|
104
104
|
|
|
105
|
-
# 基础用法 -
|
|
105
|
+
# 基础用法 - 选择属性填写模式(默认超时10秒)
|
|
106
106
|
result = ask_select(
|
|
107
107
|
options={True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
|
|
108
108
|
default_key="all",
|
|
109
109
|
prompt="请选择属性填写模式",
|
|
110
|
-
timeout=
|
|
110
|
+
timeout=10
|
|
111
111
|
)
|
|
112
112
|
print(f"用户选择: {result}") # 返回 True, False 或 "all"
|
|
113
113
|
|
|
@@ -116,7 +116,7 @@ env = ask_select(
|
|
|
116
116
|
options={"dev": "开发环境", "test": "测试环境", "prod": "生产环境"},
|
|
117
117
|
default_key="dev",
|
|
118
118
|
prompt="请选择部署环境",
|
|
119
|
-
timeout=
|
|
119
|
+
timeout=10
|
|
120
120
|
)
|
|
121
121
|
print(f"当前环境: {env}")
|
|
122
122
|
|
|
@@ -125,7 +125,16 @@ count = ask_select(
|
|
|
125
125
|
options={10: "10条", 50: "50条", 100: "100条"},
|
|
126
126
|
default_key=50,
|
|
127
127
|
prompt="查询数量",
|
|
128
|
-
timeout=
|
|
128
|
+
timeout=10
|
|
129
|
+
)
|
|
130
|
+
print(f"查询 {count} 条数据")
|
|
131
|
+
|
|
132
|
+
# 无超时模式 - 一直等待用户输入
|
|
133
|
+
count = ask_select(
|
|
134
|
+
options={10: "10条", 50: "50条", 100: "100条"},
|
|
135
|
+
default_key=50,
|
|
136
|
+
prompt="查询数量",
|
|
137
|
+
timeout=None
|
|
129
138
|
)
|
|
130
139
|
print(f"查询 {count} 条数据")
|
|
131
140
|
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from funcguard.pd_utils.filter import pd_filter
|
|
6
|
+
from funcguard.pd_utils.statistics.mask_utils import _is_empty, _is_not_empty
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_empty_helpers_handle_empty_list_correctly():
|
|
10
|
+
assert _is_empty([]) is True
|
|
11
|
+
assert _is_not_empty([]) is False
|
|
12
|
+
assert _is_empty([1]) is False
|
|
13
|
+
assert _is_not_empty([1]) is True
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_pd_filter_not_empty_excludes_real_empty_containers_and_nan():
|
|
17
|
+
df = pd.DataFrame(
|
|
18
|
+
{
|
|
19
|
+
"segments": [
|
|
20
|
+
[],
|
|
21
|
+
[1, 2],
|
|
22
|
+
None,
|
|
23
|
+
math.nan,
|
|
24
|
+
"",
|
|
25
|
+
"[]",
|
|
26
|
+
{},
|
|
27
|
+
{"a": 1},
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
filtered = pd_filter(df, ("segments", "not empty"))
|
|
33
|
+
|
|
34
|
+
assert filtered["segments"].tolist() == [[1, 2], "[]", {"a": 1}]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|