nonebot-plugin-htmlrender 0.6.8__tar.gz → 0.7.0a2__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.0a2/.github/workflows/_test-os-arch.yml +67 -0
- nonebot_plugin_htmlrender-0.7.0a2/.github/workflows/codecov.yml +20 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/PKG-INFO +2 -1
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/browser.py +85 -21
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/config.py +14 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/install.py +4 -1
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/pyproject.toml +2 -1
- nonebot_plugin_htmlrender-0.7.0a2/tests/conftest.py +42 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/test_htmlrender.py +2 -1
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/uv.lock +313 -238
- 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.0a2}/.dockerignore +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/.github/workflows/docker_image.yml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/.github/workflows/publish.yml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/.gitignore +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/.pre-commit-config.yaml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/.python-version +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/LICENSE +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/README.md +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/docker-compose.yaml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/dockerfile +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/docs/example.md +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/docs/html2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/docs/md2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/docs/template2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/docs/text2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/entrypoint.sh +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/docker-compose.yaml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/entrypoint.sh +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/html2pic.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/templates/markdown.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/templates/mystyle.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/templates/progress.html.jinja2 +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/templates/text.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/plugins/render/utils.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/example/pyproject.toml +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/consts.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/data_source.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/process.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/signal.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/github-markdown-light.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/katex/katex.min.b64_fonts.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/katex/katex.min.js +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/katex/mathtex-script-type.min.js +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/katex/mhchem.min.js +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/markdown.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/pygments-default.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/text.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/templates/text.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/nonebot_plugin_htmlrender/utils.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/resources/test_template_filter.png +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/templates/markdown.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/templates/mystyle.css +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/templates/progress.html.jinja2 +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/templates/text.html +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/test_browser.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/test_deprecated_decorator.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/tests/test_install.py +0 -0
- {nonebot_plugin_htmlrender-0.6.8 → nonebot_plugin_htmlrender-0.7.0a2}/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.0a2
|
|
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
|
+
)
|
|
@@ -4,6 +4,7 @@ from contextlib import asynccontextmanager
|
|
|
4
4
|
import os
|
|
5
5
|
from typing import Callable, Optional
|
|
6
6
|
from urllib.parse import urlparse
|
|
7
|
+
import sys
|
|
7
8
|
|
|
8
9
|
from nonebot import logger
|
|
9
10
|
|
|
@@ -171,6 +172,8 @@ async def execute_install_command(timeout: int) -> tuple[bool, str]:
|
|
|
171
172
|
install_signal_handler()
|
|
172
173
|
|
|
173
174
|
process = await create_process(
|
|
175
|
+
sys.executable,
|
|
176
|
+
"-m",
|
|
174
177
|
"playwright",
|
|
175
178
|
"install",
|
|
176
179
|
"--with-deps",
|
|
@@ -202,7 +205,7 @@ async def execute_install_command(timeout: int) -> tuple[bool, str]:
|
|
|
202
205
|
asyncio.gather(stdout_task, stderr_task), timeout=timeout
|
|
203
206
|
)
|
|
204
207
|
except asyncio.TimeoutError:
|
|
205
|
-
logger.error(f"Timed out ({timeout}
|
|
208
|
+
logger.error(f"Timed out ({timeout}s)")
|
|
206
209
|
await terminate_process(process)
|
|
207
210
|
return False, f"Timed out ({timeout}s)"
|
|
208
211
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nonebot-plugin-htmlrender"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0.alpha.2"
|
|
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.0a2}/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()
|