staran 0.6.1__py3-none-any.whl → 1.0.1__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.
@@ -1,350 +0,0 @@
1
- """
2
- Schema文档生成器
3
-
4
- 支持根据表结构定义生成多种格式的技术文档:
5
- - Markdown格式:适合开发团队和版本控制
6
- - PDF格式:适合正式交付和业务方审阅
7
- - HTML格式:适合在线查看和分享
8
-
9
- 主要功能:
10
- 1. 表结构自动解析
11
- 2. 字段信息格式化
12
- 3. 业务含义说明
13
- 4. 技术规范文档
14
- 5. 多格式导出支持
15
- """
16
-
17
- import os
18
- from typing import Dict, List, Optional
19
- from datetime import datetime
20
-
21
-
22
- class SchemaDocumentGenerator:
23
- """表结构文档生成器"""
24
-
25
- def __init__(self):
26
- self.template_configs = {
27
- 'markdown': {
28
- 'extension': '.md',
29
- 'header_template': self._get_markdown_header_template(),
30
- 'field_template': self._get_markdown_field_template(),
31
- 'footer_template': self._get_markdown_footer_template()
32
- },
33
- 'pdf': {
34
- 'extension': '.pdf',
35
- 'requires_conversion': True,
36
- 'base_format': 'markdown' # 先生成MD再转PDF
37
- },
38
- 'html': {
39
- 'extension': '.html',
40
- 'header_template': self._get_html_header_template(),
41
- 'field_template': self._get_html_field_template(),
42
- 'footer_template': self._get_html_footer_template()
43
- }
44
- }
45
-
46
- def export_schema_doc(self, schema, business_domain: str, table_type: str,
47
- output_dir: str = "./docs", format_type: str = "markdown") -> str:
48
- """
49
- 导出表结构文档
50
-
51
- Args:
52
- schema: TableSchema对象
53
- business_domain: 业务域名称 (如: AUM, CRM, RISK)
54
- table_type: 表类型 (如: behavior, asset_avg)
55
- output_dir: 输出目录
56
- format_type: 文档格式 ('markdown', 'pdf', 'html')
57
-
58
- Returns:
59
- 生成的文档文件路径
60
- """
61
- # 确保输出目录存在
62
- os.makedirs(output_dir, exist_ok=True)
63
-
64
- # 生成文件名
65
- timestamp = datetime.now().strftime("%Y%m%d")
66
- filename = f"{business_domain}_{table_type}_schema_{timestamp}"
67
-
68
- if format_type.lower() == 'pdf':
69
- # PDF格式先生成Markdown再转换
70
- md_content = self._generate_markdown_content(schema, business_domain, table_type)
71
- md_path = os.path.join(output_dir, f"{filename}.md")
72
-
73
- with open(md_path, 'w', encoding='utf-8') as f:
74
- f.write(md_content)
75
-
76
- # 转换为PDF (这里可以集成pandoc或其他转换工具)
77
- pdf_path = os.path.join(output_dir, f"{filename}.pdf")
78
- self._convert_md_to_pdf(md_path, pdf_path)
79
- return pdf_path
80
-
81
- elif format_type.lower() == 'html':
82
- # HTML格式
83
- html_content = self._generate_html_content(schema, business_domain, table_type)
84
- html_path = os.path.join(output_dir, f"{filename}.html")
85
-
86
- with open(html_path, 'w', encoding='utf-8') as f:
87
- f.write(html_content)
88
- return html_path
89
-
90
- else:
91
- # 默认Markdown格式
92
- md_content = self._generate_markdown_content(schema, business_domain, table_type)
93
- md_path = os.path.join(output_dir, f"{filename}.md")
94
-
95
- with open(md_path, 'w', encoding='utf-8') as f:
96
- f.write(md_content)
97
- return md_path
98
-
99
- def _generate_markdown_content(self, schema, business_domain: str, table_type: str) -> str:
100
- """生成Markdown格式内容"""
101
- content = []
102
-
103
- # 文档头部
104
- content.append(f"# {business_domain} - {table_type.upper()}表结构文档")
105
- content.append("")
106
- content.append(f"## 基本信息")
107
- content.append("")
108
- content.append(f"- **表名**: `{schema.table_name}`")
109
- content.append(f"- **业务域**: {business_domain}")
110
- content.append(f"- **表类型**: {table_type}")
111
- content.append(f"- **生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
112
- content.append(f"- **月度唯一性**: {'是' if getattr(schema, 'is_monthly_unique', False) else '否'}")
113
- content.append("")
114
-
115
- # 表结构说明
116
- content.append("## 表结构说明")
117
- content.append("")
118
- if hasattr(schema, 'description'):
119
- content.append(f"{schema.description}")
120
- content.append("")
121
-
122
- # 主键信息
123
- if hasattr(schema, 'primary_key') and schema.primary_key:
124
- content.append("### 主键字段")
125
- content.append("")
126
- content.append(f"- `{schema.primary_key}` (主键)")
127
- content.append("")
128
-
129
- # 日期字段
130
- if hasattr(schema, 'date_field') and schema.date_field:
131
- content.append("### 日期字段")
132
- content.append("")
133
- content.append(f"- `{schema.date_field}` (日期字段)")
134
- content.append("")
135
-
136
- # 字段详情表格
137
- content.append("## 字段详情")
138
- content.append("")
139
- content.append("| 字段名 | 数据类型 | 业务含义 | 可聚合 | 备注 |")
140
- content.append("|--------|----------|----------|--------|------|")
141
-
142
- if hasattr(schema, 'fields'):
143
- for field_name, field in schema.fields.items():
144
- # 简化数据类型显示
145
- field_type_str = str(field.field_type) if hasattr(field, 'field_type') else 'string'
146
- field_type = field_type_str.replace('FieldType.', '').lower()
147
- comment = field.comment if hasattr(field, 'comment') else ''
148
- aggregatable = '是' if getattr(field, 'aggregatable', False) else '否'
149
- remarks = '' # 可以从其他地方获取备注
150
-
151
- content.append(f"| `{field_name}` | {field_type} | {comment} | {aggregatable} | {remarks} |")
152
-
153
- content.append("")
154
-
155
- # 业务规则说明
156
- content.append("## 业务规则")
157
- content.append("")
158
- content.append("### 数据更新规则")
159
- if getattr(schema, 'is_monthly_unique', False):
160
- content.append("- 每人每月一条记录")
161
- content.append("- 月末批量更新")
162
- else:
163
- content.append("- 每人每日一条记录")
164
- content.append("- 日终批量更新")
165
- content.append("")
166
-
167
- content.append("### 数据质量要求")
168
- content.append("- 主键字段不允许为空")
169
- content.append("- 日期字段格式统一为YYYYMMDD")
170
- content.append("- 金额字段精度保持2位小数")
171
- content.append("- 比例字段取值范围[0,1]")
172
- content.append("")
173
-
174
- # 使用说明
175
- content.append("## 使用说明")
176
- content.append("")
177
- content.append("### 特征工程配置")
178
- if table_type == 'behavior':
179
- content.append("- 生成原始拷贝特征")
180
- content.append("- 生成聚合特征")
181
- content.append("- 不生成环比、同比特征")
182
- else:
183
- content.append("- 生成聚合特征")
184
- content.append("- 生成5个月环比特征")
185
- content.append("- 生成1年同比特征")
186
- content.append("")
187
-
188
- content.append("### 示例SQL查询")
189
- content.append("```sql")
190
- content.append(f"-- 查询最新数据")
191
- content.append(f"SELECT * FROM {schema.table_name}")
192
- content.append(f"WHERE data_dt = (SELECT MAX(data_dt) FROM {schema.table_name})")
193
- content.append(f"LIMIT 10;")
194
- content.append("```")
195
- content.append("")
196
-
197
- # 文档尾部
198
- content.append("---")
199
- content.append("*本文档由Staran Schema自动生成*")
200
-
201
- return "\n".join(content)
202
-
203
- def _generate_html_content(self, schema, business_domain: str, table_type: str) -> str:
204
- """生成HTML格式内容"""
205
- # 基础HTML模板,可以根据需要扩展
206
- html_content = f"""
207
- <!DOCTYPE html>
208
- <html lang="zh-CN">
209
- <head>
210
- <meta charset="UTF-8">
211
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
212
- <title>{business_domain} - {table_type.upper()}表结构文档</title>
213
- <style>
214
- body {{ font-family: 'Microsoft YaHei', Arial, sans-serif; margin: 40px; }}
215
- h1, h2, h3 {{ color: #333; }}
216
- table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
217
- th, td {{ border: 1px solid #ddd; padding: 12px; text-align: left; }}
218
- th {{ background-color: #f2f2f2; font-weight: bold; }}
219
- code {{ background-color: #f4f4f4; padding: 2px 4px; border-radius: 3px; }}
220
- .info-table {{ background-color: #f9f9f9; }}
221
- </style>
222
- </head>
223
- <body>
224
- <h1>{business_domain} - {table_type.upper()}表结构文档</h1>
225
-
226
- <h2>基本信息</h2>
227
- <table class="info-table">
228
- <tr><th>表名</th><td><code>{schema.table_name}</code></td></tr>
229
- <tr><th>业务域</th><td>{business_domain}</td></tr>
230
- <tr><th>表类型</th><td>{table_type}</td></tr>
231
- <tr><th>生成时间</th><td>{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</td></tr>
232
- <tr><th>月度唯一性</th><td>{'是' if getattr(schema, 'is_monthly_unique', False) else '否'}</td></tr>
233
- </table>
234
-
235
- <h2>字段详情</h2>
236
- <table>
237
- <thead>
238
- <tr>
239
- <th>字段名</th>
240
- <th>数据类型</th>
241
- <th>业务含义</th>
242
- <th>可聚合</th>
243
- <th>备注</th>
244
- </tr>
245
- </thead>
246
- <tbody>
247
- """
248
-
249
- # 添加字段行
250
- if hasattr(schema, 'fields'):
251
- for field_name, field in schema.fields.items():
252
- # 简化数据类型显示
253
- field_type_str = str(field.field_type) if hasattr(field, 'field_type') else 'string'
254
- field_type = field_type_str.replace('FieldType.', '').lower()
255
- comment = field.comment if hasattr(field, 'comment') else ''
256
- aggregatable = '是' if getattr(field, 'aggregatable', False) else '否'
257
- remarks = '' # 可以从其他地方获取备注
258
-
259
- html_content += f"""
260
- <tr>
261
- <td><code>{field_name}</code></td>
262
- <td>{field_type}</td>
263
- <td>{comment}</td>
264
- <td>{aggregatable}</td>
265
- <td>{remarks}</td>
266
- </tr>"""
267
-
268
- html_content += """
269
- </tbody>
270
- </table>
271
-
272
- <hr>
273
- <p><em>本文档由Staran Schema自动生成</em></p>
274
- </body>
275
- </html>"""
276
-
277
- return html_content
278
-
279
- def _convert_md_to_pdf(self, md_path: str, pdf_path: str):
280
- """将Markdown转换为PDF (需要安装pandoc或其他转换工具)"""
281
- try:
282
- import subprocess
283
- # 尝试使用pandoc转换
284
- subprocess.run([
285
- 'pandoc', md_path, '-o', pdf_path,
286
- '--pdf-engine=xelatex',
287
- '--variable=CJKmainfont:Microsoft YaHei'
288
- ], check=True)
289
- except (subprocess.CalledProcessError, FileNotFoundError):
290
- # 如果pandoc不可用,创建一个说明文件
291
- with open(pdf_path.replace('.pdf', '_conversion_note.txt'), 'w', encoding='utf-8') as f:
292
- f.write(f"PDF转换说明:\\n")
293
- f.write(f"原始Markdown文件:{md_path}\\n")
294
- f.write(f"如需PDF格式,请安装pandoc工具:\\n")
295
- f.write(f"pip install pandoc\\n")
296
- f.write(f"或访问:https://pandoc.org/installing.html\\n")
297
-
298
- def _get_markdown_header_template(self) -> str:
299
- return "# {title}\\n\\n## 基本信息\\n\\n"
300
-
301
- def _get_markdown_field_template(self) -> str:
302
- return "| {name} | {type} | {comment} | {aggregatable} |\\n"
303
-
304
- def _get_markdown_footer_template(self) -> str:
305
- return "\\n---\\n*文档生成时间: {timestamp}*\\n"
306
-
307
- def _get_html_header_template(self) -> str:
308
- return "<h1>{title}</h1>\\n<h2>基本信息</h2>\\n"
309
-
310
- def _get_html_field_template(self) -> str:
311
- return "<tr><td>{name}</td><td>{type}</td><td>{comment}</td><td>{aggregatable}</td></tr>\\n"
312
-
313
- def _get_html_footer_template(self) -> str:
314
- return "<hr><p><em>文档生成时间: {timestamp}</em></p>\\n"
315
-
316
-
317
- def export_business_docs(business_domain: str, schemas_dict: Dict, output_dir: str = "./docs",
318
- format_type: str = "markdown") -> Dict[str, str]:
319
- """
320
- 批量导出业务域表结构文档
321
-
322
- Args:
323
- business_domain: 业务域名称
324
- schemas_dict: 表结构字典 {table_type: schema}
325
- output_dir: 输出目录
326
- format_type: 文档格式
327
-
328
- Returns:
329
- 生成的文档文件路径字典
330
- """
331
- generator = SchemaDocumentGenerator()
332
- results = {}
333
-
334
- for table_type, schema in schemas_dict.items():
335
- file_path = generator.export_schema_doc(
336
- schema=schema,
337
- business_domain=business_domain,
338
- table_type=table_type,
339
- output_dir=output_dir,
340
- format_type=format_type
341
- )
342
- results[table_type] = file_path
343
-
344
- return results
345
-
346
-
347
- __all__ = [
348
- 'SchemaDocumentGenerator',
349
- 'export_business_docs'
350
- ]