funcguard 0.2.42__tar.gz → 0.2.44__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 (34) hide show
  1. {funcguard-0.2.42 → funcguard-0.2.44}/PKG-INFO +39 -3
  2. {funcguard-0.2.42 → funcguard-0.2.44}/README.md +38 -2
  3. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/__init__.py +6 -3
  4. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/core.py +89 -3
  5. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/__init__.py +3 -1
  6. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/convert_utils.py +42 -1
  7. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/statistics/agg_utils.py +10 -12
  8. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/statistics/count_utils.py +9 -10
  9. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/statistics/df_statistics.py +18 -18
  10. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard.egg-info/PKG-INFO +39 -3
  11. {funcguard-0.2.42 → funcguard-0.2.44}/setup.py +1 -1
  12. {funcguard-0.2.42 → funcguard-0.2.44}/LICENSE +0 -0
  13. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/calculate.py +0 -0
  14. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/data_models/__init__.py +0 -0
  15. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/data_models/request_models.py +0 -0
  16. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/ip_utils.py +0 -0
  17. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/log_utils.py +0 -0
  18. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/date_utils.py +0 -0
  19. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/fill_round.py +0 -0
  20. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/filter.py +0 -0
  21. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/json_utils/__init__.py +0 -0
  22. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/json_utils/json_parser.py +0 -0
  23. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/statistics/__init__.py +0 -0
  24. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/pd_utils/statistics/mask_utils.py +0 -0
  25. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/printer.py +0 -0
  26. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/time_utils.py +0 -0
  27. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard/tools.py +0 -0
  28. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard.egg-info/SOURCES.txt +0 -0
  29. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard.egg-info/dependency_links.txt +0 -0
  30. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard.egg-info/not-zip-safe +0 -0
  31. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard.egg-info/requires.txt +0 -0
  32. {funcguard-0.2.42 → funcguard-0.2.44}/funcguard.egg-info/top_level.txt +0 -0
  33. {funcguard-0.2.42 → funcguard-0.2.44}/setup.cfg +0 -0
  34. {funcguard-0.2.42 → funcguard-0.2.44}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: funcguard
3
- Version: 0.2.42
3
+ Version: 0.2.44
4
4
  Summary: FuncGuard是一个Python库,提供函数执行超时控制、重试机制、HTTP请求封装和格式化打印工具。
5
5
  Home-page: https://github.com/tinycen/funcguard
6
6
  Author: tinycen
@@ -34,7 +34,7 @@ FuncGuard是一个Python库,提供了函数执行超时控制和重试机制
34
34
 
35
35
  | 分类 | 功能描述 | 文档 |
36
36
  |------|----------|------|
37
- | **核心功能** | 函数执行超时控制、函数执行失败自动重试 | - |
37
+ | **核心功能** | 函数执行超时控制、函数执行失败自动重试、交互式选择菜单 | - |
38
38
  | **网络请求** | HTTP请求封装(支持自动重试)、MD5哈希、Basic Auth编码 | [查看](./docs/network.md) |
39
39
  | **时间工具** | 时间日志记录、耗时统计、执行时间监控和警告、时间等待(带倒计时) | [查看](./docs/time_utils.md) |
40
40
  | **打印工具** | 格式化分隔线、块打印、标题打印、进度条显示 | - |
@@ -95,6 +95,41 @@ except Exception as e:
95
95
  print(f"重试后仍然失败: {e}")
96
96
  ```
97
97
 
98
+ ### 交互式选择菜单
99
+
100
+ 使用 `ask_select` 函数创建一个带数字编号的交互式选择菜单,支持超时自动选择:
101
+
102
+ ```python
103
+ from funcguard import ask_select
104
+
105
+ # 基础用法 - 选择属性填写模式
106
+ result = ask_select(
107
+ options={True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
108
+ default_key="all",
109
+ prompt="请选择属性填写模式",
110
+ timeout=5
111
+ )
112
+ print(f"用户选择: {result}") # 返回 True, False 或 "all"
113
+
114
+ # 选择部署环境
115
+ env = ask_select(
116
+ options={"dev": "开发环境", "test": "测试环境", "prod": "生产环境"},
117
+ default_key="dev",
118
+ prompt="请选择部署环境",
119
+ timeout=3
120
+ )
121
+ print(f"当前环境: {env}")
122
+
123
+ # 选择数量(使用整数作为键)
124
+ count = ask_select(
125
+ options={10: "10条", 50: "50条", 100: "100条"},
126
+ default_key=50,
127
+ prompt="查询数量",
128
+ timeout=5
129
+ )
130
+ print(f"查询 {count} 条数据")
131
+ ```
132
+
98
133
  ### HTTP请求
99
134
 
100
135
  FuncGuard 提供了强大的 HTTP 请求功能,支持自动重试、请求日志记录、以及 curl_cffi 兜底(用于绕过反爬虫检测)。详细文档请参考 [network.md](docs/network.md)。
@@ -496,6 +531,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
496
531
  |-----------|----------|
497
532
  | `timeout_handler` | 函数执行超时控制 |
498
533
  | `retry_function` | 函数执行失败自动重试 |
534
+ | `ask_select` | 交互式数字选择菜单(支持超时自动选择) |
499
535
 
500
536
  ### 网络请求
501
537
 
@@ -542,7 +578,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
542
578
  | 函数/类名 | 功能说明 | 文档 |
543
579
  |-----------|----------|------|
544
580
  | `pd_fill_na` / `pd_fill_nat` | 数据填充 | [查看](docs/pandas/fill.md) |
545
- | `pd_convert_columns` / `pd_convert_decimal` / `pd_convert_numeric_series` / `pd_convert_str_datetime` / `pd_convert_datetime_str` | 类型转换 | [查看](docs/pandas/convert.md) |
581
+ | `pd_convert_columns` / `pd_convert_decimal` / `pd_convert_numeric_series` / `pd_convert_str_datetime` / `pd_convert_datetime_str` / `pd_convert_series` | 类型转换 | [查看](docs/pandas/convert.md) |
546
582
  | `pd_load_json` | JSON解析 | [查看](docs/pandas/json.md) |
547
583
  | `pd_filter` | 数据筛选 | [查看](docs/pandas/filter.md) |
548
584
  | `pd_count` / `pd_value_counts` | 条件计数统计 | [查看](docs/pandas/count.md) |
@@ -7,7 +7,7 @@ FuncGuard是一个Python库,提供了函数执行超时控制和重试机制
7
7
 
8
8
  | 分类 | 功能描述 | 文档 |
9
9
  |------|----------|------|
10
- | **核心功能** | 函数执行超时控制、函数执行失败自动重试 | - |
10
+ | **核心功能** | 函数执行超时控制、函数执行失败自动重试、交互式选择菜单 | - |
11
11
  | **网络请求** | HTTP请求封装(支持自动重试)、MD5哈希、Basic Auth编码 | [查看](./docs/network.md) |
12
12
  | **时间工具** | 时间日志记录、耗时统计、执行时间监控和警告、时间等待(带倒计时) | [查看](./docs/time_utils.md) |
13
13
  | **打印工具** | 格式化分隔线、块打印、标题打印、进度条显示 | - |
@@ -68,6 +68,41 @@ except Exception as e:
68
68
  print(f"重试后仍然失败: {e}")
69
69
  ```
70
70
 
71
+ ### 交互式选择菜单
72
+
73
+ 使用 `ask_select` 函数创建一个带数字编号的交互式选择菜单,支持超时自动选择:
74
+
75
+ ```python
76
+ from funcguard import ask_select
77
+
78
+ # 基础用法 - 选择属性填写模式
79
+ result = ask_select(
80
+ options={True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
81
+ default_key="all",
82
+ prompt="请选择属性填写模式",
83
+ timeout=5
84
+ )
85
+ print(f"用户选择: {result}") # 返回 True, False 或 "all"
86
+
87
+ # 选择部署环境
88
+ env = ask_select(
89
+ options={"dev": "开发环境", "test": "测试环境", "prod": "生产环境"},
90
+ default_key="dev",
91
+ prompt="请选择部署环境",
92
+ timeout=3
93
+ )
94
+ print(f"当前环境: {env}")
95
+
96
+ # 选择数量(使用整数作为键)
97
+ count = ask_select(
98
+ options={10: "10条", 50: "50条", 100: "100条"},
99
+ default_key=50,
100
+ prompt="查询数量",
101
+ timeout=5
102
+ )
103
+ print(f"查询 {count} 条数据")
104
+ ```
105
+
71
106
  ### HTTP请求
72
107
 
73
108
  FuncGuard 提供了强大的 HTTP 请求功能,支持自动重试、请求日志记录、以及 curl_cffi 兜底(用于绕过反爬虫检测)。详细文档请参考 [network.md](docs/network.md)。
@@ -469,6 +504,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
469
504
  |-----------|----------|
470
505
  | `timeout_handler` | 函数执行超时控制 |
471
506
  | `retry_function` | 函数执行失败自动重试 |
507
+ | `ask_select` | 交互式数字选择菜单(支持超时自动选择) |
472
508
 
473
509
  ### 网络请求
474
510
 
@@ -515,7 +551,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
515
551
  | 函数/类名 | 功能说明 | 文档 |
516
552
  |-----------|----------|------|
517
553
  | `pd_fill_na` / `pd_fill_nat` | 数据填充 | [查看](docs/pandas/fill.md) |
518
- | `pd_convert_columns` / `pd_convert_decimal` / `pd_convert_numeric_series` / `pd_convert_str_datetime` / `pd_convert_datetime_str` | 类型转换 | [查看](docs/pandas/convert.md) |
554
+ | `pd_convert_columns` / `pd_convert_decimal` / `pd_convert_numeric_series` / `pd_convert_str_datetime` / `pd_convert_datetime_str` / `pd_convert_series` | 类型转换 | [查看](docs/pandas/convert.md) |
519
555
  | `pd_load_json` | JSON解析 | [查看](docs/pandas/json.md) |
520
556
  | `pd_filter` | 数据筛选 | [查看](docs/pandas/filter.md) |
521
557
  | `pd_count` / `pd_value_counts` | 条件计数统计 | [查看](docs/pandas/count.md) |
@@ -1,4 +1,4 @@
1
- from .core import timeout_handler, retry_function
1
+ from .core import timeout_handler, retry_function, ask_select
2
2
  from .tools import send_request, curl_cffi_request, check_url_valid, encode_basic_auth, md5_hash
3
3
  from .time_utils import (
4
4
  time_log, time_diff, time_monitor, time_wait, color_logger,
@@ -14,7 +14,8 @@ from .pd_utils import (
14
14
  round_columns as pd_round_columns,
15
15
  cal_date_diff as pd_cal_date_diff,
16
16
 
17
- # 数据类型转换类
17
+ # 数据转换类
18
+ convert_series as pd_convert_series,
18
19
  convert_columns as pd_convert_columns,
19
20
  convert_decimal as pd_convert_decimal,
20
21
  convert_numeric_series as pd_convert_numeric_series,
@@ -49,6 +50,7 @@ __all__ = [
49
50
  # 核心功能
50
51
  "timeout_handler",
51
52
  "retry_function",
53
+ "ask_select",
52
54
 
53
55
  # 网络请求工具
54
56
  "md5_hash",
@@ -86,7 +88,8 @@ __all__ = [
86
88
  "pd_fill_nat",
87
89
  "pd_round_columns",
88
90
 
89
- # 数据类型转换类
91
+ # 数据转换类
92
+ "pd_convert_series",
90
93
  "pd_cal_date_diff",
91
94
  "pd_convert_columns",
92
95
  "pd_convert_decimal",
@@ -1,15 +1,18 @@
1
+ import time
2
+ import sys
3
+ from concurrent.futures import ThreadPoolExecutor , TimeoutError
4
+
5
+
1
6
  class FuncguardTimeoutError(Exception):
2
7
  """
3
8
  funcguard库专用的超时异常类。
4
-
9
+
5
10
  为了避免与concurrent.futures.TimeoutError和Python内置TimeoutError的命名冲突,
6
11
  特定义此异常类来明确表示这是funcguard库抛出的函数执行超时异常。
7
12
  这样用户可以清晰地区分异常来源,并进行针对性的异常处理。
8
13
  """
9
14
  pass
10
15
 
11
- import time
12
- from concurrent.futures import ThreadPoolExecutor , TimeoutError
13
16
 
14
17
  # 计算函数运行时间
15
18
  def timeout_handler( func, args = (), kwargs = None, execution_timeout = 90 ):
@@ -86,3 +89,86 @@ def retry_function( func , max_retries = 5 , execute_timeout = 90 , task_name =
86
89
  if last_exception:
87
90
  raise last_exception # 重新抛出最后一个异常
88
91
  return None
92
+
93
+
94
+ # 交互式选择菜单
95
+ def ask_select(
96
+ options: dict,
97
+ default_key = None,
98
+ prompt: str = "请选择",
99
+ timeout: int = 5,
100
+ ):
101
+ """
102
+ 显示一个数字选择菜单,接受用户输入,超时自动返回默认值。
103
+
104
+ 参数:
105
+ options: 字典,键为选项标识(任意类型),值为显示文本
106
+ 例如: {True: "需要填写属性", False: "不需要填写属性", "all": "不限制"}
107
+ default_key: 超时或输入无效时的默认返回值,若为None则使用最后一个选项的键
108
+ prompt: 提示语前缀
109
+ timeout: 超时时间(秒),默认5秒
110
+
111
+ 返回:
112
+ 用户选择的选项键(options中的某个键),或default_key
113
+
114
+ 示例:
115
+ >>> result = ask_select(
116
+ ... {True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
117
+ ... default_key="all",
118
+ ... prompt="请选择属性填写模式",
119
+ ... timeout=5,
120
+ ... )
121
+ """
122
+ # 确保选项非空
123
+ if not options:
124
+ raise ValueError("options字典不能为空")
125
+
126
+ # 设置默认值
127
+ if default_key is None:
128
+ default_key = list(options.keys())[-1]
129
+
130
+ # 构建选项列表(保持字典顺序)
131
+ items = list(options.items())
132
+
133
+ # 显示选项
134
+ option_lines = ", ".join([f"{i+1}-{label}" for i, (_, label) in enumerate(items)])
135
+ default_label = options.get(default_key, default_key)
136
+ print(f"{prompt} ({option_lines}),{timeout} 秒后自动选择[{default_label}]: ", end="", flush=True)
137
+
138
+ # 使用线程实现跨平台超时输入
139
+ from threading import Thread
140
+ from queue import Queue, Empty
141
+
142
+ result_queue = Queue()
143
+
144
+ def input_thread():
145
+ try:
146
+ user_input = input().strip()
147
+ result_queue.put(user_input)
148
+ except EOFError:
149
+ result_queue.put(None)
150
+
151
+ thread = Thread(target=input_thread, daemon=True)
152
+ thread.start()
153
+ thread.join(timeout)
154
+
155
+ try:
156
+ user_input = result_queue.get_nowait()
157
+ except Empty:
158
+ user_input = None
159
+
160
+ if user_input is None:
161
+ print(f"\n超时,自动选择[{default_label}]")
162
+ return default_key
163
+
164
+ # 验证输入
165
+ try:
166
+ choice = int(user_input)
167
+ if 1 <= choice <= len(items):
168
+ return items[choice - 1][0]
169
+ except ValueError:
170
+ pass
171
+
172
+ # 输入无效,返回默认值
173
+ print(f"输入无效,使用默认选项[{default_label}]")
174
+ return default_key
@@ -2,6 +2,7 @@ import pandas as pd
2
2
  from .fill_round import fill_na, round_columns
3
3
  from .date_utils import fill_nat, cal_date_diff
4
4
  from .convert_utils import (
5
+ convert_series,
5
6
  convert_columns,
6
7
  convert_decimal,
7
8
  convert_numeric_series,
@@ -31,7 +32,8 @@ __all__ = [
31
32
  'round_columns',
32
33
  'cal_date_diff',
33
34
 
34
- # 数据类型转换类
35
+ # 数据转换类
36
+ 'convert_series',
35
37
  'convert_columns',
36
38
  'convert_decimal',
37
39
  'convert_numeric_series',
@@ -1,6 +1,6 @@
1
1
  import pandas as pd
2
2
  from decimal import Decimal
3
- from typing import Union, List, Dict, Any, Optional
3
+ from typing import Union, List, Dict, Any, Optional, Literal
4
4
  from pandas import (
5
5
  Int64Dtype,
6
6
  Float64Dtype,
@@ -10,6 +10,47 @@ from pandas import (
10
10
  from .json_utils import json_loads
11
11
 
12
12
 
13
+ def convert_series(
14
+ data: pd.Series,
15
+ return_type: Literal["dict", "df", "series"] = "dict"
16
+ ) -> Union[Dict[Any, Union[int, float]], pd.DataFrame, pd.Series]:
17
+ """
18
+ 将 pandas Series 格式化为指定的返回类型。
19
+
20
+ 参数:
21
+ - data (pd.Series):输入的 pandas Series 数据。
22
+ - return_type (str):返回类型,支持:
23
+ - "dict":返回字典(默认)。
24
+ - "df":返回 DataFrame。
25
+ - "series":返回 pandas Series。
26
+
27
+ 返回:
28
+ - Union[Dict[Any, Union[int, float]], pd.DataFrame, pd.Series]:
29
+ 根据 return_type 返回格式化后的结果。
30
+
31
+ 示例:
32
+ >>> series = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
33
+ >>> convert_series(series, "dict")
34
+ {'a': 1, 'b': 2, 'c': 3}
35
+ >>> convert_series(series, "df")
36
+ 0
37
+ a 1
38
+ b 2
39
+ c 3
40
+ >>> convert_series(series, "series")
41
+ a 1
42
+ b 2
43
+ c 3
44
+ dtype: int64
45
+ """
46
+
47
+ if return_type == "dict":
48
+ return data.to_dict()
49
+ elif return_type == "df":
50
+ return data.to_frame()
51
+ else: # "series"
52
+ return data
53
+
13
54
 
14
55
  # 数据类型映射常量
15
56
  TYPE_MAPPING = {
@@ -1,4 +1,3 @@
1
-
2
1
  """
3
2
  聚合(aggregation)操作工具模块。
4
3
 
@@ -7,8 +6,9 @@ sum、mean、max、min、count、median、std、var等聚合计算。
7
6
  """
8
7
 
9
8
  import pandas as pd
10
- from typing import Any, Dict, Optional, Union, List, Tuple
9
+ from typing import Any, Dict, Optional, Union, List, Tuple, Literal
11
10
  from .mask_utils import build_single_mask, build_base_mask
11
+ from ..convert_utils import convert_series
12
12
 
13
13
 
14
14
  def group_agg(
@@ -21,8 +21,8 @@ def group_agg(
21
21
  logic: str = "and",
22
22
  true_mask: Optional[pd.Series] = None,
23
23
  false_mask: Optional[pd.Series] = None,
24
- to_dict: bool = True
25
- ) -> Dict[Any, Union[int, float]]:
24
+ return_type: Literal["dict", "df", "series"] = "dict"
25
+ ) -> Union[Dict[Any, Union[int, float]], pd.DataFrame, pd.Series]:
26
26
  """
27
27
  按指定列分组,对另一列进行聚合统计。
28
28
 
@@ -39,10 +39,11 @@ def group_agg(
39
39
  - logic (str):逻辑操作类型,"and" 或 "or",默认为 "and"。
40
40
  - true_mask (pd.Series):初始True掩码,默认为None。
41
41
  - false_mask (pd.Series):初始False掩码,默认为None。
42
- - to_dict (bool):是否将结果转换为字典,默认为True。
42
+ - return_type (str):返回类型,支持 "dict"(字典)、"df"(DataFrame)和 "series"(Series),
43
+ 默认为 "dict"。
43
44
 
44
45
  返回:
45
- - Dict[Any, Union[int, float]]:以分组值为键,聚合结果为值的字典。
46
+ - Union[Dict[Any, Union[int, float]], pd.Series]:以分组值为键,聚合结果为值的字典或Series。
46
47
 
47
48
  示例:
48
49
  >>> group_agg(df, "category", "amount", "sum")
@@ -80,9 +81,6 @@ def group_agg(
80
81
  result_series = result_series.sort_values(ascending=True)
81
82
  elif sort == "desc":
82
83
  result_series = result_series.sort_values(ascending=False)
83
-
84
- # 转换为字典返回
85
- if to_dict:
86
- return result_series.to_dict()
87
- else:
88
- return result_series
84
+
85
+ # 格式化并返回结果
86
+ return convert_series(result_series, return_type)
@@ -1,6 +1,7 @@
1
1
  import pandas as pd
2
- from typing import List, Tuple, Union, Optional, Dict, Any, Mapping
2
+ from typing import List, Tuple, Union, Optional, Dict, Any, Mapping, Literal
3
3
  from .mask_utils import build_single_mask, build_base_mask
4
+ from ..convert_utils import convert_series
4
5
 
5
6
 
6
7
  def value_counts(
@@ -13,8 +14,8 @@ def value_counts(
13
14
  logic: str = "and",
14
15
  true_mask: Optional[pd.Series] = None,
15
16
  false_mask: Optional[pd.Series] = None,
16
- to_dict: bool = True
17
- ) -> Mapping[Any, Union[int, float]]:
17
+ return_type: Literal["dict", "df", "series"] = "dict"
18
+ ) -> Union[Mapping[Any, Union[int, float]], pd.DataFrame, pd.Series]:
18
19
  """
19
20
  统计DataFrame指定列中不同值的计数数据。
20
21
 
@@ -30,10 +31,11 @@ def value_counts(
30
31
  - logic (str):逻辑操作类型,"and" 或 "or",默认为 "and"。
31
32
  - true_mask (pd.Series):初始True掩码,默认为None。
32
33
  - false_mask (pd.Series):初始False掩码,默认为None。
33
- - to_dict (bool):是否将结果转换为字典,默认为True。
34
+ - return_type (str):返回类型,支持 "dict"(字典)、"df"(DataFrame)和 "series"(Series),
35
+ 默认为 "dict"。
34
36
 
35
37
  返回:
36
- - Mapping[Any, Union[int, float]]:以值为键,计数/百分比为值的字典。
38
+ - Union[Mapping[Any, Union[int, float]], pd.Series]:以值为键,计数/百分比为值的字典或Series。
37
39
 
38
40
  示例:
39
41
  >>> value_counts(df, "status")
@@ -76,11 +78,8 @@ def value_counts(
76
78
  dropna=dropna
77
79
  )
78
80
 
79
- # 转换为字典返回
80
- if to_dict:
81
- return result_series.to_dict()
82
- else:
83
- return result_series
81
+ # 格式化并返回结果
82
+ return convert_series(result_series, return_type)
84
83
 
85
84
 
86
85
  def count(
@@ -1,5 +1,5 @@
1
1
  import pandas as pd
2
- from typing import Any, Dict, List, Tuple, Union, Optional, Mapping
2
+ from typing import Any, Dict, List, Tuple, Union, Optional, Mapping, Literal
3
3
  from .mask_utils import build_single_mask as _original_build_single_mask, build_base_mask as _original_build_base_mask, combine_masks
4
4
  from .count_utils import count as _original_count, value_counts as _original_value_counts
5
5
  from .agg_utils import group_agg as _original_group_agg
@@ -43,8 +43,8 @@ class DataFrameStatistics:
43
43
  self._false_mask = pd.Series([False] * self._length, index=self._index)
44
44
 
45
45
 
46
- def build_base_mask(self, conditions: List[Tuple], logic: str = "and",
47
- true_mask: Optional[pd.Series] = None,
46
+ def build_base_mask(self, conditions: List[Tuple], logic: str = "and",
47
+ true_mask: Optional[pd.Series] = None,
48
48
  false_mask: Optional[pd.Series] = None) -> pd.Series:
49
49
  """
50
50
  构建基础查询条件掩码,自动使用内部掩码参数
@@ -54,7 +54,7 @@ class DataFrameStatistics:
54
54
  - logic (str):逻辑操作类型,"and" 或 "or",默认为 "and"
55
55
  - true_mask (pd.Series):初始True掩码,默认为None(使用内部缓存)
56
56
  - false_mask (pd.Series):初始False掩码,默认为None(使用内部缓存)
57
-
57
+
58
58
  返回:
59
59
  - pd.Series:布尔掩码,True表示符合条件的行
60
60
  """
@@ -69,10 +69,10 @@ class DataFrameStatistics:
69
69
  def build_single_mask(self, condition: Tuple) -> pd.Series:
70
70
  """
71
71
  构建单个掩码,用于简单条件判断,自动使用内部DataFrame
72
-
72
+
73
73
  参数:
74
74
  - condition (Tuple):条件元组,包含(列名, 运算符, 值)
75
-
75
+
76
76
  返回:
77
77
  - pd.Series:布尔掩码,True表示符合条件的行
78
78
  **注意**:此Series是通过原生pandas表达式(df[col] > value)直接返回,
@@ -114,8 +114,8 @@ class DataFrameStatistics:
114
114
  logic: str = "and",
115
115
  true_mask: Optional[pd.Series] = None,
116
116
  false_mask: Optional[pd.Series] = None,
117
- to_dict: bool = True
118
- ) -> Mapping[Any, Union[int, float]]:
117
+ return_type: Literal["dict", "df", "series"] = "dict"
118
+ ) -> Union[Mapping[Any, Union[int, float]], pd.DataFrame, pd.Series]:
119
119
  """
120
120
  统计指定列中不同值的计数数据,自动使用内部掩码参数
121
121
 
@@ -129,11 +129,11 @@ class DataFrameStatistics:
129
129
  - logic (str):逻辑操作类型,"and" 或 "or",默认为 "and"
130
130
  - true_mask (pd.Series):初始True掩码,默认为None(使用内部缓存)
131
131
  - false_mask (pd.Series):初始False掩码,默认为None(使用内部缓存)
132
- - to_dict (bool):是否将结果转换为字典,默认为True。
132
+ - return_type (str):返回类型,支持 "dict"(字典)、"df"(DataFrame)和 "series"(Series),
133
+ 默认为 "dict"。
133
134
 
134
-
135
135
  返回:
136
- - Mapping[Any, Union[int, float]]:以值为键,计数/百分比为值的字典
136
+ - Union[Mapping[Any, Union[int, float]], pd.DataFrame, pd.Series]:以值为键,计数/百分比为值的字典、DataFrame或Series
137
137
 
138
138
  示例:
139
139
  >>> stats.value_counts("status")
@@ -154,7 +154,7 @@ class DataFrameStatistics:
154
154
  false_mask = self._false_mask
155
155
  return _original_value_counts(
156
156
  self._df, column, mode, sort, dropna,
157
- conditions, logic, true_mask, false_mask, to_dict
157
+ conditions, logic, true_mask, false_mask, return_type
158
158
  )
159
159
 
160
160
 
@@ -168,8 +168,8 @@ class DataFrameStatistics:
168
168
  logic: str = "and",
169
169
  true_mask: Optional[pd.Series] = None,
170
170
  false_mask: Optional[pd.Series] = None,
171
- to_dict: bool = True
172
- ) -> Dict[Any, Union[int, float]]:
171
+ return_type: Literal["dict", "df", "series"] = "dict"
172
+ ) -> Union[Dict[Any, Union[int, float]], pd.DataFrame, pd.Series]:
173
173
  """
174
174
  按指定列分组,对另一列进行聚合统计,自动使用内部掩码参数
175
175
 
@@ -184,11 +184,11 @@ class DataFrameStatistics:
184
184
  - logic (str):逻辑操作类型,"and" 或 "or",默认为 "and"
185
185
  - true_mask (pd.Series):初始True掩码,默认为None(使用内部缓存)
186
186
  - false_mask (pd.Series):初始False掩码,默认为None(使用内部缓存)
187
- - to_dict (bool):是否将结果转换为字典,默认为True。
187
+ - return_type (str):返回类型,支持 "dict"(字典)、"df"(DataFrame)和 "series"(Series),
188
+ 默认为 "dict"。
188
189
 
189
-
190
190
  返回:
191
- - Dict[Any, Union[int, float]]:以分组值为键,聚合结果为值的字典
191
+ - Union[Dict[Any, Union[int, float]], pd.DataFrame, pd.Series]:以分组值为键,聚合结果为值的字典、DataFrame或Series
192
192
 
193
193
  示例:
194
194
  >>> stats.group_agg("category", "amount", "sum")
@@ -205,7 +205,7 @@ class DataFrameStatistics:
205
205
  false_mask = self._false_mask
206
206
  return _original_group_agg(
207
207
  self._df, group_col, agg_col, agg_func, sort,
208
- conditions, logic, true_mask, false_mask, to_dict
208
+ conditions, logic, true_mask, false_mask, return_type
209
209
  )
210
210
 
211
211
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: funcguard
3
- Version: 0.2.42
3
+ Version: 0.2.44
4
4
  Summary: FuncGuard是一个Python库,提供函数执行超时控制、重试机制、HTTP请求封装和格式化打印工具。
5
5
  Home-page: https://github.com/tinycen/funcguard
6
6
  Author: tinycen
@@ -34,7 +34,7 @@ FuncGuard是一个Python库,提供了函数执行超时控制和重试机制
34
34
 
35
35
  | 分类 | 功能描述 | 文档 |
36
36
  |------|----------|------|
37
- | **核心功能** | 函数执行超时控制、函数执行失败自动重试 | - |
37
+ | **核心功能** | 函数执行超时控制、函数执行失败自动重试、交互式选择菜单 | - |
38
38
  | **网络请求** | HTTP请求封装(支持自动重试)、MD5哈希、Basic Auth编码 | [查看](./docs/network.md) |
39
39
  | **时间工具** | 时间日志记录、耗时统计、执行时间监控和警告、时间等待(带倒计时) | [查看](./docs/time_utils.md) |
40
40
  | **打印工具** | 格式化分隔线、块打印、标题打印、进度条显示 | - |
@@ -95,6 +95,41 @@ except Exception as e:
95
95
  print(f"重试后仍然失败: {e}")
96
96
  ```
97
97
 
98
+ ### 交互式选择菜单
99
+
100
+ 使用 `ask_select` 函数创建一个带数字编号的交互式选择菜单,支持超时自动选择:
101
+
102
+ ```python
103
+ from funcguard import ask_select
104
+
105
+ # 基础用法 - 选择属性填写模式
106
+ result = ask_select(
107
+ options={True: "需要填写属性", False: "不需要填写属性", "all": "不限制"},
108
+ default_key="all",
109
+ prompt="请选择属性填写模式",
110
+ timeout=5
111
+ )
112
+ print(f"用户选择: {result}") # 返回 True, False 或 "all"
113
+
114
+ # 选择部署环境
115
+ env = ask_select(
116
+ options={"dev": "开发环境", "test": "测试环境", "prod": "生产环境"},
117
+ default_key="dev",
118
+ prompt="请选择部署环境",
119
+ timeout=3
120
+ )
121
+ print(f"当前环境: {env}")
122
+
123
+ # 选择数量(使用整数作为键)
124
+ count = ask_select(
125
+ options={10: "10条", 50: "50条", 100: "100条"},
126
+ default_key=50,
127
+ prompt="查询数量",
128
+ timeout=5
129
+ )
130
+ print(f"查询 {count} 条数据")
131
+ ```
132
+
98
133
  ### HTTP请求
99
134
 
100
135
  FuncGuard 提供了强大的 HTTP 请求功能,支持自动重试、请求日志记录、以及 curl_cffi 兜底(用于绕过反爬虫检测)。详细文档请参考 [network.md](docs/network.md)。
@@ -496,6 +531,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
496
531
  |-----------|----------|
497
532
  | `timeout_handler` | 函数执行超时控制 |
498
533
  | `retry_function` | 函数执行失败自动重试 |
534
+ | `ask_select` | 交互式数字选择菜单(支持超时自动选择) |
499
535
 
500
536
  ### 网络请求
501
537
 
@@ -542,7 +578,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
542
578
  | 函数/类名 | 功能说明 | 文档 |
543
579
  |-----------|----------|------|
544
580
  | `pd_fill_na` / `pd_fill_nat` | 数据填充 | [查看](docs/pandas/fill.md) |
545
- | `pd_convert_columns` / `pd_convert_decimal` / `pd_convert_numeric_series` / `pd_convert_str_datetime` / `pd_convert_datetime_str` | 类型转换 | [查看](docs/pandas/convert.md) |
581
+ | `pd_convert_columns` / `pd_convert_decimal` / `pd_convert_numeric_series` / `pd_convert_str_datetime` / `pd_convert_datetime_str` / `pd_convert_series` | 类型转换 | [查看](docs/pandas/convert.md) |
546
582
  | `pd_load_json` | JSON解析 | [查看](docs/pandas/json.md) |
547
583
  | `pd_filter` | 数据筛选 | [查看](docs/pandas/filter.md) |
548
584
  | `pd_count` / `pd_value_counts` | 条件计数统计 | [查看](docs/pandas/count.md) |
@@ -9,7 +9,7 @@ except FileNotFoundError:
9
9
 
10
10
  setup(
11
11
  name='funcguard',
12
- version='0.2.42',
12
+ version='0.2.44',
13
13
  packages=find_packages(),
14
14
  install_requires=[
15
15
  'requests',
File without changes
File without changes
File without changes