athena-kit 1.0.0__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 (164) hide show
  1. athena_kit-1.0.0/LICENSE +21 -0
  2. athena_kit-1.0.0/PKG-INFO +245 -0
  3. athena_kit-1.0.0/README.md +210 -0
  4. athena_kit-1.0.0/pyproject.toml +90 -0
  5. athena_kit-1.0.0/src/athena_kit/__init__.py +5 -0
  6. athena_kit-1.0.0/src/athena_kit/_import_utils.py +41 -0
  7. athena_kit-1.0.0/src/athena_kit/bosun/__init__.py +32 -0
  8. athena_kit-1.0.0/src/athena_kit/bosun/ast/__init__.py +71 -0
  9. athena_kit-1.0.0/src/athena_kit/bosun/ast/nodes.py +115 -0
  10. athena_kit-1.0.0/src/athena_kit/bosun/ast/queries.py +130 -0
  11. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/__init__.py +95 -0
  12. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/enums.py +38 -0
  13. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/exceptions.py +2 -0
  14. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/intervals.py +45 -0
  15. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/models.py +205 -0
  16. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/parser.py +303 -0
  17. athena_kit-1.0.0/src/athena_kit/bosun/opentsdb/serializer.py +87 -0
  18. athena_kit-1.0.0/src/athena_kit/bosun/parser/__init__.py +43 -0
  19. athena_kit-1.0.0/src/athena_kit/bosun/parser/exceptions.py +7 -0
  20. athena_kit-1.0.0/src/athena_kit/bosun/parser/lexer.py +237 -0
  21. athena_kit-1.0.0/src/athena_kit/bosun/parser/parselets.py +173 -0
  22. athena_kit-1.0.0/src/athena_kit/bosun/parser/parser.py +46 -0
  23. athena_kit-1.0.0/src/athena_kit/bosun/parser/preprocess.py +399 -0
  24. athena_kit-1.0.0/src/athena_kit/bosun/parser/tokens.py +108 -0
  25. athena_kit-1.0.0/src/athena_kit/core/__init__.py +211 -0
  26. athena_kit-1.0.0/src/athena_kit/core/models/__init__.py +30 -0
  27. athena_kit-1.0.0/src/athena_kit/core/models/base.py +11 -0
  28. athena_kit-1.0.0/src/athena_kit/core/models/enums.py +114 -0
  29. athena_kit-1.0.0/src/athena_kit/core/tabular/__init__.py +55 -0
  30. athena_kit-1.0.0/src/athena_kit/core/tabular/backend.py +120 -0
  31. athena_kit-1.0.0/src/athena_kit/core/tabular/cell.py +22 -0
  32. athena_kit-1.0.0/src/athena_kit/core/tabular/pandas.py +139 -0
  33. athena_kit-1.0.0/src/athena_kit/core/tabular/repository.py +134 -0
  34. athena_kit-1.0.0/src/athena_kit/core/tabular/row.py +90 -0
  35. athena_kit-1.0.0/src/athena_kit/core/tabular/serialization.py +204 -0
  36. athena_kit-1.0.0/src/athena_kit/core/tabular/source.py +26 -0
  37. athena_kit-1.0.0/src/athena_kit/core/temporal/__init__.py +78 -0
  38. athena_kit-1.0.0/src/athena_kit/core/temporal/codec/__init__.py +90 -0
  39. athena_kit-1.0.0/src/athena_kit/core/temporal/codec/date.py +179 -0
  40. athena_kit-1.0.0/src/athena_kit/core/temporal/codec/datetime.py +204 -0
  41. athena_kit-1.0.0/src/athena_kit/core/temporal/codec/options.py +95 -0
  42. athena_kit-1.0.0/src/athena_kit/core/temporal/codec/temporal.py +141 -0
  43. athena_kit-1.0.0/src/athena_kit/core/temporal/codec/time.py +140 -0
  44. athena_kit-1.0.0/src/athena_kit/core/temporal/normalize.py +53 -0
  45. athena_kit-1.0.0/src/athena_kit/core/temporal/predicates.py +14 -0
  46. athena_kit-1.0.0/src/athena_kit/core/temporal/timezone.py +87 -0
  47. athena_kit-1.0.0/src/athena_kit/core/temporal/types.py +64 -0
  48. athena_kit-1.0.0/src/athena_kit/core/values/__init__.py +53 -0
  49. athena_kit-1.0.0/src/athena_kit/core/values/fallbacks.py +60 -0
  50. athena_kit-1.0.0/src/athena_kit/core/values/optional.py +81 -0
  51. athena_kit-1.0.0/src/athena_kit/core/values/predicates.py +0 -0
  52. athena_kit-1.0.0/src/athena_kit/http/__init__.py +76 -0
  53. athena_kit-1.0.0/src/athena_kit/http/aclient.py +38 -0
  54. athena_kit-1.0.0/src/athena_kit/http/client.py +38 -0
  55. athena_kit-1.0.0/src/athena_kit/http/hooks/__init__.py +79 -0
  56. athena_kit-1.0.0/src/athena_kit/http/hooks/event_hooks.py +105 -0
  57. athena_kit-1.0.0/src/athena_kit/http/hooks/logging.py +106 -0
  58. athena_kit-1.0.0/src/athena_kit/http/hooks/request_id.py +48 -0
  59. athena_kit-1.0.0/src/athena_kit/http/hooks/response_status.py +58 -0
  60. athena_kit-1.0.0/src/athena_kit/http/hooks/types.py +19 -0
  61. athena_kit-1.0.0/src/athena_kit/http/response_json.py +257 -0
  62. athena_kit-1.0.0/src/athena_kit/http/retrying.py +169 -0
  63. athena_kit-1.0.0/src/athena_kit/lark/__init__.py +28 -0
  64. athena_kit-1.0.0/src/athena_kit/lark/aclient.py +65 -0
  65. athena_kit-1.0.0/src/athena_kit/lark/auth.py +91 -0
  66. athena_kit-1.0.0/src/athena_kit/lark/sheets/__init__.py +30 -0
  67. athena_kit-1.0.0/src/athena_kit/lark/sheets/a1_notation.py +66 -0
  68. athena_kit-1.0.0/src/athena_kit/lark/sheets/aclient.py +343 -0
  69. athena_kit-1.0.0/src/athena_kit/lark/sheets/backend.py +64 -0
  70. athena_kit-1.0.0/src/athena_kit/lark/sheets/requests.py +63 -0
  71. athena_kit-1.0.0/src/athena_kit/matplotlib/__init__.py +2 -0
  72. athena_kit-1.0.0/src/athena_kit/matplotlib/adapters/__init__.py +35 -0
  73. athena_kit-1.0.0/src/athena_kit/matplotlib/adapters/styles.py +129 -0
  74. athena_kit-1.0.0/src/athena_kit/matplotlib/datas/__init__.py +34 -0
  75. athena_kit-1.0.0/src/athena_kit/matplotlib/datas/categorical.py +56 -0
  76. athena_kit-1.0.0/src/athena_kit/matplotlib/datas/xy.py +63 -0
  77. athena_kit-1.0.0/src/athena_kit/matplotlib/decorations/__init__.py +39 -0
  78. athena_kit-1.0.0/src/athena_kit/matplotlib/decorations/axis.py +34 -0
  79. athena_kit-1.0.0/src/athena_kit/matplotlib/decorations/cartesian.py +126 -0
  80. athena_kit-1.0.0/src/athena_kit/matplotlib/decorations/chart.py +26 -0
  81. athena_kit-1.0.0/src/athena_kit/matplotlib/decorations/grid.py +24 -0
  82. athena_kit-1.0.0/src/athena_kit/matplotlib/decorations/tick.py +58 -0
  83. athena_kit-1.0.0/src/athena_kit/matplotlib/options/__init__.py +38 -0
  84. athena_kit-1.0.0/src/athena_kit/matplotlib/options/_base.py +11 -0
  85. athena_kit-1.0.0/src/athena_kit/matplotlib/options/chart.py +38 -0
  86. athena_kit-1.0.0/src/athena_kit/matplotlib/options/coords/__init__.py +47 -0
  87. athena_kit-1.0.0/src/athena_kit/matplotlib/options/coords/axis.py +95 -0
  88. athena_kit-1.0.0/src/athena_kit/matplotlib/options/coords/cartesian.py +48 -0
  89. athena_kit-1.0.0/src/athena_kit/matplotlib/options/coords/grid.py +52 -0
  90. athena_kit-1.0.0/src/athena_kit/matplotlib/options/coords/legend.py +37 -0
  91. athena_kit-1.0.0/src/athena_kit/matplotlib/options/coords/tick.py +104 -0
  92. athena_kit-1.0.0/src/athena_kit/matplotlib/options/figure.py +28 -0
  93. athena_kit-1.0.0/src/athena_kit/matplotlib/options/plots/__init__.py +62 -0
  94. athena_kit-1.0.0/src/athena_kit/matplotlib/options/plots/bar.py +105 -0
  95. athena_kit-1.0.0/src/athena_kit/matplotlib/options/plots/data_label.py +89 -0
  96. athena_kit-1.0.0/src/athena_kit/matplotlib/options/plots/line.py +42 -0
  97. athena_kit-1.0.0/src/athena_kit/matplotlib/options/plots/marker.py +50 -0
  98. athena_kit-1.0.0/src/athena_kit/matplotlib/options/renderfig.py +57 -0
  99. athena_kit-1.0.0/src/athena_kit/matplotlib/options/rules/__init__.py +42 -0
  100. athena_kit-1.0.0/src/athena_kit/matplotlib/options/rules/conditions.py +73 -0
  101. athena_kit-1.0.0/src/athena_kit/matplotlib/options/rules/data_context.py +43 -0
  102. athena_kit-1.0.0/src/athena_kit/matplotlib/options/rules/matches.py +53 -0
  103. athena_kit-1.0.0/src/athena_kit/matplotlib/options/savefig.py +80 -0
  104. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/__init__.py +30 -0
  105. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/chart.py +21 -0
  106. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/color_cycle.py +17 -0
  107. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/coords/__init__.py +25 -0
  108. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/coords/_axes_runtime.py +80 -0
  109. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/coords/_render_plan.py +122 -0
  110. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/coords/cartesian.py +59 -0
  111. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/coords/legend.py +39 -0
  112. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/coords/tick.py +119 -0
  113. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/__init__.py +25 -0
  114. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/bar_plot.py +169 -0
  115. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/layers/__init__.py +33 -0
  116. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/layers/bar_layer.py +56 -0
  117. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/layers/datalabel_layer.py +120 -0
  118. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/layers/line_layer.py +52 -0
  119. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/layers/marker_layer.py +119 -0
  120. athena_kit-1.0.0/src/athena_kit/matplotlib/rendering/plots/line_plot.py +63 -0
  121. athena_kit-1.0.0/src/athena_kit/matplotlib/runtime/__init__.py +64 -0
  122. athena_kit-1.0.0/src/athena_kit/matplotlib/runtime/artifact.py +62 -0
  123. athena_kit-1.0.0/src/athena_kit/matplotlib/runtime/context.py +220 -0
  124. athena_kit-1.0.0/src/athena_kit/matplotlib/runtime/pipeline.py +40 -0
  125. athena_kit-1.0.0/src/athena_kit/matplotlib/runtime/renderer.py +107 -0
  126. athena_kit-1.0.0/src/athena_kit/matplotlib/runtime/writers.py +99 -0
  127. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/__init__.py +34 -0
  128. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/_base.py +12 -0
  129. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/chart.py +51 -0
  130. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/coords/__init__.py +49 -0
  131. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/coords/base.py +27 -0
  132. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/coords/cartesian.py +121 -0
  133. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/coords/polar.py +62 -0
  134. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/coords/tick.py +94 -0
  135. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/coords/unions.py +44 -0
  136. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/figure.py +104 -0
  137. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/plots/__init__.py +41 -0
  138. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/plots/bar.py +53 -0
  139. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/plots/base.py +16 -0
  140. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/plots/line.py +51 -0
  141. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/plots/pie.py +27 -0
  142. athena_kit-1.0.0/src/athena_kit/matplotlib/specs/plots/unions.py +31 -0
  143. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/__init__.py +57 -0
  144. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/base.py +23 -0
  145. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/chart.py +28 -0
  146. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/coord.py +31 -0
  147. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/figure.py +34 -0
  148. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/grid.py +38 -0
  149. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/legend.py +75 -0
  150. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/plot.py +31 -0
  151. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/presets/__init__.py +30 -0
  152. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/presets/fonts.py +15 -0
  153. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/presets/palettes.py +16 -0
  154. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/theme.py +58 -0
  155. athena_kit-1.0.0/src/athena_kit/matplotlib/styles/tick.py +69 -0
  156. athena_kit-1.0.0/src/athena_kit/matplotlib/transforms/__init__.py +0 -0
  157. athena_kit-1.0.0/src/athena_kit/matplotlib/transforms/alignment_data.py +120 -0
  158. athena_kit-1.0.0/src/athena_kit/matplotlib/transforms/normalize_data.py +131 -0
  159. athena_kit-1.0.0/src/athena_kit/matplotlib/transforms/tick_labels.py +101 -0
  160. athena_kit-1.0.0/src/athena_kit/matplotlib/types/__init__.py +92 -0
  161. athena_kit-1.0.0/src/athena_kit/matplotlib/types/options.py +37 -0
  162. athena_kit-1.0.0/src/athena_kit/matplotlib/types/specs.py +124 -0
  163. athena_kit-1.0.0/src/athena_kit/matplotlib/types/styles.py +201 -0
  164. athena_kit-1.0.0/src/athena_kit/py.typed +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wangmu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,245 @@
1
+ Metadata-Version: 2.4
2
+ Name: athena-kit
3
+ Version: 1.0.0
4
+ Summary: A modular Python toolkit for Athena projects.
5
+ Keywords: athena,toolkit,utilities,temporal,pydantic
6
+ Author: wangmu
7
+ Author-email: wangmu <wangmu8889@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Classifier: Typing :: Typed
17
+ Requires-Dist: pydantic>=2.13.4
18
+ Requires-Dist: httpx>=0.28.1 ; extra == 'all'
19
+ Requires-Dist: matplotlib>=3.10.9 ; extra == 'all'
20
+ Requires-Dist: pandas>=2.3.3 ; extra == 'all'
21
+ Requires-Dist: pandas>=2.3.3 ; extra == 'dataframe'
22
+ Requires-Dist: httpx>=0.28.1 ; extra == 'http'
23
+ Requires-Dist: httpx>=0.28.1 ; extra == 'lark'
24
+ Requires-Dist: matplotlib>=3.10.9 ; extra == 'matplotlib'
25
+ Requires-Python: >=3.12
26
+ Project-URL: Homepage, https://github.com/wangmu0115/Athena
27
+ Project-URL: Repository, https://github.com/wangmu0115/Athena
28
+ Project-URL: Issues, https://github.com/wangmu0115/Athena/issues
29
+ Provides-Extra: all
30
+ Provides-Extra: dataframe
31
+ Provides-Extra: http
32
+ Provides-Extra: lark
33
+ Provides-Extra: matplotlib
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Athena Kit
37
+
38
+ Athena Kit 是 Athena 项目使用的模块化 Python 工具包。
39
+
40
+ 它发布为一个 Python 包:`athena-kit`,并提供统一的 Python 命名空间:`athena_kit`。
41
+
42
+ ## 安装
43
+
44
+ ```shell
45
+ uv add athena-kit
46
+ uv add "athena-kit[http]"
47
+ uv add "athena-kit[lark]"
48
+ uv add "athena-kit[matplotlib]"
49
+ uv add "athena-kit[dataframe]"
50
+ uv add "athena-kit[all]"
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ### athena http
56
+
57
+ `athena_kit.http` 基于 HTTPX 做薄封装,提供同步/异步客户端、常用 event hooks、JSON 响应提取和简单重试工具。
58
+
59
+ 同步请求:
60
+
61
+ ```python
62
+ from athena_kit.http import HttpClient
63
+
64
+ with HttpClient(base_url="https://api.example.test", request_id=True) as client:
65
+ response = client.get("/items")
66
+ response.raise_for_status()
67
+ ```
68
+
69
+ 异步请求:
70
+
71
+ ```python
72
+ from athena_kit.http import AsyncHttpClient
73
+
74
+ async with AsyncHttpClient(base_url="https://api.example.test", request_id=True) as client:
75
+ response = await client.get("/items")
76
+ response.raise_for_status()
77
+ ```
78
+
79
+ 启用请求 ID、日志和响应状态检查:
80
+
81
+ ```python
82
+ from athena_kit.http import HttpClient
83
+
84
+ with HttpClient(
85
+ base_url="https://api.example.test",
86
+ request_id=True,
87
+ logging=True,
88
+ response_status=True,
89
+ ) as client:
90
+ response = client.get("/items")
91
+ ```
92
+
93
+ 提取 JSON 响应中的业务数据:
94
+
95
+ ```python
96
+ from athena_kit.http import create_biz_code_validator, extract_response_json_value
97
+
98
+ data = extract_response_json_value(
99
+ response,
100
+ "data.items[0]",
101
+ validator=create_biz_code_validator(code_key="code", success_codes=(0,)),
102
+ )
103
+ ```
104
+
105
+ 为请求增加简单重试:
106
+
107
+ ```python
108
+ import httpx
109
+ from athena_kit.http import RetryOptions, retry
110
+
111
+ response = retry(
112
+ request=lambda: client.get("/items"),
113
+ options=RetryOptions(attempts=3, initial_delay=0.2, multiplier=2.0, jitter=0.1, logger=True),
114
+ should_retry_result=lambda response: response.status_code in {429, 500, 502, 503, 504},
115
+ should_retry_exception=lambda exc: isinstance(exc, httpx.TimeoutException),
116
+ )
117
+ ```
118
+
119
+ 更多 HTTP 使用案例见 [docs/athena_http.md](docs/athena_http.md)。
120
+
121
+ ### athena tabular
122
+
123
+ `athena_kit.core.tabular` 提供二维表格模型、单元格序列化、pandas DataFrame 转换,以及同步/异步表格后端和仓储抽象。
124
+
125
+ 定义一行表格模型:
126
+
127
+ ```python
128
+ from datetime import date
129
+
130
+ from athena_kit.core.tabular import TableCell, TableRow
131
+
132
+
133
+ class TradeRow(TableRow):
134
+ trade_date: date = TableCell(title="日期", order=1)
135
+ symbol: str = TableCell(title="代码", order=2)
136
+ amount: int = TableCell(title="成交额", order=3)
137
+ ```
138
+
139
+ 模型和二维表格行互相转换:
140
+
141
+ ```python
142
+ row = TradeRow(trade_date=date(2026, 6, 11), symbol="000001", amount=1200)
143
+
144
+ assert TradeRow.table_headers() == ["日期", "代码", "成交额"]
145
+ assert row.to_table_row() == ["2026-06-11", "000001", 1200]
146
+ ```
147
+
148
+ 使用 repository 接入具体二维表格后端:
149
+
150
+ ```python
151
+ from athena_kit.core.tabular import TableRepository
152
+
153
+ repository = TableRepository(backend, locator, TradeRow)
154
+ rows = repository.list_all()
155
+ ```
156
+
157
+ 更多 Tabular 使用案例见 [docs/athena_tabular.md](docs/athena_tabular.md)。
158
+
159
+ ### athena lark
160
+
161
+ `athena_kit.lark` 提供飞书开放平台异步客户端。当前重点支持 Sheets,包括创建电子表格、批量新增工作表、读写单个工作表范围,以及接入 `core.tabular` 的异步表格后端。
162
+
163
+ 创建飞书客户端并新增电子表格:
164
+
165
+ ```python
166
+ from athena_kit.lark import AsyncLarkClient
167
+
168
+
169
+ async with AsyncLarkClient(app_id="cli_xxx", app_secret="xxx", response_status=True) as client:
170
+ spreadsheet_token, url = await client.sheets.create_spreadsheet(
171
+ folder_token="fldcn_xxx",
172
+ title="交易汇总",
173
+ )
174
+ ```
175
+
176
+ 写入飞书工作表:
177
+
178
+ ```python
179
+ revision, updated_rows, updated_columns = await client.sheets.overwrite_values(
180
+ spreadsheet_token=spreadsheet_token,
181
+ sheet_id="sheet_xxx",
182
+ headers=["日期", "代码", "成交额"],
183
+ rows_values=[["2026-06-11", "000001", 1200]],
184
+ start_row=1,
185
+ )
186
+ ```
187
+
188
+ 接入异步表格仓储:
189
+
190
+ ```python
191
+ from athena_kit.core.tabular import AsyncTableRepository
192
+ from athena_kit.lark.sheets import AsyncLarkSheetsBackend, LarkSheetsLocator
193
+
194
+ backend = AsyncLarkSheetsBackend(client.sheets)
195
+ locator = LarkSheetsLocator(spreadsheet_token=spreadsheet_token, sheet_id="sheet_xxx")
196
+ repository = AsyncTableRepository(backend, locator, TradeRow)
197
+
198
+ rows = await repository.list_all()
199
+ ```
200
+
201
+ 更多 Lark Sheets 使用案例见 [docs/athena_lark.md](docs/athena_lark.md)。
202
+
203
+ ## 模块结构
204
+
205
+ - `athena_kit.core`:基础模型、时间编解码、表格和通用值处理工具。
206
+ - `athena_kit.http`:基于 HTTPX 的同步/异步 HTTP 工具。
207
+ - `athena_kit.lark`:飞书开放平台异步客户端和 Sheets 工具。
208
+ - `athena_kit.matplotlib`:声明式图表渲染工具。
209
+ - `athena_kit.bosun`:Bosun 表达式解析和 OpenTSDB 查询工具。
210
+
211
+ ## 开发
212
+
213
+ ```shell
214
+ uv sync --extra all
215
+ uv run ruff check src tests examples
216
+ uv run ruff format --check src tests examples
217
+ uv run pytest tests
218
+ ```
219
+
220
+ ## 发布到 PyPI
221
+
222
+ 发布前确认版本号已经更新,并且 `pyproject.toml` 和 `src/athena_kit/__init__.py` 中的版本一致。
223
+
224
+ ```shell
225
+ uv sync --extra all
226
+ uv run ruff check src tests examples
227
+ uv run ruff format --check src tests examples
228
+ uv run pytest tests
229
+ rm -rf dist
230
+ uv build
231
+ uv publish
232
+ ```
233
+
234
+ 如果是第一次发布,先在 PyPI 创建 API Token,然后按 `uv publish` 的提示输入 token;也可以提前设置环境变量:
235
+
236
+ ```shell
237
+ export UV_PUBLISH_TOKEN="pypi-..."
238
+ uv publish
239
+ ```
240
+
241
+ 发布完成后,在其他项目中安装:
242
+
243
+ ```shell
244
+ uv add athena-kit
245
+ ```
@@ -0,0 +1,210 @@
1
+ # Athena Kit
2
+
3
+ Athena Kit 是 Athena 项目使用的模块化 Python 工具包。
4
+
5
+ 它发布为一个 Python 包:`athena-kit`,并提供统一的 Python 命名空间:`athena_kit`。
6
+
7
+ ## 安装
8
+
9
+ ```shell
10
+ uv add athena-kit
11
+ uv add "athena-kit[http]"
12
+ uv add "athena-kit[lark]"
13
+ uv add "athena-kit[matplotlib]"
14
+ uv add "athena-kit[dataframe]"
15
+ uv add "athena-kit[all]"
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### athena http
21
+
22
+ `athena_kit.http` 基于 HTTPX 做薄封装,提供同步/异步客户端、常用 event hooks、JSON 响应提取和简单重试工具。
23
+
24
+ 同步请求:
25
+
26
+ ```python
27
+ from athena_kit.http import HttpClient
28
+
29
+ with HttpClient(base_url="https://api.example.test", request_id=True) as client:
30
+ response = client.get("/items")
31
+ response.raise_for_status()
32
+ ```
33
+
34
+ 异步请求:
35
+
36
+ ```python
37
+ from athena_kit.http import AsyncHttpClient
38
+
39
+ async with AsyncHttpClient(base_url="https://api.example.test", request_id=True) as client:
40
+ response = await client.get("/items")
41
+ response.raise_for_status()
42
+ ```
43
+
44
+ 启用请求 ID、日志和响应状态检查:
45
+
46
+ ```python
47
+ from athena_kit.http import HttpClient
48
+
49
+ with HttpClient(
50
+ base_url="https://api.example.test",
51
+ request_id=True,
52
+ logging=True,
53
+ response_status=True,
54
+ ) as client:
55
+ response = client.get("/items")
56
+ ```
57
+
58
+ 提取 JSON 响应中的业务数据:
59
+
60
+ ```python
61
+ from athena_kit.http import create_biz_code_validator, extract_response_json_value
62
+
63
+ data = extract_response_json_value(
64
+ response,
65
+ "data.items[0]",
66
+ validator=create_biz_code_validator(code_key="code", success_codes=(0,)),
67
+ )
68
+ ```
69
+
70
+ 为请求增加简单重试:
71
+
72
+ ```python
73
+ import httpx
74
+ from athena_kit.http import RetryOptions, retry
75
+
76
+ response = retry(
77
+ request=lambda: client.get("/items"),
78
+ options=RetryOptions(attempts=3, initial_delay=0.2, multiplier=2.0, jitter=0.1, logger=True),
79
+ should_retry_result=lambda response: response.status_code in {429, 500, 502, 503, 504},
80
+ should_retry_exception=lambda exc: isinstance(exc, httpx.TimeoutException),
81
+ )
82
+ ```
83
+
84
+ 更多 HTTP 使用案例见 [docs/athena_http.md](docs/athena_http.md)。
85
+
86
+ ### athena tabular
87
+
88
+ `athena_kit.core.tabular` 提供二维表格模型、单元格序列化、pandas DataFrame 转换,以及同步/异步表格后端和仓储抽象。
89
+
90
+ 定义一行表格模型:
91
+
92
+ ```python
93
+ from datetime import date
94
+
95
+ from athena_kit.core.tabular import TableCell, TableRow
96
+
97
+
98
+ class TradeRow(TableRow):
99
+ trade_date: date = TableCell(title="日期", order=1)
100
+ symbol: str = TableCell(title="代码", order=2)
101
+ amount: int = TableCell(title="成交额", order=3)
102
+ ```
103
+
104
+ 模型和二维表格行互相转换:
105
+
106
+ ```python
107
+ row = TradeRow(trade_date=date(2026, 6, 11), symbol="000001", amount=1200)
108
+
109
+ assert TradeRow.table_headers() == ["日期", "代码", "成交额"]
110
+ assert row.to_table_row() == ["2026-06-11", "000001", 1200]
111
+ ```
112
+
113
+ 使用 repository 接入具体二维表格后端:
114
+
115
+ ```python
116
+ from athena_kit.core.tabular import TableRepository
117
+
118
+ repository = TableRepository(backend, locator, TradeRow)
119
+ rows = repository.list_all()
120
+ ```
121
+
122
+ 更多 Tabular 使用案例见 [docs/athena_tabular.md](docs/athena_tabular.md)。
123
+
124
+ ### athena lark
125
+
126
+ `athena_kit.lark` 提供飞书开放平台异步客户端。当前重点支持 Sheets,包括创建电子表格、批量新增工作表、读写单个工作表范围,以及接入 `core.tabular` 的异步表格后端。
127
+
128
+ 创建飞书客户端并新增电子表格:
129
+
130
+ ```python
131
+ from athena_kit.lark import AsyncLarkClient
132
+
133
+
134
+ async with AsyncLarkClient(app_id="cli_xxx", app_secret="xxx", response_status=True) as client:
135
+ spreadsheet_token, url = await client.sheets.create_spreadsheet(
136
+ folder_token="fldcn_xxx",
137
+ title="交易汇总",
138
+ )
139
+ ```
140
+
141
+ 写入飞书工作表:
142
+
143
+ ```python
144
+ revision, updated_rows, updated_columns = await client.sheets.overwrite_values(
145
+ spreadsheet_token=spreadsheet_token,
146
+ sheet_id="sheet_xxx",
147
+ headers=["日期", "代码", "成交额"],
148
+ rows_values=[["2026-06-11", "000001", 1200]],
149
+ start_row=1,
150
+ )
151
+ ```
152
+
153
+ 接入异步表格仓储:
154
+
155
+ ```python
156
+ from athena_kit.core.tabular import AsyncTableRepository
157
+ from athena_kit.lark.sheets import AsyncLarkSheetsBackend, LarkSheetsLocator
158
+
159
+ backend = AsyncLarkSheetsBackend(client.sheets)
160
+ locator = LarkSheetsLocator(spreadsheet_token=spreadsheet_token, sheet_id="sheet_xxx")
161
+ repository = AsyncTableRepository(backend, locator, TradeRow)
162
+
163
+ rows = await repository.list_all()
164
+ ```
165
+
166
+ 更多 Lark Sheets 使用案例见 [docs/athena_lark.md](docs/athena_lark.md)。
167
+
168
+ ## 模块结构
169
+
170
+ - `athena_kit.core`:基础模型、时间编解码、表格和通用值处理工具。
171
+ - `athena_kit.http`:基于 HTTPX 的同步/异步 HTTP 工具。
172
+ - `athena_kit.lark`:飞书开放平台异步客户端和 Sheets 工具。
173
+ - `athena_kit.matplotlib`:声明式图表渲染工具。
174
+ - `athena_kit.bosun`:Bosun 表达式解析和 OpenTSDB 查询工具。
175
+
176
+ ## 开发
177
+
178
+ ```shell
179
+ uv sync --extra all
180
+ uv run ruff check src tests examples
181
+ uv run ruff format --check src tests examples
182
+ uv run pytest tests
183
+ ```
184
+
185
+ ## 发布到 PyPI
186
+
187
+ 发布前确认版本号已经更新,并且 `pyproject.toml` 和 `src/athena_kit/__init__.py` 中的版本一致。
188
+
189
+ ```shell
190
+ uv sync --extra all
191
+ uv run ruff check src tests examples
192
+ uv run ruff format --check src tests examples
193
+ uv run pytest tests
194
+ rm -rf dist
195
+ uv build
196
+ uv publish
197
+ ```
198
+
199
+ 如果是第一次发布,先在 PyPI 创建 API Token,然后按 `uv publish` 的提示输入 token;也可以提前设置环境变量:
200
+
201
+ ```shell
202
+ export UV_PUBLISH_TOKEN="pypi-..."
203
+ uv publish
204
+ ```
205
+
206
+ 发布完成后,在其他项目中安装:
207
+
208
+ ```shell
209
+ uv add athena-kit
210
+ ```
@@ -0,0 +1,90 @@
1
+ [project]
2
+ name = "athena-kit"
3
+ version = "1.0.0"
4
+ description = "A modular Python toolkit for Athena projects."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "wangmu", email = "wangmu8889@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "pydantic>=2.13.4",
12
+ ]
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ keywords = ["athena", "toolkit", "utilities", "temporal", "pydantic"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ "Typing :: Typed",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/wangmu0115/Athena"
28
+ Repository = "https://github.com/wangmu0115/Athena"
29
+ Issues = "https://github.com/wangmu0115/Athena/issues"
30
+
31
+ [project.optional-dependencies]
32
+ dataframe = [
33
+ "pandas>=2.3.3",
34
+ ]
35
+ http = [
36
+ "httpx>=0.28.1",
37
+ ]
38
+ lark = [
39
+ "httpx>=0.28.1",
40
+ ]
41
+ matplotlib = [
42
+ "matplotlib>=3.10.9",
43
+ ]
44
+ all = [
45
+ "httpx>=0.28.1",
46
+ "matplotlib>=3.10.9",
47
+ "pandas>=2.3.3",
48
+ ]
49
+
50
+ [build-system]
51
+ requires = ["uv_build>=0.9.25,<0.12.0"]
52
+ build-backend = "uv_build"
53
+
54
+ [dependency-groups]
55
+ dev = [
56
+ "pytest>=9.0.3",
57
+ "ruff>=0.15.12",
58
+ ]
59
+
60
+ [tool.ruff]
61
+ line-length = 120
62
+ target-version = "py312"
63
+ src = [
64
+ "src",
65
+ "tests",
66
+ "examples",
67
+ ]
68
+
69
+ [tool.ruff.lint]
70
+ select = [
71
+ "E", # pycodestyle error
72
+ "F", # pyflakes
73
+ "I", # isort
74
+ "UP", # pyupgrade
75
+ "B", # flake8-bugbear
76
+ "SIM", # flake8-simplify
77
+ ]
78
+ ignore = []
79
+
80
+ [tool.ruff.format]
81
+ quote-style = "double"
82
+ indent-style = "space"
83
+ line-ending = "auto"
84
+ docstring-code-format = true
85
+ preview = true
86
+
87
+ [tool.ruff.lint.isort]
88
+ known-first-party = [
89
+ "athena_kit",
90
+ ]
@@ -0,0 +1,5 @@
1
+ """Athena Kit public namespace."""
2
+
3
+ __all__ = ("__version__",)
4
+
5
+ __version__ = "1.0.0"
@@ -0,0 +1,41 @@
1
+ from importlib import import_module
2
+
3
+
4
+ def import_attr(
5
+ attr_name: str,
6
+ module_name: str | None,
7
+ package: str | None,
8
+ ) -> object:
9
+ """Import an attribute from a module located in a package.
10
+
11
+ This utility function is used in custom `__getattr__` methods within `__init__.py`
12
+ files to dynamically import attributes.
13
+
14
+ Args:
15
+ attr_name: The name of the attribute to import.
16
+ module_name: The name of the module to import from.
17
+
18
+ If `None`, the attribute is imported from the package itself.
19
+ package: The name of the package where the module is located.
20
+
21
+ Returns:
22
+ The imported attribute.
23
+
24
+ Raises:
25
+ ImportError: If the module cannot be found.
26
+ AttributeError: If the attribute does not exist in the module or package.
27
+ """
28
+ if module_name == "__module__" or module_name is None:
29
+ try:
30
+ result = import_module(f".{attr_name}", package=package)
31
+ except ModuleNotFoundError:
32
+ msg = f"module '{package!r}' has no attribute {attr_name!r}"
33
+ raise AttributeError(msg) from None
34
+ else:
35
+ try:
36
+ module = import_module(f".{module_name}", package=package)
37
+ except ModuleNotFoundError as err:
38
+ msg = f"module '{package!r}.{module_name!r}' not found ({err})"
39
+ raise ImportError(msg) from None
40
+ result = getattr(module, attr_name)
41
+ return result
@@ -0,0 +1,32 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from athena_kit._import_utils import import_attr
4
+
5
+ if TYPE_CHECKING:
6
+ from athena_kit.bosun.parser import Lexer, Parser
7
+ from athena_kit.bosun.parser.preprocess import preprocess
8
+
9
+ __all__ = (
10
+ "Lexer",
11
+ "Parser",
12
+ "preprocess",
13
+ )
14
+
15
+ _dynamic_imports = {
16
+ "Lexer": "parser",
17
+ "Parser": "parser",
18
+ "preprocess": "parser.preprocess",
19
+ }
20
+
21
+
22
+ def __getattr__(attr_name: str) -> object:
23
+ module_name = _dynamic_imports.get(attr_name)
24
+ if module_name is None:
25
+ raise AttributeError(f"module {__name__!r} has no attribute {attr_name!r}")
26
+ result = import_attr(attr_name, module_name, __spec__.parent)
27
+ globals()[attr_name] = result
28
+ return result
29
+
30
+
31
+ def __dir__() -> list[str]:
32
+ return list(__all__)