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.
Files changed (35) hide show
  1. {funcguard-0.2.48 → funcguard-0.2.50}/PKG-INFO +14 -5
  2. {funcguard-0.2.48 → funcguard-0.2.50}/README.md +13 -4
  3. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/core.py +17 -12
  4. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/mask_utils.py +6 -4
  5. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/PKG-INFO +14 -5
  6. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/SOURCES.txt +2 -1
  7. {funcguard-0.2.48 → funcguard-0.2.50}/setup.py +1 -1
  8. funcguard-0.2.50/tests/test_pd_filter_empty.py +34 -0
  9. {funcguard-0.2.48 → funcguard-0.2.50}/LICENSE +0 -0
  10. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/__init__.py +0 -0
  11. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/calculate.py +0 -0
  12. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/data_models/__init__.py +0 -0
  13. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/data_models/request_models.py +0 -0
  14. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/ip_utils.py +0 -0
  15. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/log_utils.py +0 -0
  16. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/__init__.py +0 -0
  17. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/convert_utils.py +0 -0
  18. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/date_utils.py +0 -0
  19. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/fill_round.py +0 -0
  20. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/filter.py +0 -0
  21. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/json_utils/__init__.py +0 -0
  22. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/json_utils/json_parser.py +0 -0
  23. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/__init__.py +0 -0
  24. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/agg_utils.py +0 -0
  25. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/count_utils.py +0 -0
  26. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/pd_utils/statistics/df_statistics.py +0 -0
  27. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/printer.py +0 -0
  28. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/time_utils.py +0 -0
  29. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard/tools.py +0 -0
  30. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/dependency_links.txt +0 -0
  31. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/not-zip-safe +0 -0
  32. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/requires.txt +0 -0
  33. {funcguard-0.2.48 → funcguard-0.2.50}/funcguard.egg-info/top_level.txt +0 -0
  34. {funcguard-0.2.48 → funcguard-0.2.50}/setup.cfg +0 -0
  35. {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.48
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=5
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=3
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=5
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=5
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=3
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=5
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 = 5,
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: 超时时间(秒),默认5秒
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=5,
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
- remaining = timeout
154
- while remaining > 0 and thread.is_alive():
155
- print(f"\r{prompt} ({option_lines}),{remaining} 秒后自动选择[{default_label}]: ", end="", flush=True)
156
- time.sleep(1)
157
- remaining -= 1
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.48
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=5
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=3
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=5
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
  ```
@@ -29,4 +29,5 @@ funcguard/pd_utils/statistics/agg_utils.py
29
29
  funcguard/pd_utils/statistics/count_utils.py
30
30
  funcguard/pd_utils/statistics/df_statistics.py
31
31
  funcguard/pd_utils/statistics/mask_utils.py
32
- tests/__init__.py
32
+ tests/__init__.py
33
+ tests/test_pd_filter_empty.py
@@ -9,7 +9,7 @@ except FileNotFoundError:
9
9
 
10
10
  setup(
11
11
  name='funcguard',
12
- version='0.2.48',
12
+ version='0.2.50',
13
13
  packages=find_packages(),
14
14
  install_requires=[
15
15
  'requests',
@@ -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