nonebot-plugin-sentry-transaction 0.1.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.
- nonebot_plugin_sentry_transaction-0.1.0/LICENSE +21 -0
- nonebot_plugin_sentry_transaction-0.1.0/PKG-INFO +132 -0
- nonebot_plugin_sentry_transaction-0.1.0/README.md +99 -0
- nonebot_plugin_sentry_transaction-0.1.0/nonebot_plugin_sentry_transaction/__init__.py +19 -0
- nonebot_plugin_sentry_transaction-0.1.0/nonebot_plugin_sentry_transaction/config.py +7 -0
- nonebot_plugin_sentry_transaction-0.1.0/nonebot_plugin_sentry_transaction/tracing.py +109 -0
- nonebot_plugin_sentry_transaction-0.1.0/pyproject.toml +135 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 呵呵です
|
|
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,132 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: nonebot-plugin-sentry-transaction
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Non-invasive Sentry tracing for NoneBot events and matchers
|
|
5
|
+
Author: shoucandanghehe
|
|
6
|
+
Author-email: shoucandanghehe <wallfjjd@gmail.com>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 呵呵です
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
Requires-Dist: nonebot-plugin-sentry>=2.0.0
|
|
29
|
+
Requires-Dist: nonebot2>=2.4.4
|
|
30
|
+
Requires-Dist: sentry-sdk>=2.15.0
|
|
31
|
+
Requires-Python: >=3.10
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
<!-- markdownlint-disable MD033 MD036 MD041 -->
|
|
35
|
+
<div align="center">
|
|
36
|
+
<a href="https://v2.nonebot.dev/store">
|
|
37
|
+
<img src="./assets/NoneBotPlugin.png" width="300" alt="logo" />
|
|
38
|
+
</a>
|
|
39
|
+
|
|
40
|
+
# nonebot-plugin-sentry-transaction
|
|
41
|
+
|
|
42
|
+
✨ NoneBot2 事件与 Matcher 的非侵入式 Sentry 性能追踪 ✨
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+

|
|
46
|
+
[](https://github.com/astral-sh/uv)
|
|
47
|
+
[](https://github.com/astral-sh/ruff)
|
|
48
|
+

|
|
49
|
+

|
|
50
|
+
[](https://codecov.io/gh/shoucandanghehe/nonebot-plugin-sentry-transaction)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
简体中文 | [English](./README.en-us.md)
|
|
55
|
+
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
## 📖 功能特性
|
|
59
|
+
|
|
60
|
+
- 每个事件产生一个 Sentry **Transaction**(`op: nonebot.event`)
|
|
61
|
+
- 每次 Matcher 运行产生一个 Sentry **Span**(`op: nonebot.matcher`)
|
|
62
|
+
- 并发事件拥有独立 trace,互不干扰
|
|
63
|
+
- 同优先级并发 Matcher 拥有独立 span
|
|
64
|
+
- httpx / SQLAlchemy / aiohttp 等集成的子 span 自动挂载
|
|
65
|
+
- Matcher 异常反映为 `internal_error` span 状态
|
|
66
|
+
|
|
67
|
+
## 🔧 前置条件
|
|
68
|
+
|
|
69
|
+
本插件**不负责**初始化 Sentry,请配合 [nonebot-plugin-sentry](https://github.com/nonebot/plugin-sentry) 使用:
|
|
70
|
+
|
|
71
|
+
```env
|
|
72
|
+
SENTRY_DSN=https://<key>@<org>.ingest.sentry.io/<project>
|
|
73
|
+
SENTRY_TRACES_SAMPLE_RATE=1.0
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
其他 Sentry 配置项请参阅 [nonebot-plugin-sentry 文档](https://github.com/nonebot/plugin-sentry)。
|
|
77
|
+
|
|
78
|
+
## 💿 安装
|
|
79
|
+
|
|
80
|
+
### 🚀 使用 uv
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uv add nonebot-plugin-sentry-transaction
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 🚀 使用 PDM
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pdm add nonebot-plugin-sentry-transaction
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 🚀 使用 Poetry
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
poetry add nonebot-plugin-sentry-transaction
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## ⚙️ 配置
|
|
99
|
+
|
|
100
|
+
| 配置项 | 默认值 | 说明 |
|
|
101
|
+
|--------|--------|------|
|
|
102
|
+
| `SENTRY_NB_TRACE_ENABLED` | `true` | 设为 `false` 可关闭事件/Matcher 追踪,同时保留 Sentry 错误上报。 |
|
|
103
|
+
|
|
104
|
+
## 📊 在 Sentry 中的呈现
|
|
105
|
+
|
|
106
|
+
**Transaction** 出现在 Performance 面板,名称来自 `event.get_event_name()`,例如 `message.private.friend`、`notice.group_upload`。
|
|
107
|
+
|
|
108
|
+
**Span** 以 Matcher 所属插件命名(`plugin_name`),回退到 `module_name` 或类名。
|
|
109
|
+
|
|
110
|
+
各 transaction/span 携带以下 tag:
|
|
111
|
+
|
|
112
|
+
| Tag | 来源 |
|
|
113
|
+
|-----|------|
|
|
114
|
+
| `adapter` | `bot.type` |
|
|
115
|
+
| `event_type` | `event.get_type()` |
|
|
116
|
+
| `matcher.plugin` | `Matcher.plugin_name` |
|
|
117
|
+
| `matcher.module` | `Matcher.module_name` |
|
|
118
|
+
|
|
119
|
+
## 🔍 工作原理
|
|
120
|
+
|
|
121
|
+
插件在加载时 monkey-patch NoneBot 的两个内部函数:
|
|
122
|
+
|
|
123
|
+
- `nonebot.message.handle_event` — 包装 `sentry_sdk.isolation_scope()` + `start_transaction()`
|
|
124
|
+
- `nonebot.message._run_matcher` — 包装 `sentry_sdk.new_scope()` + `start_span()`
|
|
125
|
+
|
|
126
|
+
同时注册 `run_postprocessor` 钩子,检测被 NoneBot 内部捕获的 Matcher 异常并将 span 状态设为 `internal_error`。
|
|
127
|
+
|
|
128
|
+
不修改任何业务插件代码。
|
|
129
|
+
|
|
130
|
+
## 📄 许可证
|
|
131
|
+
|
|
132
|
+
本项目使用 [MIT](./LICENSE) 许可证开源。
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!-- markdownlint-disable MD033 MD036 MD041 -->
|
|
2
|
+
<div align="center">
|
|
3
|
+
<a href="https://v2.nonebot.dev/store">
|
|
4
|
+
<img src="./assets/NoneBotPlugin.png" width="300" alt="logo" />
|
|
5
|
+
</a>
|
|
6
|
+
|
|
7
|
+
# nonebot-plugin-sentry-transaction
|
|
8
|
+
|
|
9
|
+
✨ NoneBot2 事件与 Matcher 的非侵入式 Sentry 性能追踪 ✨
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
[](https://github.com/astral-sh/uv)
|
|
14
|
+
[](https://github.com/astral-sh/ruff)
|
|
15
|
+

|
|
16
|
+

|
|
17
|
+
[](https://codecov.io/gh/shoucandanghehe/nonebot-plugin-sentry-transaction)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
简体中文 | [English](./README.en-us.md)
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
## 📖 功能特性
|
|
26
|
+
|
|
27
|
+
- 每个事件产生一个 Sentry **Transaction**(`op: nonebot.event`)
|
|
28
|
+
- 每次 Matcher 运行产生一个 Sentry **Span**(`op: nonebot.matcher`)
|
|
29
|
+
- 并发事件拥有独立 trace,互不干扰
|
|
30
|
+
- 同优先级并发 Matcher 拥有独立 span
|
|
31
|
+
- httpx / SQLAlchemy / aiohttp 等集成的子 span 自动挂载
|
|
32
|
+
- Matcher 异常反映为 `internal_error` span 状态
|
|
33
|
+
|
|
34
|
+
## 🔧 前置条件
|
|
35
|
+
|
|
36
|
+
本插件**不负责**初始化 Sentry,请配合 [nonebot-plugin-sentry](https://github.com/nonebot/plugin-sentry) 使用:
|
|
37
|
+
|
|
38
|
+
```env
|
|
39
|
+
SENTRY_DSN=https://<key>@<org>.ingest.sentry.io/<project>
|
|
40
|
+
SENTRY_TRACES_SAMPLE_RATE=1.0
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
其他 Sentry 配置项请参阅 [nonebot-plugin-sentry 文档](https://github.com/nonebot/plugin-sentry)。
|
|
44
|
+
|
|
45
|
+
## 💿 安装
|
|
46
|
+
|
|
47
|
+
### 🚀 使用 uv
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv add nonebot-plugin-sentry-transaction
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 🚀 使用 PDM
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pdm add nonebot-plugin-sentry-transaction
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 🚀 使用 Poetry
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
poetry add nonebot-plugin-sentry-transaction
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## ⚙️ 配置
|
|
66
|
+
|
|
67
|
+
| 配置项 | 默认值 | 说明 |
|
|
68
|
+
|--------|--------|------|
|
|
69
|
+
| `SENTRY_NB_TRACE_ENABLED` | `true` | 设为 `false` 可关闭事件/Matcher 追踪,同时保留 Sentry 错误上报。 |
|
|
70
|
+
|
|
71
|
+
## 📊 在 Sentry 中的呈现
|
|
72
|
+
|
|
73
|
+
**Transaction** 出现在 Performance 面板,名称来自 `event.get_event_name()`,例如 `message.private.friend`、`notice.group_upload`。
|
|
74
|
+
|
|
75
|
+
**Span** 以 Matcher 所属插件命名(`plugin_name`),回退到 `module_name` 或类名。
|
|
76
|
+
|
|
77
|
+
各 transaction/span 携带以下 tag:
|
|
78
|
+
|
|
79
|
+
| Tag | 来源 |
|
|
80
|
+
|-----|------|
|
|
81
|
+
| `adapter` | `bot.type` |
|
|
82
|
+
| `event_type` | `event.get_type()` |
|
|
83
|
+
| `matcher.plugin` | `Matcher.plugin_name` |
|
|
84
|
+
| `matcher.module` | `Matcher.module_name` |
|
|
85
|
+
|
|
86
|
+
## 🔍 工作原理
|
|
87
|
+
|
|
88
|
+
插件在加载时 monkey-patch NoneBot 的两个内部函数:
|
|
89
|
+
|
|
90
|
+
- `nonebot.message.handle_event` — 包装 `sentry_sdk.isolation_scope()` + `start_transaction()`
|
|
91
|
+
- `nonebot.message._run_matcher` — 包装 `sentry_sdk.new_scope()` + `start_span()`
|
|
92
|
+
|
|
93
|
+
同时注册 `run_postprocessor` 钩子,检测被 NoneBot 内部捕获的 Matcher 异常并将 span 状态设为 `internal_error`。
|
|
94
|
+
|
|
95
|
+
不修改任何业务插件代码。
|
|
96
|
+
|
|
97
|
+
## 📄 许可证
|
|
98
|
+
|
|
99
|
+
本项目使用 [MIT](./LICENSE) 许可证开源。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from nonebot import get_plugin_config, require
|
|
2
|
+
from nonebot.plugin import PluginMetadata
|
|
3
|
+
|
|
4
|
+
require('nonebot_plugin_sentry')
|
|
5
|
+
|
|
6
|
+
from .config import Config # noqa: E402
|
|
7
|
+
from .tracing import setup_tracing # noqa: E402
|
|
8
|
+
|
|
9
|
+
__plugin_meta__ = PluginMetadata(
|
|
10
|
+
name='nonebot-plugin-sentry-transaction',
|
|
11
|
+
description='NoneBot Event 与 Matcher 的非侵入式 Sentry tracing',
|
|
12
|
+
usage='配置 nonebot-plugin-sentry 完成 Sentry 初始化。设置 SENTRY_NB_TRACE_ENABLED=false 可关闭 tracing。',
|
|
13
|
+
type='library',
|
|
14
|
+
config=Config,
|
|
15
|
+
supported_adapters=None,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
config = get_plugin_config(Config)
|
|
19
|
+
setup_tracing(config)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import sys
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import nonebot.message
|
|
8
|
+
import sentry_sdk
|
|
9
|
+
from nonebot.exception import StopPropagation
|
|
10
|
+
from nonebot.message import run_postprocessor
|
|
11
|
+
from sentry_sdk.tracing import Span as SentrySpan
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from contextlib import AsyncExitStack
|
|
15
|
+
|
|
16
|
+
from nonebot.adapters import Bot, Event
|
|
17
|
+
from nonebot.matcher import Matcher
|
|
18
|
+
from nonebot.typing import T_DependencyCache, T_State
|
|
19
|
+
|
|
20
|
+
from .config import Config
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_original_handle_event = nonebot.message.handle_event
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def traced_handle_event(bot: Bot, event: Event) -> None:
|
|
27
|
+
# isolation_scope 为每个事件创建独立的隔离作用域,防止并发事件之间污染 trace 状态。
|
|
28
|
+
with sentry_sdk.isolation_scope() as scope:
|
|
29
|
+
scope.set_tag('adapter', bot.type)
|
|
30
|
+
scope.set_tag('event_type', event.get_type())
|
|
31
|
+
|
|
32
|
+
with sentry_sdk.start_transaction(op='nonebot.event', name=event.get_event_name()) as transaction:
|
|
33
|
+
transaction.set_tag('adapter', bot.type)
|
|
34
|
+
transaction.set_tag('event_type', event.get_type())
|
|
35
|
+
await _original_handle_event(bot, event)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def patch_handle_event() -> None:
|
|
39
|
+
nonebot.message.handle_event = traced_handle_event
|
|
40
|
+
|
|
41
|
+
# Adapter 在导入时通过 from nonebot.message import handle_event 绑定了本地引用,
|
|
42
|
+
# 仅替换模块属性无法覆盖这些引用,需遍历 sys.modules 逐一替换。
|
|
43
|
+
for module in sys.modules.values():
|
|
44
|
+
if module is nonebot.message:
|
|
45
|
+
continue
|
|
46
|
+
try:
|
|
47
|
+
module_dict = vars(module)
|
|
48
|
+
except TypeError:
|
|
49
|
+
continue
|
|
50
|
+
for attr_name, attr_value in module_dict.items():
|
|
51
|
+
if attr_value is _original_handle_event:
|
|
52
|
+
with contextlib.suppress(AttributeError, TypeError):
|
|
53
|
+
setattr(module, attr_name, traced_handle_event)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_original_run_matcher = nonebot.message._run_matcher # noqa: SLF001
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def traced_run_matcher( # noqa: PLR0913
|
|
60
|
+
Matcher: type[Matcher], # noqa: N803
|
|
61
|
+
bot: Bot,
|
|
62
|
+
event: Event,
|
|
63
|
+
state: T_State,
|
|
64
|
+
stack: AsyncExitStack | None = None,
|
|
65
|
+
dependency_cache: T_DependencyCache | None = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
# new_scope 分叉当前 scope,防止同优先级并发 matcher 互相覆盖 active span。
|
|
68
|
+
with sentry_sdk.new_scope() as scope:
|
|
69
|
+
span_name = Matcher.plugin_name or Matcher.module_name or Matcher.__name__
|
|
70
|
+
scope.set_tag('matcher.plugin', Matcher.plugin_name or 'unknown')
|
|
71
|
+
scope.set_tag('matcher.module', Matcher.module_name or 'unknown')
|
|
72
|
+
|
|
73
|
+
# 在 span 内部捕获 StopPropagation,确保 span 以 ok 状态正常结束,
|
|
74
|
+
# 随后重新抛出以保持 NoneBot 的事件传播语义。
|
|
75
|
+
stop_propagation = False
|
|
76
|
+
with sentry_sdk.start_span(op='nonebot.matcher', name=span_name):
|
|
77
|
+
try:
|
|
78
|
+
await _original_run_matcher(Matcher, bot, event, state, stack, dependency_cache)
|
|
79
|
+
except StopPropagation:
|
|
80
|
+
stop_propagation = True
|
|
81
|
+
|
|
82
|
+
if stop_propagation:
|
|
83
|
+
raise StopPropagation
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def patch_run_matcher() -> None:
|
|
87
|
+
# check_and_run_matcher 通过模块全局名调用 _run_matcher(运行时解析),
|
|
88
|
+
# 因此只需替换模块属性,无需扫描 sys.modules。
|
|
89
|
+
nonebot.message._run_matcher = traced_run_matcher # noqa: SLF001
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
async def _on_matcher_done(exception: Exception | None = None) -> None:
|
|
93
|
+
"""检测 matcher 内部异常并将 span 标记为错误。
|
|
94
|
+
|
|
95
|
+
_run_matcher 会捕获 matcher 异常但不重新抛出,导致 span 的 __exit__
|
|
96
|
+
无法感知异常。此 hook 通过 exception 参数补充设置 span 状态。
|
|
97
|
+
"""
|
|
98
|
+
span = sentry_sdk.get_current_span()
|
|
99
|
+
if isinstance(span, SentrySpan) and exception is not None:
|
|
100
|
+
span.set_status('internal_error')
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def setup_tracing(config: Config) -> None:
|
|
104
|
+
"""在插件加载时安装 tracing patch。"""
|
|
105
|
+
if not config.sentry_nb_trace_enabled or not sentry_sdk.is_initialized():
|
|
106
|
+
return
|
|
107
|
+
patch_handle_event()
|
|
108
|
+
patch_run_matcher()
|
|
109
|
+
run_postprocessor(_on_matcher_done)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nonebot-plugin-sentry-transaction"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Non-invasive Sentry tracing for NoneBot events and matchers"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "shoucandanghehe", email = "wallfjjd@gmail.com" }]
|
|
7
|
+
license = { file = "LICENSE" }
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"nonebot-plugin-sentry>=2.0.0",
|
|
11
|
+
"nonebot2>=2.4.4",
|
|
12
|
+
"sentry-sdk>=2.15.0",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["uv_build>=0.10.6,<0.11.0"]
|
|
17
|
+
build-backend = "uv_build"
|
|
18
|
+
|
|
19
|
+
[tool.uv.build-backend]
|
|
20
|
+
module-name = "nonebot_plugin_sentry_transaction"
|
|
21
|
+
module-root = ""
|
|
22
|
+
|
|
23
|
+
[tool.ruff]
|
|
24
|
+
line-length = 120
|
|
25
|
+
target-version = "py310"
|
|
26
|
+
|
|
27
|
+
[tool.ruff.lint]
|
|
28
|
+
select = [
|
|
29
|
+
"F", # pyflakes
|
|
30
|
+
"E", # pycodestyle errors
|
|
31
|
+
"W", # pycodestyle warnings
|
|
32
|
+
"C90", # mccabe
|
|
33
|
+
"I", # isort
|
|
34
|
+
"N", # PEP8-naming
|
|
35
|
+
"UP", # pyupgrade
|
|
36
|
+
"YTT", # flake8-2020
|
|
37
|
+
"ANN", # flake8-annotations
|
|
38
|
+
"ASYNC", # flake8-async
|
|
39
|
+
"S", # flake8-bandit
|
|
40
|
+
"BLE", # flake8-blind-except
|
|
41
|
+
"FBT", # flake8-boolean-trap
|
|
42
|
+
"B", # flake8-bugbear
|
|
43
|
+
"A", # flake8-builtins
|
|
44
|
+
"COM", # flake8-commas
|
|
45
|
+
"C4", # flake8-comprehensions
|
|
46
|
+
"DTZ", # flake8-datetimez
|
|
47
|
+
"T10", # flake8-debugger
|
|
48
|
+
"EM", # flake8-errmsg
|
|
49
|
+
"FA", # flake8-future-annotations
|
|
50
|
+
"ISC", # flake8-implicit-str-concat
|
|
51
|
+
"ICN", # flake8-import-conventions
|
|
52
|
+
"PIE", # flake8-pie
|
|
53
|
+
"T20", # flake8-print
|
|
54
|
+
"PYI", # flake8-pyi
|
|
55
|
+
"Q", # flake8-quotes
|
|
56
|
+
"RSE", # flake8-raise
|
|
57
|
+
"RET", # flake8-return
|
|
58
|
+
"SLF", # flake8-self
|
|
59
|
+
"SLOT", # flake8-slots
|
|
60
|
+
"SIM", # flake8-simplify
|
|
61
|
+
"TID", # flake8-tidy-imports
|
|
62
|
+
"TC", # flake8-type-checking
|
|
63
|
+
"ARG", # flake8-unused-arguments
|
|
64
|
+
"PTH", # flake8-use-pathlib
|
|
65
|
+
"ERA", # eradicate
|
|
66
|
+
"PD", # pandas-vet
|
|
67
|
+
"PGH", # pygrep-hooks
|
|
68
|
+
"PL", # pylint
|
|
69
|
+
"TRY", # tryceratops
|
|
70
|
+
"FLY", # flynt
|
|
71
|
+
"FAST", # FastAPI
|
|
72
|
+
"PERF", # Perflint
|
|
73
|
+
"FURB", # refurb
|
|
74
|
+
"RUF", # Ruff-specific rules
|
|
75
|
+
]
|
|
76
|
+
ignore = [
|
|
77
|
+
"E501", # 过长的行由 ruff format 处理, 剩余的都是字符串
|
|
78
|
+
"ANN202", # 向 NoneBot 注册的函数
|
|
79
|
+
"TRY003",
|
|
80
|
+
"COM812", # 强制尾随逗号
|
|
81
|
+
"TID252", # 相对导入
|
|
82
|
+
"ISC001", # format warning
|
|
83
|
+
"RUF002", # docstring 中的全角标点
|
|
84
|
+
"RUF003", # 注释中的全角标点
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.per-file-ignores]
|
|
88
|
+
"tests/**/*.py" = ["S101", "ANN", "PLR2004", "SIM117", "E402"]
|
|
89
|
+
|
|
90
|
+
[tool.ruff.lint.flake8-quotes]
|
|
91
|
+
inline-quotes = "single"
|
|
92
|
+
multiline-quotes = "double"
|
|
93
|
+
|
|
94
|
+
[tool.ruff.lint.flake8-annotations]
|
|
95
|
+
mypy-init-return = true
|
|
96
|
+
|
|
97
|
+
[tool.ruff.lint.flake8-builtins]
|
|
98
|
+
builtins-ignorelist = ["id"]
|
|
99
|
+
|
|
100
|
+
[tool.ruff.format]
|
|
101
|
+
quote-style = "single"
|
|
102
|
+
|
|
103
|
+
[tool.basedpyright]
|
|
104
|
+
pythonVersion = "3.10"
|
|
105
|
+
pythonPlatform = "All"
|
|
106
|
+
defineConstant = { PYDANTIC_V2 = true }
|
|
107
|
+
typeCheckingMode = "standard"
|
|
108
|
+
reportExplicitAny = 'hint'
|
|
109
|
+
reportUnnecessaryTypeIgnoreComment = 'error'
|
|
110
|
+
reportImplicitOverride = 'error'
|
|
111
|
+
reportUnnecessaryComparison = 'error'
|
|
112
|
+
reportImplicitAbstractClass = 'error'
|
|
113
|
+
enableTypeIgnoreComments = false
|
|
114
|
+
|
|
115
|
+
[dependency-groups]
|
|
116
|
+
dev = [
|
|
117
|
+
"basedpyright>=1.38.3",
|
|
118
|
+
"mypy>=1.19.1",
|
|
119
|
+
"pytest>=9.0.2",
|
|
120
|
+
"pytest-asyncio>=0.24",
|
|
121
|
+
"pytest-cov>=4.0",
|
|
122
|
+
"ruff>=0.15.7",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
[tool.pytest.ini_options]
|
|
127
|
+
asyncio_mode = "strict"
|
|
128
|
+
|
|
129
|
+
[tool.coverage.run]
|
|
130
|
+
source = ["nonebot_plugin_sentry_transaction"]
|
|
131
|
+
|
|
132
|
+
[tool.coverage.report]
|
|
133
|
+
exclude_lines = [
|
|
134
|
+
"if TYPE_CHECKING:",
|
|
135
|
+
]
|