pytbox 0.0.5__py3-none-any.whl → 0.0.6__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.

Potentially problematic release.


This version of pytbox might be problematic. Click here for more details.

@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from pytbox.utils.load_config import load_config_by_file
6
+
7
+ from jinja2 import Environment, FileSystemLoader
8
+
9
+
10
+ jinja2_path = Path(__file__).parent / 'jinja2'
11
+ env = Environment(loader=FileSystemLoader(jinja2_path))
12
+
13
+ ping_template = env.get_template('input.ping/ping.toml.j2')
14
+ prometheus_template = env.get_template('input.prometheus/prometheus.toml.j2')
15
+
16
+
17
+ class BuildConfig:
18
+ '''
19
+ 生成配置
20
+
21
+ Args:
22
+ instances (_type_): _description_
23
+ output_dir (_type_): _description_
24
+ '''
25
+ def __init__(self, instances, output_dir):
26
+ self.instances = load_config_by_file(instances)
27
+ self.output_dir = output_dir
28
+
29
+
30
+
31
+ def ping(self):
32
+ instances = self.instances['ping']['instance']
33
+ render_data = ping_template.render(instances=instances)
34
+ target_dir = Path(self.output_dir) / 'input.ping'
35
+ if not target_dir.exists():
36
+ target_dir.mkdir(parents=True, exist_ok=True)
37
+
38
+ with open(Path(self.output_dir) / 'input.ping' / 'ping.toml', 'w', encoding='utf-8') as f:
39
+ f.write(render_data)
40
+
41
+ def prometheus(self):
42
+ instances = self.instances['prometheus']['urls']
43
+ render_data = prometheus_template.render(instances=instances)
44
+ target_dir = Path(self.output_dir) / 'input.prometheus'
45
+ if not target_dir.exists():
46
+ target_dir.mkdir(parents=True, exist_ok=True)
47
+
48
+ with open(Path(self.output_dir) / 'input.prometheus' / 'prometheus.toml', 'w', encoding='utf-8') as f:
49
+ f.write(render_data)
50
+
51
+ def run(self):
52
+ # self.ping()
53
+ self.prometheus()
pytbox/cli/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """
2
+ Pytbox CLI 包
3
+ """
4
+
5
+ from .main import main
6
+
7
+ __all__ = ['main']
@@ -0,0 +1,7 @@
1
+ """
2
+ Categraf CLI 模块
3
+ """
4
+
5
+ from .commands import categraf_group
6
+
7
+ __all__ = ['categraf_group']
@@ -0,0 +1,55 @@
1
+ """
2
+ Categraf 相关命令 - 支持 rich 美化输出
3
+ """
4
+
5
+ import shutil
6
+ from pathlib import Path
7
+ import click
8
+ from ...utils.richutils import RichUtils
9
+ from ...categraf.build_config import BuildConfig
10
+
11
+
12
+
13
+ rich_utils = RichUtils()
14
+
15
+
16
+ @click.group()
17
+ def categraf_group():
18
+ """Categraf 配置管理工具"""
19
+ pass
20
+
21
+
22
+ @categraf_group.command('get-instances')
23
+ @click.option('--output-dir', '-o', type=click.Path(exists=True), default='.')
24
+ def get_instances(output_dir):
25
+ """获取 Categraf 实例配置"""
26
+ instances_template_path = Path(__file__).parent.parent.parent / 'categraf' / 'instances.toml'
27
+ dest_path = Path(output_dir) / 'instances.toml'
28
+ shutil.copy(instances_template_path, dest_path)
29
+ rich_utils.print(msg=f'已将 {instances_template_path} 复制到 {dest_path}', style='info')
30
+
31
+
32
+ @categraf_group.command('build-config')
33
+ @click.option('--instances', '-i', type=click.Path(exists=True), default='.')
34
+ @click.option('--output-dir', '-o', type=click.Path(exists=True), default='.')
35
+ def build_config(instances, output_dir):
36
+ '''
37
+ 生成配置
38
+
39
+ Args:
40
+ instances (_type_): _description_
41
+ output_dir (_type_): _description_
42
+ '''
43
+ # ping_template_path = Path(__file__).parent.parent.parent / 'categraf' / 'ping.toml'
44
+ # dest_path = Path(output_dir) / 'ping.toml'
45
+ # shutil.copy(ping_template_path, dest_path)
46
+ # rich_utils.print(msg=f'已将 {ping_template_path} 复制到 {dest_path}', style='info')
47
+ # 获取 instances 和 output_dir 的绝对路径
48
+ instances_abs = str(Path(instances).resolve())
49
+ output_dir_abs = str(Path(output_dir).resolve())
50
+
51
+ rich_utils.print(msg=f'instances 绝对路径: {instances_abs}', style='info')
52
+ rich_utils.print(msg=f'output_dir 绝对路径: {output_dir_abs}', style='info')
53
+
54
+ build_config = BuildConfig(instances_abs, output_dir_abs)
55
+ build_config.run()
@@ -0,0 +1,6 @@
1
+ """
2
+ CLI 通用模块
3
+ """
4
+
5
+ from .options import *
6
+ from .utils import *
@@ -0,0 +1,42 @@
1
+ """
2
+ 通用的 Click 选项定义
3
+ """
4
+
5
+ import click
6
+
7
+ # 通用选项
8
+ output_option = click.option(
9
+ '--output', '-o',
10
+ type=click.Path(),
11
+ help='输出到文件'
12
+ )
13
+
14
+ format_option = click.option(
15
+ '--format', 'output_format',
16
+ type=click.Choice(['toml', 'json', 'yaml']),
17
+ default='toml',
18
+ help='输出格式'
19
+ )
20
+
21
+ data_option = click.option(
22
+ '--data', '-d',
23
+ help='JSON 格式的模板变量'
24
+ )
25
+
26
+ data_file_option = click.option(
27
+ '--data-file',
28
+ type=click.Path(exists=True),
29
+ help='包含模板变量的 JSON 文件'
30
+ )
31
+
32
+ verbose_option = click.option(
33
+ '--verbose', '-v',
34
+ is_flag=True,
35
+ help='显示详细信息'
36
+ )
37
+
38
+ quiet_option = click.option(
39
+ '--quiet', '-q',
40
+ is_flag=True,
41
+ help='静默模式,只显示错误'
42
+ )
@@ -0,0 +1,269 @@
1
+ """
2
+ CLI 通用工具函数 - 集成 rich 支持
3
+ """
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Optional, Dict, Any, Union
8
+
9
+ try:
10
+ from rich.console import Console
11
+
12
+ from rich.panel import Panel
13
+ from rich.table import Table
14
+ from rich.progress import track
15
+ from rich.syntax import Syntax
16
+ from rich.tree import Tree
17
+ RICH_AVAILABLE = True
18
+ except ImportError:
19
+ RICH_AVAILABLE = False
20
+
21
+ # 如果 rich 不可用,使用标准输出
22
+ import click
23
+
24
+
25
+ class Logger:
26
+ """增强的日志器,支持 rich 格式化输出"""
27
+
28
+ def __init__(self, verbose: bool = False, quiet: bool = False):
29
+ self.verbose = verbose
30
+ self.quiet = quiet
31
+
32
+ if RICH_AVAILABLE:
33
+ self.console = Console()
34
+ else:
35
+ self.console = None
36
+
37
+ def info(self, message: str, style: str = "info"):
38
+ """信息日志"""
39
+ if self.quiet:
40
+ return
41
+
42
+ if RICH_AVAILABLE:
43
+ if style == "success":
44
+ self.console.print(f"✅ {message}", style="bold green")
45
+ elif style == "warning":
46
+ self.console.print(f"⚠️ {message}", style="bold yellow")
47
+ elif style == "error":
48
+ self.console.print(f"❌ {message}", style="bold red")
49
+ else:
50
+ self.console.print(f"ℹ️ {message}", style="bold blue")
51
+ else:
52
+ click.echo(message)
53
+
54
+ def success(self, message: str):
55
+ """成功日志"""
56
+ self.info(message, "success")
57
+
58
+ def warning(self, message: str):
59
+ """警告日志"""
60
+ self.info(message, "warning")
61
+
62
+ def error(self, message: str):
63
+ """错误日志"""
64
+ if RICH_AVAILABLE:
65
+ self.console.print(f"❌ {message}", style="bold red", err=True)
66
+ else:
67
+ click.echo(f"错误: {message}", err=True)
68
+
69
+ def debug(self, message: str):
70
+ """调试日志"""
71
+ if self.verbose:
72
+ if RICH_AVAILABLE:
73
+ self.console.print(f"🔍 {message}", style="dim")
74
+ else:
75
+ click.echo(f"DEBUG: {message}")
76
+
77
+ def print_panel(self, content: str, title: str = "", style: str = "info"):
78
+ """打印面板"""
79
+ if self.quiet:
80
+ return
81
+
82
+ if RICH_AVAILABLE:
83
+ if style == "success":
84
+ panel_style = "green"
85
+ elif style == "warning":
86
+ panel_style = "yellow"
87
+ elif style == "error":
88
+ panel_style = "red"
89
+ else:
90
+ panel_style = "blue"
91
+
92
+ panel = Panel(content, title=title, border_style=panel_style)
93
+ self.console.print(panel)
94
+ else:
95
+ if title:
96
+ click.echo(f"=== {title} ===")
97
+ click.echo(content)
98
+
99
+ def print_table(self, data: list, headers: list, title: str = ""):
100
+ """打印表格"""
101
+ if self.quiet:
102
+ return
103
+
104
+ if RICH_AVAILABLE:
105
+ table = Table(title=title, show_header=True, header_style="bold magenta")
106
+
107
+ for header in headers:
108
+ table.add_column(header)
109
+
110
+ for row in data:
111
+ table.add_row(*[str(cell) for cell in row])
112
+
113
+ self.console.print(table)
114
+ else:
115
+ if title:
116
+ click.echo(f"=== {title} ===")
117
+ click.echo("\t".join(headers))
118
+ for row in data:
119
+ click.echo("\t".join(str(cell) for cell in row))
120
+
121
+ def print_syntax(self, code: str, language: str = "toml", title: str = ""):
122
+ """打印语法高亮的代码"""
123
+ if self.quiet:
124
+ return
125
+
126
+ if RICH_AVAILABLE:
127
+ syntax = Syntax(code, language, theme="monokai", line_numbers=True)
128
+ if title:
129
+ panel = Panel(syntax, title=title, border_style="blue")
130
+ self.console.print(panel)
131
+ else:
132
+ self.console.print(syntax)
133
+ else:
134
+ if title:
135
+ click.echo(f"=== {title} ===")
136
+ click.echo(code)
137
+
138
+
139
+ # 全局日志器实例
140
+ logger = Logger()
141
+
142
+
143
+ def set_logger_config(verbose: bool = False, quiet: bool = False):
144
+ """设置日志器配置"""
145
+ global logger
146
+ logger = Logger(verbose=verbose, quiet=quiet)
147
+
148
+
149
+ def handle_error(error: Exception):
150
+ """统一的错误处理"""
151
+ logger.error(str(error))
152
+
153
+
154
+ def write_output(content: str, output_path: Optional[str] = None, content_type: str = "text"):
155
+ """统一的输出处理"""
156
+ if output_path:
157
+ try:
158
+ output_file = Path(output_path)
159
+ output_file.parent.mkdir(parents=True, exist_ok=True)
160
+
161
+ with open(output_file, 'w', encoding='utf-8') as f:
162
+ f.write(content)
163
+
164
+ logger.success(f"内容已保存到: {output_path}")
165
+ logger.debug(f"文件大小: {len(content)} 字符")
166
+
167
+ except Exception as e:
168
+ logger.error(f"保存文件失败: {e}")
169
+ raise
170
+ else:
171
+ # 根据内容类型选择合适的显示方式
172
+ if content_type == "json":
173
+ logger.print_syntax(content, "json", "JSON 内容")
174
+ elif content_type == "yaml":
175
+ logger.print_syntax(content, "yaml", "YAML 内容")
176
+ elif content_type == "toml":
177
+ logger.print_syntax(content, "toml", "TOML 内容")
178
+ elif content_type == "template":
179
+ logger.print_syntax(content, "jinja2", "模板内容")
180
+ else:
181
+ logger.print_panel(content, "输出内容")
182
+
183
+
184
+ def load_template_vars(data_str: Optional[str] = None, data_file: Optional[str] = None) -> Dict[str, Any]:
185
+ """加载模板变量"""
186
+ template_vars = {}
187
+
188
+ try:
189
+ if data_file:
190
+ logger.debug(f"从文件加载变量: {data_file}")
191
+ with open(data_file, 'r', encoding='utf-8') as f:
192
+ file_vars = json.load(f)
193
+ template_vars.update(file_vars)
194
+ logger.debug(f"从文件加载了 {len(file_vars)} 个变量")
195
+
196
+ if data_str:
197
+ logger.debug("从命令行加载变量")
198
+ cli_vars = json.loads(data_str)
199
+ template_vars.update(cli_vars)
200
+ logger.debug(f"从命令行加载了 {len(cli_vars)} 个变量")
201
+
202
+ if template_vars:
203
+ logger.debug(f"总计加载变量: {list(template_vars.keys())}")
204
+
205
+ return template_vars
206
+
207
+ except json.JSONDecodeError as e:
208
+ raise ValueError(f"JSON 格式错误: {e}")
209
+ except FileNotFoundError as e:
210
+ raise FileNotFoundError(f"数据文件不存在: {e}")
211
+ except Exception as e:
212
+ raise Exception(f"加载模板变量失败: {e}")
213
+
214
+
215
+ def show_progress(items, description: str = "处理中..."):
216
+ """显示进度条"""
217
+ if RICH_AVAILABLE and not logger.quiet:
218
+ return track(items, description=description)
219
+ else:
220
+ return items
221
+
222
+
223
+ def create_tree_view(data: dict, title: str = "数据结构") -> None:
224
+ """创建树形视图显示数据"""
225
+ if logger.quiet:
226
+ return
227
+
228
+ if RICH_AVAILABLE:
229
+ tree = Tree(title)
230
+
231
+ def add_dict_to_tree(node, data_dict):
232
+ for key, value in data_dict.items():
233
+ if isinstance(value, dict):
234
+ child = node.add(f"[bold blue]{key}[/bold blue]")
235
+ add_dict_to_tree(child, value)
236
+ elif isinstance(value, list):
237
+ child = node.add(f"[bold green]{key}[/bold green] ({len(value)} items)")
238
+ for i, item in enumerate(value):
239
+ if isinstance(item, dict):
240
+ item_node = child.add(f"[dim]Item {i}[/dim]")
241
+ add_dict_to_tree(item_node, item)
242
+ else:
243
+ child.add(f"[dim]{item}[/dim]")
244
+ else:
245
+ node.add(f"[yellow]{key}[/yellow]: [white]{value}[/white]")
246
+
247
+ add_dict_to_tree(tree, data)
248
+ logger.console.print(tree)
249
+ else:
250
+ # 简单的文本输出
251
+ logger.info(f"=== {title} ===")
252
+
253
+ def print_dict(data_dict, indent=0):
254
+ for key, value in data_dict.items():
255
+ prefix = " " * indent
256
+ if isinstance(value, dict):
257
+ click.echo(f"{prefix}{key}:")
258
+ print_dict(value, indent + 1)
259
+ elif isinstance(value, list):
260
+ click.echo(f"{prefix}{key}: ({len(value)} items)")
261
+ for item in value:
262
+ if isinstance(item, dict):
263
+ print_dict(item, indent + 1)
264
+ else:
265
+ click.echo(f"{prefix} - {item}")
266
+ else:
267
+ click.echo(f"{prefix}{key}: {value}")
268
+
269
+ print_dict(data)
@@ -0,0 +1,7 @@
1
+ """
2
+ 输出格式化器模块
3
+ """
4
+
5
+ from .output import OutputFormatter
6
+
7
+ __all__ = ['OutputFormatter']
@@ -0,0 +1,155 @@
1
+ """
2
+ 输出格式化器 - 支持多种格式和 rich 美化
3
+ """
4
+
5
+ import json
6
+ from typing import Any, Dict, Union
7
+ from ..common.utils import logger
8
+
9
+
10
+ class OutputFormatter:
11
+ """输出格式化器"""
12
+
13
+ @staticmethod
14
+ def format_data(data: Union[Dict[str, Any], list], format_type: str = 'toml') -> str:
15
+ """格式化数据
16
+
17
+ Args:
18
+ data: 要格式化的数据
19
+ format_type: 输出格式 ('toml', 'json', 'yaml')
20
+
21
+ Returns:
22
+ str: 格式化后的字符串
23
+
24
+ Raises:
25
+ ImportError: 缺少必要的依赖
26
+ ValueError: 不支持的格式
27
+ """
28
+ logger.debug(f"格式化数据为 {format_type} 格式")
29
+
30
+ if format_type == 'json':
31
+ return OutputFormatter._format_json(data)
32
+ elif format_type == 'yaml':
33
+ return OutputFormatter._format_yaml(data)
34
+ elif format_type == 'toml':
35
+ return OutputFormatter._format_toml(data)
36
+ else:
37
+ raise ValueError(f"不支持的格式: {format_type}")
38
+
39
+ @staticmethod
40
+ def _format_json(data: Any) -> str:
41
+ """格式化为 JSON"""
42
+ try:
43
+ result = json.dumps(data, indent=2, ensure_ascii=False)
44
+ logger.debug(f"JSON 格式化完成,长度: {len(result)} 字符")
45
+ return result
46
+ except Exception as e:
47
+ logger.error(f"JSON 格式化失败: {e}")
48
+ raise
49
+
50
+ @staticmethod
51
+ def _format_yaml(data: Any) -> str:
52
+ """格式化为 YAML"""
53
+ try:
54
+ import yaml
55
+ result = yaml.dump(
56
+ data,
57
+ default_flow_style=False,
58
+ allow_unicode=True,
59
+ sort_keys=False,
60
+ indent=2
61
+ )
62
+ logger.debug(f"YAML 格式化完成,长度: {len(result)} 字符")
63
+ return result
64
+ except ImportError:
65
+ error_msg = "需要安装 pyyaml: pip install pyyaml"
66
+ logger.error(error_msg)
67
+ raise ImportError(error_msg)
68
+ except Exception as e:
69
+ logger.error(f"YAML 格式化失败: {e}")
70
+ raise
71
+
72
+ @staticmethod
73
+ def _format_toml(data: Any) -> str:
74
+ """格式化为 TOML"""
75
+ try:
76
+ import toml
77
+ result = toml.dumps(data)
78
+ logger.debug(f"TOML 格式化完成,长度: {len(result)} 字符")
79
+ return result
80
+ except ImportError:
81
+ try:
82
+ # Python 3.11+ 的 tomllib 只能读取,不能写入
83
+ import tomllib
84
+ error_msg = "需要安装 toml 库来支持 TOML 输出: pip install toml"
85
+ logger.error(error_msg)
86
+ raise ImportError(error_msg)
87
+ except ImportError:
88
+ error_msg = "需要安装 toml: pip install toml"
89
+ logger.error(error_msg)
90
+ raise ImportError(error_msg)
91
+ except Exception as e:
92
+ logger.error(f"TOML 格式化失败: {e}")
93
+ raise
94
+
95
+ @staticmethod
96
+ def format_template_list(templates: list) -> str:
97
+ """格式化模板列表"""
98
+ if not templates:
99
+ return "未找到模板文件"
100
+
101
+ logger.debug(f"格式化 {len(templates)} 个模板")
102
+
103
+ # 按文件类型分组
104
+ groups = {}
105
+ for template in templates:
106
+ if '.' in template:
107
+ ext = template.split('.')[-1]
108
+ if ext not in groups:
109
+ groups[ext] = []
110
+ groups[ext].append(template)
111
+ else:
112
+ if 'other' not in groups:
113
+ groups['other'] = []
114
+ groups['other'].append(template)
115
+
116
+ result = []
117
+ result.append("可用模板:")
118
+
119
+ for ext, files in sorted(groups.items()):
120
+ result.append(f"\n{ext.upper()} 模板:")
121
+ for template in sorted(files):
122
+ result.append(f" - {template}")
123
+
124
+ return "\n".join(result)
125
+
126
+ @staticmethod
127
+ def format_config_summary(config: Dict[str, Any]) -> str:
128
+ """格式化配置摘要"""
129
+ logger.debug("生成配置摘要")
130
+
131
+ result = []
132
+ result.append("配置摘要:")
133
+
134
+ for service, service_config in config.items():
135
+ result.append(f"\n📊 {service.upper()} 服务:")
136
+
137
+ if isinstance(service_config, dict):
138
+ for key, value in service_config.items():
139
+ if isinstance(value, list):
140
+ result.append(f" {key}: {len(value)} 项")
141
+ # 显示前几个项目
142
+ for i, item in enumerate(value[:3]):
143
+ if isinstance(item, dict):
144
+ item_keys = list(item.keys())[:2] # 只显示前两个键
145
+ result.append(f" - 项目 {i+1}: {item_keys}")
146
+ else:
147
+ result.append(f" - {item}")
148
+ if len(value) > 3:
149
+ result.append(f" ... 还有 {len(value) - 3} 项")
150
+ else:
151
+ result.append(f" {key}: {value}")
152
+ else:
153
+ result.append(f" 值: {service_config}")
154
+
155
+ return "\n".join(result)
pytbox/cli/main.py ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Pytbox 主命令行入口
4
+ """
5
+
6
+ import click
7
+ from .categraf import categraf_group
8
+
9
+
10
+ @click.group()
11
+ @click.version_option()
12
+ def main():
13
+ """Pytbox 命令行工具集合"""
14
+ pass
15
+
16
+
17
+ # 注册子命令组
18
+ main.add_command(categraf_group, name='categraf')
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
pytbox/cli.py ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Pytbox 命令行工具 - 入口文件(保持向后兼容)
4
+ """
5
+
6
+ from pytbox.cli import main
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -930,9 +930,12 @@ class ExtensionsEndpoint(Endpoint):
930
930
  final_data = fields[name][0].get('value')[0]['text']
931
931
 
932
932
  elif isinstance(fields[name], int):
933
- # 将时间戳转换为时间字符串格式
934
- final_data = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(fields[name] / 1000 ))
935
-
933
+ if len(str(fields[name])) >= 12 and fields[name] > 10**11:
934
+ final_data = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(fields[name] / 1000))
935
+ elif len(str(fields[name])) == 10 and 10**9 < fields[name] < 10**11:
936
+ final_data = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(fields[name]))
937
+ else:
938
+ final_data = fields[name]
936
939
  elif isinstance(fields[name], dict):
937
940
  if fields[name].get('type') == 1:
938
941
  final_data = fields[name].get('value')[0]['text']
pytbox/log/logger.py CHANGED
@@ -85,7 +85,6 @@ class AppLogger:
85
85
  logger.info(f"[{caller_filename}:{caller_lineno}:{caller_function}] {message}")
86
86
  if self.enable_victorialog:
87
87
  r = self.victorialog.send_program_log(stream=self.stream, level="INFO", message=message, app_name=self.app_name, file_name=call_full_filename, line_number=caller_lineno, function_name=caller_function)
88
- print(r)
89
88
  if feishu_notify:
90
89
  self.feishu(message)
91
90
 
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ from typing import Literal
5
+ from rich.console import Console
6
+ from rich.theme import Theme
7
+
8
+
9
+ class RichUtils:
10
+
11
+ def __init__(self):
12
+ self.theme = Theme({
13
+ "info": "bold blue",
14
+ "warning": "bold yellow",
15
+ "danger": "bold red",
16
+ })
17
+ self.console = Console(theme=self.theme)
18
+
19
+
20
+ def print(self, msg: str, style: Literal['info', 'warning', 'danger']='info'):
21
+ self.console.print(msg, style=style)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytbox
3
- Version: 0.0.5
3
+ Version: 0.0.6
4
4
  Summary: A collection of Python integrations and utilities (Feishu, Dida365, VictoriaMetrics, ...)
5
5
  Author-email: mingming hou <houm01@foxmail.com>
6
6
  License: MIT
@@ -11,11 +11,17 @@ Requires-Dist: pydantic>=1.10
11
11
  Requires-Dist: onepasswordconnectsdk>=1.0.0
12
12
  Requires-Dist: loguru>=0.7.3
13
13
  Requires-Dist: chinese_calendar>=1.10.0
14
+ Requires-Dist: click>=8.0.0
15
+ Requires-Dist: rich>=12.0.0
14
16
  Provides-Extra: dev
15
17
  Requires-Dist: pytest; extra == "dev"
16
18
  Requires-Dist: black; extra == "dev"
17
19
  Requires-Dist: ruff; extra == "dev"
18
20
  Requires-Dist: python-dotenv; extra == "dev"
21
+ Provides-Extra: cli
22
+ Requires-Dist: jinja2>=3.0.0; extra == "cli"
23
+ Requires-Dist: pyyaml>=6.0; extra == "cli"
24
+ Requires-Dist: toml>=0.10.0; extra == "cli"
19
25
 
20
26
  # PytBox
21
27
 
@@ -1,26 +1,39 @@
1
1
  pytbox/base.py,sha256=_SpfeIiJE4xbQMsYghnMehcNzHP-mBfrKONX43b0OQk,1490
2
+ pytbox/cli.py,sha256=N775a0GK80IT2lQC2KRYtkZpIiu9UjavZmaxgNUgJhQ,160
2
3
  pytbox/dida365.py,sha256=pUMPB9AyLZpTTbaz2LbtzdEpyjvuGf4YlRrCvM5sbJo,10545
3
4
  pytbox/onepassword_connect.py,sha256=nD3xTl1ykQ4ct_dCRRF138gXCtk-phPfKYXuOn-P7Z8,3064
4
5
  pytbox/onepassword_sa.py,sha256=08iUcYud3aEHuQcUsem9bWNxdXKgaxFbMy9yvtr-DZQ,6995
5
6
  pytbox/alert/alert_handler.py,sha256=FePPQS4LyGphSJ0QMv0_pLWaXxEqsRlcTKMfUjtsNfk,5048
6
7
  pytbox/alert/ping.py,sha256=g36X0U3U8ndZqfpVIcuoxJJ0X5gST3I_IwjTQC1roHA,779
7
8
  pytbox/alicloud/sls.py,sha256=UR4GdI86dCKAFI2xt_1DELu7q743dpd3xrYtuNpfC5A,4065
9
+ pytbox/categraf/build_config.py,sha256=PQkxTgc8AORQJbkOrd-kJ8IC4USnp4IFQA9LZW0LBI4,1695
10
+ pytbox/cli/__init__.py,sha256=5ID4-oXrMsHFcfDsQeXDYeThPOuQ1Fl2x2kHWfgfOEw,67
11
+ pytbox/cli/main.py,sha256=S-DBp-1d0BCpvZ7jRE3bYmhKSiPpCJHFGsbdVF485BY,322
12
+ pytbox/cli/categraf/__init__.py,sha256=HfhDhWiWEuT5e6fXb6fs7UgoZPwn9WQ1wdFoza2muaI,96
13
+ pytbox/cli/categraf/commands.py,sha256=M-coJaHhb5I9fMW7OMWe9SMrs_RmSm4hSIJ1CPS0Ipc,1874
14
+ pytbox/cli/common/__init__.py,sha256=1_OE4q6OIUQkpwXBWqiKHr7SXxEu925hRgmd2hulIy4,70
15
+ pytbox/cli/common/options.py,sha256=Xv1wXja-fdaQVY6_FzvYRrXDozeTOJV6BL8zYIKJE9k,773
16
+ pytbox/cli/common/utils.py,sha256=0uQ5L1l5cySFheixB91B9ptq0p6tGsBhqvvm3ouRGbI,9050
17
+ pytbox/cli/formatters/__init__.py,sha256=4o85w4j-A-O1oBLvuE9q8AFiJ2C9rvB3MIKsy5VvdfQ,101
18
+ pytbox/cli/formatters/output.py,sha256=h5WhZlQk1rjmxEj88Jy5ODLcv6L5zfGUhks_3AWIkKU,5455
8
19
  pytbox/common/__init__.py,sha256=3JWfgCQZKZuSH5NCE7OCzKwq82pkyop9l7sH5YSNyfU,122
9
20
  pytbox/database/mongo.py,sha256=CSpHC7iR-M0BaVxXz5j6iXjMKPgXJX_G7MrjCj5Gm8Q,3478
10
21
  pytbox/database/victoriametrics.py,sha256=PfeshtlgZNfbiq7Fo4ibJruWYeAKryBXu8ckl8YC1jM,4389
11
22
  pytbox/feishu/client.py,sha256=kwGLseGT_iQUFmSqpuS2_77WmxtHstD64nXvktuQ3B4,5865
12
- pytbox/feishu/endpoints.py,sha256=z_nHGXAjlIyYdFnbAWY4hfzzHrENJvoNOqY9sA6-FLk,40009
23
+ pytbox/feishu/endpoints.py,sha256=KmLB7yq0mpJgkWsTgGCufrejrPGV6JP0_p1GE6Pp4yI,40264
13
24
  pytbox/feishu/errors.py,sha256=79qFAHZw7jDj3gnWAjI1-W4tB0q1_aSfdjee4xzXeuI,1179
14
25
  pytbox/feishu/helpers.py,sha256=jhSkHiUw4822QBXx2Jw8AksogZdakZ-3QqvC3lB3qEI,201
15
26
  pytbox/feishu/typing.py,sha256=3hWkJgOi-v2bt9viMxkyvNHsPgrbAa0aZOxsZYg2vdM,122
16
- pytbox/log/logger.py,sha256=N7KOM7Xl_FZI_RR8oggjV9sVph-Lrmspl-yBMJr2LLQ,7437
27
+ pytbox/log/logger.py,sha256=7ZisXRxLb_MVbIqlYHWoTbj1EA0Z4G5SZvITlt1IKW8,7416
17
28
  pytbox/log/victorialog.py,sha256=gffEiq38adv9sC5oZeMcyKghd3SGfRuqtZOFuqHQF6E,4139
18
29
  pytbox/utils/env.py,sha256=jO_-BKbGuDU7lIL9KYkcxGCzQwTXfxD4mIYtSAjREmI,622
19
30
  pytbox/utils/load_config.py,sha256=wNCDPLH7xet5b9pUlTz6VsBejRsJZ7LP85wWMaITBYg,3042
20
31
  pytbox/utils/ping_checker.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
21
32
  pytbox/utils/response.py,sha256=kXjlwt0WVmLRam2eu1shzX2cQ7ux4cCQryaPGYwle5g,1247
33
+ pytbox/utils/richutils.py,sha256=OT9_q2Q1bthzB0g1GlhZVvM4ZAepJRKL6a_Vsr6vEqo,487
22
34
  pytbox/utils/timeutils.py,sha256=XbK2KB-SVi7agNqoQN7i40wysrZvrGuwebViv1Cw-Ok,20226
23
- pytbox-0.0.5.dist-info/METADATA,sha256=cNFwHW1aNu_zPUuXq7KOBRj-6cx6oSO-UbAPbJFQOdU,6037
24
- pytbox-0.0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
- pytbox-0.0.5.dist-info/top_level.txt,sha256=YADgWue-Oe128ptN3J2hS3GB0Ncc5uZaSUM3e1rwswE,7
26
- pytbox-0.0.5.dist-info/RECORD,,
35
+ pytbox-0.0.6.dist-info/METADATA,sha256=XTF_u4mj5KSUyGRNBtrFiA-UHffcS0gZwsYH62DPKl4,6245
36
+ pytbox-0.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ pytbox-0.0.6.dist-info/entry_points.txt,sha256=YaTOJ2oPjOiv2SZwY0UC-UA9QS2phRH1oMvxGnxO0Js,43
38
+ pytbox-0.0.6.dist-info/top_level.txt,sha256=YADgWue-Oe128ptN3J2hS3GB0Ncc5uZaSUM3e1rwswE,7
39
+ pytbox-0.0.6.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pytbox = pytbox.cli:main
File without changes