nonebot-plugin-htmlrender 0.6.8__tar.gz → 0.7.0a1__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_htmlrender-0.7.0a1/.github/workflows/_test-os-arch.yml +67 -0
- nonebot_plugin_htmlrender-0.7.0a1/.github/workflows/codecov.yml +20 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/PKG-INFO +2 -1
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/browser.py +85 -21
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/config.py +14 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/install.py +1 -1
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/pyproject.toml +2 -1
- nonebot_plugin_htmlrender-0.7.0a1/tests/conftest.py +42 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/test_htmlrender.py +2 -1
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/uv.lock +19 -8
- nonebot_plugin_htmlrender-0.6.8/.github/workflows/codecov.yml +0 -43
- nonebot_plugin_htmlrender-0.6.8/tests/conftest.py +0 -15
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.dockerignore +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.github/workflows/docker_image.yml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.github/workflows/publish.yml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.gitignore +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.pre-commit-config.yaml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.python-version +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/LICENSE +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/README.md +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/docker-compose.yaml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/dockerfile +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/docs/example.md +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/docs/html2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/docs/md2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/docs/template2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/docs/text2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/entrypoint.sh +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/docker-compose.yaml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/entrypoint.sh +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/html2pic.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/templates/markdown.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/templates/mystyle.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/templates/progress.html.jinja2 +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/templates/text.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/plugins/render/utils.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/pyproject.toml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/consts.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/data_source.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/process.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/signal.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/github-markdown-light.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/katex/katex.min.b64_fonts.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/katex/katex.min.js +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/katex/mathtex-script-type.min.js +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/katex/mhchem.min.js +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/markdown.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/pygments-default.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/text.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/templates/text.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/nonebot_plugin_htmlrender/utils.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/resources/test_template_filter.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/markdown.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/mystyle.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/progress.html.jinja2 +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/text.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/test_browser.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/test_deprecated_decorator.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/test_install.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/test_process.py +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
on:
|
|
2
|
+
workflow_call:
|
|
3
|
+
inputs:
|
|
4
|
+
python-version:
|
|
5
|
+
required: true
|
|
6
|
+
type: string
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Test (Py ${{ inputs.python-version }} — ${{ matrix.os_label }})
|
|
11
|
+
runs-on: ${{ matrix.runs_on }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: true
|
|
14
|
+
matrix:
|
|
15
|
+
include:
|
|
16
|
+
- runs_on: ubuntu-latest
|
|
17
|
+
os_label: ubuntu-latest x64
|
|
18
|
+
arch: x64
|
|
19
|
+
platform: linux
|
|
20
|
+
|
|
21
|
+
- runs_on: macos-latest
|
|
22
|
+
os_label: macos-latest arm64
|
|
23
|
+
arch: arm64
|
|
24
|
+
platform: macos
|
|
25
|
+
|
|
26
|
+
- runs_on: windows-latest
|
|
27
|
+
os_label: windows-latest x64
|
|
28
|
+
arch: x64
|
|
29
|
+
platform: windows
|
|
30
|
+
|
|
31
|
+
- runs_on: ubuntu-24.04-arm
|
|
32
|
+
os_label: ubuntu-24.04-arm arm64
|
|
33
|
+
arch: arm64
|
|
34
|
+
platform: linux
|
|
35
|
+
|
|
36
|
+
env:
|
|
37
|
+
OS: ${{ matrix.os_label }}
|
|
38
|
+
PYTHON_VERSION: ${{ inputs.python-version }}
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Set up uv
|
|
44
|
+
uses: astral-sh/setup-uv@v6
|
|
45
|
+
with:
|
|
46
|
+
python-version: ${{ inputs.python-version }}
|
|
47
|
+
enable-cache: true
|
|
48
|
+
cache-suffix: ${{ matrix.runs_on }}-${{ inputs.python-version }}
|
|
49
|
+
|
|
50
|
+
- name: Sync deps
|
|
51
|
+
run: uv sync --locked --all-extras --dev
|
|
52
|
+
|
|
53
|
+
- name: Install Playwright (Linux)
|
|
54
|
+
if: matrix.platform == 'linux'
|
|
55
|
+
run: uv run playwright install --with-deps && uv run playwright install --with-deps
|
|
56
|
+
- name: Install Playwright (non-Linux)
|
|
57
|
+
if: matrix.platform != 'linux'
|
|
58
|
+
run: uv run playwright install && uv run playwright install
|
|
59
|
+
|
|
60
|
+
- name: Run tests
|
|
61
|
+
run: uv run pytest -s -n auto
|
|
62
|
+
|
|
63
|
+
- name: Upload coverage to Codecov
|
|
64
|
+
uses: codecov/codecov-action@v5
|
|
65
|
+
with:
|
|
66
|
+
env_vars: OS,PYTHON_VERSION
|
|
67
|
+
verbose: true
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Code Coverage
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ master, dev , feat/*]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ master ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
per-python:
|
|
11
|
+
name: Python ${{ matrix.python-version }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
16
|
+
|
|
17
|
+
uses: ./.github/workflows/_test-os-arch.yml
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
secrets: inherit
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nonebot-plugin-htmlrender
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0a1
|
|
4
4
|
Summary: 通过浏览器渲染图片
|
|
5
5
|
Project-URL: Homepage, https://github.com/kexue-z/nonebot-plugin-htmlrender
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/kexue-z/nonebot-plugin-htmlrender/issues
|
|
@@ -37,6 +37,7 @@ Requires-Dist: playwright>=1.48.0
|
|
|
37
37
|
Requires-Dist: pygments>=2.10.0
|
|
38
38
|
Requires-Dist: pymdown-extensions>=9.1
|
|
39
39
|
Requires-Dist: python-markdown-math>=0.8
|
|
40
|
+
Requires-Dist: tenacity>=9.1.2
|
|
40
41
|
Description-Content-Type: text/markdown
|
|
41
42
|
|
|
42
43
|
# nonebot-plugin-htmlrender
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import AsyncIterator
|
|
2
|
-
from contextlib import asynccontextmanager
|
|
2
|
+
from contextlib import AsyncExitStack, asynccontextmanager
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from nonebot.log import logger
|
|
@@ -10,6 +10,7 @@ from playwright.async_api import (
|
|
|
10
10
|
Playwright,
|
|
11
11
|
async_playwright,
|
|
12
12
|
)
|
|
13
|
+
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
|
|
13
14
|
|
|
14
15
|
from nonebot_plugin_htmlrender.config import plugin_config
|
|
15
16
|
from nonebot_plugin_htmlrender.install import install_browser
|
|
@@ -127,7 +128,30 @@ async def _connect(browser_type: str, **kwargs) -> Browser:
|
|
|
127
128
|
if _playwright is not None:
|
|
128
129
|
return await _browser_cls.connect(**kwargs)
|
|
129
130
|
else:
|
|
130
|
-
raise RuntimeError("Playwright
|
|
131
|
+
raise RuntimeError("Playwright is not initialized")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@retry(
|
|
135
|
+
retry=retry_if_exception_type(RuntimeError),
|
|
136
|
+
stop=stop_after_attempt(4),
|
|
137
|
+
wait=wait_fixed(1),
|
|
138
|
+
reraise=True,
|
|
139
|
+
before_sleep=lambda retry_state: logger.warning(
|
|
140
|
+
f"Attempt {retry_state.attempt_number} failed, retrying..."
|
|
141
|
+
),
|
|
142
|
+
)
|
|
143
|
+
async def _check_env_with_install_retry(**kwargs):
|
|
144
|
+
try:
|
|
145
|
+
return await check_playwright_env(**kwargs)
|
|
146
|
+
except RuntimeError:
|
|
147
|
+
if plugin_config.htmlrender_ci_mode:
|
|
148
|
+
raise
|
|
149
|
+
try:
|
|
150
|
+
await install_browser()
|
|
151
|
+
except Exception as e:
|
|
152
|
+
logger.error(f"Browser installation failed: {e!s}")
|
|
153
|
+
raise RuntimeError(f"install_browser failed: {e}") from e
|
|
154
|
+
raise
|
|
131
155
|
|
|
132
156
|
|
|
133
157
|
@with_lock
|
|
@@ -144,8 +168,10 @@ async def startup_htmlrender(**kwargs) -> Browser:
|
|
|
144
168
|
global _browser, _playwright
|
|
145
169
|
|
|
146
170
|
await shutdown_htmlrender()
|
|
147
|
-
|
|
148
|
-
|
|
171
|
+
|
|
172
|
+
if not plugin_config.htmlrender_ci_mode:
|
|
173
|
+
clean_playwright_cache()
|
|
174
|
+
_prepare_playwright_env_vars()
|
|
149
175
|
|
|
150
176
|
_playwright = await async_playwright().start()
|
|
151
177
|
logger.debug("Playwright started")
|
|
@@ -177,31 +203,69 @@ async def startup_htmlrender(**kwargs) -> Browser:
|
|
|
177
203
|
f" '{plugin_config.htmlrender_browser_executable_path}': {e}"
|
|
178
204
|
) from e
|
|
179
205
|
else:
|
|
180
|
-
|
|
181
|
-
_browser = await check_playwright_env(**kwargs)
|
|
182
|
-
except RuntimeError:
|
|
183
|
-
await install_browser()
|
|
184
|
-
_browser = await check_playwright_env(**kwargs)
|
|
206
|
+
_browser = await _check_env_with_install_retry(**kwargs)
|
|
185
207
|
|
|
186
208
|
return _browser
|
|
187
209
|
|
|
188
210
|
|
|
189
211
|
async def shutdown_htmlrender() -> None:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
212
|
+
is_remote = bool(
|
|
213
|
+
plugin_config.htmlrender_connect or plugin_config.htmlrender_connect_over_cdp
|
|
214
|
+
)
|
|
215
|
+
async with AsyncExitStack() as stack:
|
|
216
|
+
await _schedule_browser_shutdown(stack, is_remote=is_remote)
|
|
217
|
+
await _schedule_playwright_shutdown(stack)
|
|
218
|
+
_clear_globals()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
async def _schedule_browser_shutdown(stack: AsyncExitStack, *, is_remote: bool) -> None:
|
|
222
|
+
global _browser
|
|
223
|
+
if not _browser:
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
should_close = (not is_remote) and plugin_config.htmlrender_shutdown_browser_on_exit
|
|
227
|
+
if not should_close:
|
|
228
|
+
logger.info(
|
|
229
|
+
"Skipping browser shutdown due to configuration or remote connection."
|
|
230
|
+
)
|
|
231
|
+
return
|
|
232
|
+
|
|
233
|
+
browser = _browser
|
|
234
|
+
if not browser.is_connected():
|
|
235
|
+
logger.info("Browser was already disconnected.")
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
logger.debug("Disconnecting browser...")
|
|
239
|
+
|
|
240
|
+
async def _close_browser():
|
|
241
|
+
with suppress_and_log():
|
|
242
|
+
await browser.close()
|
|
243
|
+
logger.info("Disconnected browser.")
|
|
244
|
+
|
|
245
|
+
stack.push_async_callback(_close_browser)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
async def _schedule_playwright_shutdown(stack: AsyncExitStack) -> None:
|
|
249
|
+
global _playwright
|
|
250
|
+
if not _playwright:
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
pw = _playwright
|
|
254
|
+
logger.debug("Stopping Playwright...")
|
|
255
|
+
|
|
256
|
+
async def _stop_pw():
|
|
200
257
|
with suppress_and_log():
|
|
201
|
-
|
|
202
|
-
await _playwright.stop()
|
|
258
|
+
await pw.stop()
|
|
203
259
|
logger.info("Playwright stopped.")
|
|
204
260
|
|
|
261
|
+
stack.push_async_callback(_stop_pw)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _clear_globals() -> None:
|
|
265
|
+
global _browser, _playwright
|
|
266
|
+
_browser = None
|
|
267
|
+
_playwright = None
|
|
268
|
+
|
|
205
269
|
|
|
206
270
|
async def check_playwright_env(**kwargs) -> Browser:
|
|
207
271
|
"""
|
|
@@ -3,6 +3,7 @@ from typing import Any, Optional
|
|
|
3
3
|
|
|
4
4
|
from nonebot import get_driver, get_plugin_config
|
|
5
5
|
from nonebot.compat import model_validator
|
|
6
|
+
from nonebot.log import logger
|
|
6
7
|
import nonebot_plugin_localstore as store
|
|
7
8
|
from pydantic import BaseModel, Field
|
|
8
9
|
|
|
@@ -32,6 +33,14 @@ class Config(BaseModel):
|
|
|
32
33
|
default=plugin_config_dir,
|
|
33
34
|
description="配置路径,不填则使用 `nonebot-plugin-localstore` 管理",
|
|
34
35
|
)
|
|
36
|
+
htmlrender_shutdown_browser_on_exit: bool = Field(
|
|
37
|
+
default=True,
|
|
38
|
+
description="在插件关闭时关闭浏览器实例,在连接到远程浏览器时默认为 False。",
|
|
39
|
+
)
|
|
40
|
+
htmlrender_ci_mode: bool = Field(
|
|
41
|
+
default=False,
|
|
42
|
+
description="启用CI模式,跳过浏览器安装和环境变量",
|
|
43
|
+
)
|
|
35
44
|
htmlrender_download_host: Optional[str] = Field(
|
|
36
45
|
default=None, description="下载Playwright浏览器时的主机地址。"
|
|
37
46
|
)
|
|
@@ -93,3 +102,8 @@ class Config(BaseModel):
|
|
|
93
102
|
|
|
94
103
|
global_config = get_driver().config
|
|
95
104
|
plugin_config = get_plugin_config(Config)
|
|
105
|
+
|
|
106
|
+
if plugin_config.htmlrender_ci_mode:
|
|
107
|
+
logger.info(
|
|
108
|
+
"CI mode enabled, skipping browser installation and environment variable setup."
|
|
109
|
+
)
|
|
@@ -202,7 +202,7 @@ async def execute_install_command(timeout: int) -> tuple[bool, str]:
|
|
|
202
202
|
asyncio.gather(stdout_task, stderr_task), timeout=timeout
|
|
203
203
|
)
|
|
204
204
|
except asyncio.TimeoutError:
|
|
205
|
-
logger.error(f"Timed out ({timeout}
|
|
205
|
+
logger.error(f"Timed out ({timeout}s)")
|
|
206
206
|
await terminate_process(process)
|
|
207
207
|
return False, f"Timed out ({timeout}s)"
|
|
208
208
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nonebot-plugin-htmlrender"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0.alpha.1"
|
|
4
4
|
description = "通过浏览器渲染图片"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "kexue", email = "x@kexue-cloud.cn" }]
|
|
@@ -16,6 +16,7 @@ dependencies = [
|
|
|
16
16
|
"pygments>=2.10.0",
|
|
17
17
|
"pymdown-extensions>=9.1",
|
|
18
18
|
"python-markdown-math>=0.8",
|
|
19
|
+
"tenacity>=9.1.2",
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
[project.urls]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import gc
|
|
2
|
+
|
|
3
|
+
import anyio
|
|
4
|
+
import nonebot
|
|
5
|
+
from nonebug import NONEBOT_INIT_KWARGS
|
|
6
|
+
import pytest
|
|
7
|
+
from pytest_asyncio import is_async_test
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def pytest_configure(config: pytest.Config) -> None:
|
|
11
|
+
config.stash[NONEBOT_INIT_KWARGS] = {
|
|
12
|
+
"superusers": {"10001"},
|
|
13
|
+
"command_start": {""},
|
|
14
|
+
"log_level": "DEBUG",
|
|
15
|
+
"htmlrender_ci_mode": True,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def pytest_collection_modifyitems(items: list[pytest.Item]):
|
|
20
|
+
pytest_asyncio_tests = (item for item in items if is_async_test(item))
|
|
21
|
+
session_scope_marker = pytest.mark.asyncio(loop_scope="session")
|
|
22
|
+
for async_test in pytest_asyncio_tests:
|
|
23
|
+
async_test.add_marker(session_scope_marker, append=False)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
27
|
+
async def after_nonebot_init(after_nonebot_init: None):
|
|
28
|
+
nonebot.require("nonebot_plugin_htmlrender")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
32
|
+
async def _cleanup_playwright_session():
|
|
33
|
+
from nonebot_plugin_htmlrender import shutdown_htmlrender
|
|
34
|
+
|
|
35
|
+
yield
|
|
36
|
+
|
|
37
|
+
await shutdown_htmlrender()
|
|
38
|
+
|
|
39
|
+
gc.collect()
|
|
40
|
+
gc.collect()
|
|
41
|
+
|
|
42
|
+
await anyio.lowlevel.checkpoint()
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/test_htmlrender.py
RENAMED
|
@@ -152,7 +152,8 @@ async def test_capture_element(mocker: MockerFixture) -> None:
|
|
|
152
152
|
|
|
153
153
|
mock_page = mocker.AsyncMock()
|
|
154
154
|
mock_page.goto = mocker.AsyncMock()
|
|
155
|
-
mock_page.on = mocker.
|
|
155
|
+
mock_page.on = mocker.MagicMock()
|
|
156
|
+
mock_page.off = mocker.MagicMock()
|
|
156
157
|
mock_page.locator = mocker.MagicMock(return_value=mock_locator)
|
|
157
158
|
|
|
158
159
|
mock_cm = mocker.MagicMock()
|
|
@@ -771,7 +771,7 @@ wheels = [
|
|
|
771
771
|
|
|
772
772
|
[[package]]
|
|
773
773
|
name = "nonebot-plugin-htmlrender"
|
|
774
|
-
version = "0.
|
|
774
|
+
version = "0.7.0a1"
|
|
775
775
|
source = { editable = "." }
|
|
776
776
|
dependencies = [
|
|
777
777
|
{ name = "aiofiles" },
|
|
@@ -783,6 +783,7 @@ dependencies = [
|
|
|
783
783
|
{ name = "pygments" },
|
|
784
784
|
{ name = "pymdown-extensions" },
|
|
785
785
|
{ name = "python-markdown-math" },
|
|
786
|
+
{ name = "tenacity" },
|
|
786
787
|
]
|
|
787
788
|
|
|
788
789
|
[package.dev-dependencies]
|
|
@@ -808,6 +809,7 @@ requires-dist = [
|
|
|
808
809
|
{ name = "pygments", specifier = ">=2.10.0" },
|
|
809
810
|
{ name = "pymdown-extensions", specifier = ">=9.1" },
|
|
810
811
|
{ name = "python-markdown-math", specifier = ">=0.8" },
|
|
812
|
+
{ name = "tenacity", specifier = ">=9.1.2" },
|
|
811
813
|
]
|
|
812
814
|
|
|
813
815
|
[package.metadata.requires-dev]
|
|
@@ -1145,7 +1147,7 @@ wheels = [
|
|
|
1145
1147
|
|
|
1146
1148
|
[[package]]
|
|
1147
1149
|
name = "pydantic"
|
|
1148
|
-
version = "2.11.
|
|
1150
|
+
version = "2.11.9"
|
|
1149
1151
|
source = { registry = "https://pypi.org/simple" }
|
|
1150
1152
|
dependencies = [
|
|
1151
1153
|
{ name = "annotated-types" },
|
|
@@ -1153,9 +1155,9 @@ dependencies = [
|
|
|
1153
1155
|
{ name = "typing-extensions" },
|
|
1154
1156
|
{ name = "typing-inspection" },
|
|
1155
1157
|
]
|
|
1156
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1158
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
|
|
1157
1159
|
wheels = [
|
|
1158
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1160
|
+
{ url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
|
|
1159
1161
|
]
|
|
1160
1162
|
|
|
1161
1163
|
[[package]]
|
|
@@ -1330,16 +1332,16 @@ wheels = [
|
|
|
1330
1332
|
|
|
1331
1333
|
[[package]]
|
|
1332
1334
|
name = "pytest-asyncio"
|
|
1333
|
-
version = "1.
|
|
1335
|
+
version = "1.2.0"
|
|
1334
1336
|
source = { registry = "https://pypi.org/simple" }
|
|
1335
1337
|
dependencies = [
|
|
1336
1338
|
{ name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" },
|
|
1337
1339
|
{ name = "pytest" },
|
|
1338
|
-
{ name = "typing-extensions", marker = "python_full_version < '3.
|
|
1340
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
1339
1341
|
]
|
|
1340
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1342
|
+
sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" }
|
|
1341
1343
|
wheels = [
|
|
1342
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1344
|
+
{ url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" },
|
|
1343
1345
|
]
|
|
1344
1346
|
|
|
1345
1347
|
[[package]]
|
|
@@ -1492,6 +1494,15 @@ wheels = [
|
|
|
1492
1494
|
{ url = "https://files.pythonhosted.org/packages/ce/fd/901cfa59aaa5b30a99e16876f11abe38b59a1a2c51ffb3d7142bb6089069/starlette-0.47.3-py3-none-any.whl", hash = "sha256:89c0778ca62a76b826101e7c709e70680a1699ca7da6b44d38eb0a7e61fe4b51", size = 72991, upload-time = "2025-08-24T13:36:40.887Z" },
|
|
1493
1495
|
]
|
|
1494
1496
|
|
|
1497
|
+
[[package]]
|
|
1498
|
+
name = "tenacity"
|
|
1499
|
+
version = "9.1.2"
|
|
1500
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1501
|
+
sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" }
|
|
1502
|
+
wheels = [
|
|
1503
|
+
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
|
|
1504
|
+
]
|
|
1505
|
+
|
|
1495
1506
|
[[package]]
|
|
1496
1507
|
name = "tomli"
|
|
1497
1508
|
version = "2.2.1"
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
name: Code Coverage
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- "master"
|
|
7
|
-
- "dev"
|
|
8
|
-
pull_request:
|
|
9
|
-
branches:
|
|
10
|
-
- "master"
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
test:
|
|
14
|
-
name: Test
|
|
15
|
-
runs-on: ${{ matrix.os }}
|
|
16
|
-
strategy:
|
|
17
|
-
matrix:
|
|
18
|
-
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
19
|
-
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
20
|
-
fail-fast: false
|
|
21
|
-
env:
|
|
22
|
-
OS: ${{ matrix.os }}
|
|
23
|
-
PYTHON_VERSION: ${{ matrix.python-version }}
|
|
24
|
-
steps:
|
|
25
|
-
- name: Checkout
|
|
26
|
-
uses: actions/checkout@v4
|
|
27
|
-
|
|
28
|
-
- name: Install the latest version of uv
|
|
29
|
-
uses: astral-sh/setup-uv@v3
|
|
30
|
-
with:
|
|
31
|
-
enable-cache: true
|
|
32
|
-
python-version: ${{ matrix.python-version }}
|
|
33
|
-
|
|
34
|
-
- run: uv sync
|
|
35
|
-
shell: bash
|
|
36
|
-
|
|
37
|
-
- name: Run tests
|
|
38
|
-
run: uv run pytest -s
|
|
39
|
-
|
|
40
|
-
- name: Upload coverage to Codecov
|
|
41
|
-
uses: codecov/codecov-action@v2
|
|
42
|
-
with:
|
|
43
|
-
env_vars: OS,PYTHON_VERSION
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import nonebot
|
|
2
|
-
import pytest
|
|
3
|
-
from pytest_asyncio import is_async_test
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def pytest_collection_modifyitems(items: list[pytest.Item]):
|
|
7
|
-
pytest_asyncio_tests = (item for item in items if is_async_test(item))
|
|
8
|
-
session_scope_marker = pytest.mark.asyncio(loop_scope="session")
|
|
9
|
-
for async_test in pytest_asyncio_tests:
|
|
10
|
-
async_test.add_marker(session_scope_marker, append=False)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@pytest.fixture(scope="session", autouse=True)
|
|
14
|
-
async def after_nonebot_init(after_nonebot_init: None):
|
|
15
|
-
nonebot.require("nonebot_plugin_htmlrender")
|
|
File without changes
|
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.github/workflows/publish.yml
RENAMED
|
File without changes
|
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/.pre-commit-config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/docker-compose.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/example/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/markdown.css
RENAMED
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/mystyle.css
RENAMED
|
File without changes
|
|
File without changes
|
{nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a1}/tests/templates/text.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|