mirror of
https://github.com/suyiiyii/nonebot-bison.git
synced 2025-06-05 19:36:43 +08:00
* feat: 实现导出存储的订阅信息的功能 * test: 编写导出功能测试 * test: 使用tmp_path * feat: 实现导入订阅文件功能 * refactor: 将订阅导入导出部分独立出来 * fix: 修复一些拼写错误 test: 完成import的第一个测试 * feat: 将订阅导入导出函数加入nb script test: 添加cli测试 * test: 完善subs import测试 * 🐛 fix nb cli entrypoint name error * fix: 修改错误的entry_point, 关闭yaml导出时对键名的排序 * fix: 使用更简短的命令名 * 🚚 将subs_io迁移到config下 * ♻️ 不再使用抛出异常的方式创建目录 * refactor: 将subscribe_export类转为函数 * refactor: 将subscribe_import类转为函数 * refactor: 根据重写的subs_io重新调整cli * test: 调整重写subs_io后的test * chore: 清理未使用的import内容 * feat(cli): 将--yaml更改为--format * test: 调整测试 * fix(cli): 为import添加不支持格式的报错 * ⚡ improve export performace * feat: subscribes_import函数不再需要传入参数函数,而是指定为add_subscribes fix: nbesf_parser在传入str时将调用parse_raw, 否则调用parse_obj * feat: subscribes_import现在会根据nbesf_data的版本选择合适的导入方式 * fix(test): 调整测试 * feat: nb bison export命令不再将文件导出到data目录,而是当前工作目录 * docs: 增添相关文档 * fix(test): 修复错误的变量名 --------- Co-authored-by: felinae98 <731499577@qq.com>
144 lines
4.0 KiB
Python
144 lines
4.0 KiB
Python
import importlib
|
|
import json
|
|
import time
|
|
from functools import partial, wraps
|
|
from pathlib import Path
|
|
from types import ModuleType
|
|
from typing import Any, Callable, Coroutine, TypeVar
|
|
|
|
from nonebot.log import logger
|
|
|
|
from ..config.subs_io import nbesf_parser, subscribes_export, subscribes_import
|
|
from ..config.subs_io.nbesf_model import SubGroup
|
|
from ..scheduler.manager import init_scheduler
|
|
|
|
try:
|
|
import anyio
|
|
import click
|
|
from typing_extensions import ParamSpec
|
|
except ImportError as e: # pragma: no cover
|
|
raise ImportError("请使用 `pip install nonebot-bison[cli]` 安装所需依赖") from e
|
|
|
|
|
|
def import_yaml_module() -> ModuleType:
|
|
try:
|
|
pyyaml = importlib.import_module("yaml")
|
|
except ImportError as e:
|
|
raise ImportError("请使用 `pip install nonebot-bison[yaml]` 安装所需依赖") from e
|
|
|
|
return pyyaml
|
|
|
|
|
|
P = ParamSpec("P")
|
|
R = TypeVar("R")
|
|
|
|
|
|
def run_sync(func: Callable[P, R]) -> Callable[P, Coroutine[Any, Any, R]]:
|
|
@wraps(func)
|
|
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
return await anyio.to_thread.run_sync(partial(func, *args, **kwargs))
|
|
|
|
return wrapper
|
|
|
|
|
|
def run_async(func: Callable[P, Coroutine[Any, Any, R]]) -> Callable[P, R]:
|
|
@wraps(func)
|
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
return anyio.from_thread.run(partial(func, *args, **kwargs))
|
|
|
|
return wrapper
|
|
|
|
|
|
@click.group()
|
|
def cli():
|
|
"""Nonebot Bison CLI"""
|
|
pass
|
|
|
|
|
|
def path_init(ctx, param, value):
|
|
if not value:
|
|
export_path = Path.cwd()
|
|
else:
|
|
export_path = Path(value)
|
|
|
|
return export_path
|
|
|
|
|
|
@cli.command(help="导出Nonebot Bison Exchangable Subcribes File", name="export")
|
|
@click.option(
|
|
"--path", "-p", default=None, callback=path_init, help="导出路径, 如果不指定,则默认为工作目录"
|
|
)
|
|
@click.option(
|
|
"--format",
|
|
default="json",
|
|
type=click.Choice(["json", "yaml", "yml"]),
|
|
help="指定导出格式[json, yaml],默认为 json",
|
|
)
|
|
@run_async
|
|
async def subs_export(path: Path, format: str):
|
|
|
|
await init_scheduler()
|
|
|
|
export_file = path / f"bison_subscribes_export_{int(time.time())}.{format}"
|
|
|
|
logger.info("正在获取订阅信息...")
|
|
export_data: SubGroup = await subscribes_export(lambda x: x)
|
|
|
|
with export_file.open("w", encoding="utf-8") as f:
|
|
match format:
|
|
case "yaml" | "yml":
|
|
logger.info("正在导出为yaml...")
|
|
|
|
pyyaml = import_yaml_module()
|
|
pyyaml.safe_dump(export_data.dict(), f, sort_keys=False)
|
|
|
|
case "json":
|
|
logger.info("正在导出为json...")
|
|
|
|
json.dump(export_data.dict(), f, indent=4, ensure_ascii=False)
|
|
|
|
case _:
|
|
raise click.BadParameter(message=f"不支持的导出格式: {format}")
|
|
|
|
logger.success(f"导出完毕!已导出到 {path} ")
|
|
|
|
|
|
@cli.command(help="从Nonebot Biosn Exchangable Subscribes File导入订阅", name="import")
|
|
@click.option("--path", "-p", required=True, help="导入文件名")
|
|
@click.option(
|
|
"--format",
|
|
default="json",
|
|
type=click.Choice(["json", "yaml", "yml"]),
|
|
help="指定导入格式[json, yaml],默认为 json",
|
|
)
|
|
@run_async
|
|
async def subs_import(path: str, format: str):
|
|
|
|
await init_scheduler()
|
|
|
|
import_file_path = Path(path)
|
|
assert import_file_path.is_file(), "该路径不是文件!"
|
|
|
|
with import_file_path.open("r", encoding="utf-8") as f:
|
|
match format:
|
|
case "yaml" | "yml":
|
|
logger.info("正在从yaml导入...")
|
|
|
|
pyyaml = import_yaml_module()
|
|
import_items = pyyaml.safe_load(f)
|
|
|
|
case "json":
|
|
logger.info("正在从json导入...")
|
|
|
|
import_items = json.load(f)
|
|
|
|
case _:
|
|
raise click.BadParameter(message=f"不支持的导入格式: {format}")
|
|
|
|
nbesf_data = nbesf_parser(import_items)
|
|
await subscribes_import(nbesf_data)
|
|
|
|
|
|
def main():
|
|
anyio.run(run_sync(cli)) # pragma: no cover
|