Compare commits

..

19 Commits

Author SHA1 Message Date
87e6a544a2 🔖 1.0.0.a7 2023-11-16 21:34:41 +08:00
74db1931fd 🐛 修复在多个无效参数时 Alconna 自动回复的bug 2023-11-16 21:33:24 +08:00
1ca6d1f86a 使用 zoneinfo 处理时区,并优化数据库查询逻辑 2023-11-16 16:27:06 +08:00
dependabot[bot]
7361789245 ⬆️ Bump nonebot-plugin-orm from 0.5.0 to 0.5.1 (#199) 2023-11-15 15:44:10 +00:00
fe69d8d2fe 🔖 1.0.0.a6 2023-11-15 14:37:41 +08:00
2737119865 🐛 修复 茶服 命令参数设置错误的bug 2023-11-15 14:36:54 +08:00
34a654b5df 🐛 修复只输入主命令时不发送帮助提示的bug 2023-11-15 14:34:27 +08:00
f9f39618a1 💚 修复Release CI 2023-11-15 14:02:22 +08:00
81a3c9cb79 🔖 1.0.0.a5 2023-11-15 11:44:23 +08:00
4a15c45e0a 💚 修复Release CI 2023-11-15 11:44:23 +08:00
e90ad53ee6 🐛 修复在事件响应器异常退出后 Recorder 继续执行的bug 2023-11-15 11:37:12 +08:00
0c968be163 避免 Alconna 在 ParamsUnmatched 时自动回复
🎨 将通用 handle 封装一下
2023-11-15 11:04:09 +08:00
bfadac4f79 添加配置项 请求超时时间 2023-11-15 00:43:12 +08:00
89f09cd66c 🔥 删除配置项 db_url 2023-11-15 00:37:04 +08:00
777703362e 🎨 先断开连接再删文件 2023-11-15 00:28:54 +08:00
ea5308877c 🎨 🔥 去除一个没什么用的函数 2023-11-15 00:26:55 +08:00
3cc93925a6 🐛 修复迁移旧数据库时拿错config字段的bug 2023-11-15 00:14:03 +08:00
e0bd0a9252 🐛 修复 io user info 解析错误的bug 2023-11-15 00:07:05 +08:00
d31ce48a18 💚 修复Release CI 2023-11-14 13:15:51 +08:00
13 changed files with 113 additions and 105 deletions

View File

@@ -14,22 +14,23 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry
shell: bash
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: '3.11' python-version: '3.11'
cache: "poetry" cache: "poetry"
- name: Install Poetry - run: poetry install
shell: bash shell: bash
run: |
pip install poetry
poetry install
- name: Get Version - name: Get Version
id: version id: version
run: | run: |
echo "VERSION=$(poetry version -s)" >> $GITHUB_OUTPUT echo "VERSION=$(poetry version -s)" >> $GITHUB_OUTPUT
echo "TAG_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT echo "TAG_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Check Version - name: Check Version
@@ -43,6 +44,6 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1 uses: pypa/gh-action-pypi-publish@release/v1
- name: Publish Package to GitHub Release - name: Publish Package to GitHub Release
run: gh release upload --clobber ${{ steps.version.outputs.TAG_NAME }} dist/*.tar.gz dist/*.whl run: gh release create ${{ steps.version.outputs.TAG_NAME }} dist/*.tar.gz dist/*.whl -t "🔖 ${{ steps.version.outputs.TAG_NAME }}" --generate-notes
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,4 +11,4 @@ CACHE_PATH: Path = get_cache_dir('nonebot_plugin_tetris_stats')
class Config(BaseModel): class Config(BaseModel):
"""配置类""" """配置类"""
db_url: str = 'sqlite://data/nonebot_plugin_tetris_stats/data.db' tetris_req_timeout: float = 30.0

View File

@@ -64,7 +64,7 @@ def upgrade(name: str = '') -> None:
if name: if name:
return return
try: try:
db_path = Path(config.db_path) db_path = Path(config.db_url)
except AttributeError: except AttributeError:
db_path = Path('data/nonebot_plugin_tetris_stats/data.db') db_path = Path('data/nonebot_plugin_tetris_stats/data.db')
if db_path.exists() is False: if db_path.exists() is False:
@@ -84,7 +84,7 @@ def upgrade(name: str = '') -> None:
raise RuntimeError('nonebot_plugin_tetris_stats: 请先安装 0.4.4 版本完成迁移之后再升级') raise RuntimeError('nonebot_plugin_tetris_stats: 请先安装 0.4.4 版本完成迁移之后再升级')
logger.info('nonebot_plugin_tetris_stats: 发现来自老版本的数据, 正在迁移...') logger.info('nonebot_plugin_tetris_stats: 发现来自老版本的数据, 正在迁移...')
migrate_old_data(connection) migrate_old_data(connection)
db_path.unlink() db_path.unlink()
def downgrade(name: str = '') -> None: def downgrade(name: str = '') -> None:

View File

@@ -1,7 +1,12 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from datetime import UTC, datetime from datetime import UTC, datetime
from typing import Any
from nonebot.matcher import Matcher
from nonebot_plugin_alconna import AlcMatches, AlconnaMatcher
from ..utils.exception import MessageFormatError
from ..utils.typing import CommandType, GameType from ..utils.typing import CommandType, GameType
@@ -65,6 +70,9 @@ class Processor(ABC):
def __del__(self) -> None: def __del__(self) -> None:
finish_time = datetime.now(tz=UTC) finish_time = datetime.now(tz=UTC)
if Recorder.is_error_event(self.event_id):
Recorder.del_error_event(self.event_id)
return
historical_data = Recorder.get_historical_data(self.event_id) historical_data = Recorder.get_historical_data(self.event_id)
historical_data.game_platform = self.game_platform historical_data.game_platform = self.game_platform
historical_data.command_type = self.command_type historical_data.command_type = self.command_type
@@ -75,6 +83,24 @@ class Processor(ABC):
Recorder.update_historical_data(self.event_id, historical_data) Recorder.update_historical_data(self.event_id, historical_data)
def add_default_handlers(matcher: type[AlconnaMatcher]) -> None:
@matcher.handle()
async def _(matcher: Matcher, account: MessageFormatError):
await matcher.finish(str(account))
@matcher.handle()
async def _(matcher: Matcher, matches: AlcMatches):
if matches.head_matched and matches.options != {} or matches.main_args == {}:
await matcher.finish(
(f'{matches.error_info!r}\n' if matches.error_info is not None else '')
+ f'输入"{matches.header_result} --help"查看帮助'
)
@matcher.handle()
async def _(matcher: Matcher, other: Any): # noqa: ANN401
await matcher.finish()
from . import ( # noqa: F401, E402 from . import ( # noqa: F401, E402
io_data_processor, io_data_processor,
top_data_processor, top_data_processor,

View File

@@ -1,17 +1,19 @@
from datetime import timedelta from datetime import timedelta
from zoneinfo import ZoneInfo
from arclet.alconna import Alconna, Arg, ArgFlag, Args, CommandMeta, Option from arclet.alconna import Alconna, AllParam, Arg, ArgFlag, Args, CommandMeta, Option
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot_plugin_alconna import At, on_alconna from nonebot_plugin_alconna import At, on_alconna
from nonebot_plugin_orm import get_session from nonebot_plugin_orm import get_session
from sqlalchemy import select from sqlalchemy import func, select
from ...db import query_bind_info from ...db import query_bind_info
from ...utils.exception import MessageFormatError, NeedCatchError from ...utils.exception import NeedCatchError
from ...utils.metrics import get_metrics from ...utils.metrics import get_metrics
from ...utils.platform import get_platform from ...utils.platform import get_platform
from ...utils.typing import Me from ...utils.typing import Me
from .. import add_default_handlers
from ..constant import BIND_COMMAND, QUERY_COMMAND from ..constant import BIND_COMMAND, QUERY_COMMAND
from .constant import GAME_TYPE from .constant import GAME_TYPE
from .model import IORank from .model import IORank
@@ -65,6 +67,7 @@ alc = on_alconna(
dest='rank', dest='rank',
help_text='查询 IO 段位信息', help_text='查询 IO 段位信息',
), ),
Arg('other', AllParam, flags=[ArgFlag.HIDDEN, ArgFlag.OPTIONAL]),
meta=CommandMeta( meta=CommandMeta(
description='查询 TETR.IO 的信息', description='查询 TETR.IO 的信息',
example='io绑定scdhh\nio查我\niorankx', example='io绑定scdhh\nio查我\niorankx',
@@ -130,7 +133,7 @@ async def _(event: Event, matcher: Matcher, account: User):
@alc.assign('rank') @alc.assign('rank')
async def _(event: Event, matcher: Matcher, rank: Rank): async def _(matcher: Matcher, rank: Rank):
if rank == 'z': if rank == 'z':
await matcher.finish('暂不支持查询未知段位') await matcher.finish('暂不支持查询未知段位')
try: try:
@@ -138,13 +141,25 @@ async def _(event: Event, matcher: Matcher, rank: Rank):
except NeedCatchError as e: except NeedCatchError as e:
await matcher.finish(str(f'段位信息获取失败\n{e}')) await matcher.finish(str(f'段位信息获取失败\n{e}'))
async with get_session() as session: async with get_session() as session:
data = ( latest_data = (
await session.scalars(select(IORank).where(IORank.rank == rank).order_by(IORank.id.desc()).limit(5)) await session.scalars(select(IORank).where(IORank.rank == rank).order_by(IORank.id.desc()).limit(1))
).all() ).one()
latest_data = data[0] compare_data = (
await session.scalars(
select(IORank)
.where(IORank.rank == rank)
.order_by(
func.abs(
func.julianday(IORank.create_time)
- func.julianday(latest_data.create_time - timedelta(hours=24))
)
)
.limit(1)
)
).one()
message = f'{rank.upper()} 段 分数线 {latest_data.tr_line:.2f} TR, {latest_data.player_count} 名玩家\n' message = f'{rank.upper()} 段 分数线 {latest_data.tr_line:.2f} TR, {latest_data.player_count} 名玩家\n'
if len(data) > 1: if compare_data.id != latest_data.id:
message += f'对比 {(latest_data.create_time-data[-1].create_time).total_seconds()/3600:.2f} 小时前趋势: {f"{difference:.2f}" if (difference:=latest_data.tr_line-data[-1].tr_line) > 0 else f"{-difference:.2f}" if difference < 0 else ""}' message += f'对比 {(latest_data.create_time-compare_data.create_time).total_seconds()/3600:.2f} 小时前趋势: {f"{difference:.2f}" if (difference:=latest_data.tr_line-compare_data.tr_line) > 0 else f"{-difference:.2f}" if difference < 0 else ""}'
else: else:
message += '暂无对比数据' message += '暂无对比数据'
avg = get_metrics(pps=latest_data.avg_pps, apm=latest_data.avg_apm, vs=latest_data.avg_vs) avg = get_metrics(pps=latest_data.avg_pps, apm=latest_data.avg_apm, vs=latest_data.avg_vs)
@@ -169,11 +184,9 @@ async def _(event: Event, matcher: Matcher, rank: Rank):
f'APM: {latest_data.high_apm[1]} By: {latest_data.high_apm[0]["name"].upper()}\n' f'APM: {latest_data.high_apm[1]} By: {latest_data.high_apm[0]["name"].upper()}\n'
f'ADPM: {max_vs.adpm} ( {max_vs.vs}vs ) By: {latest_data.high_vs[0]["name"].upper()}\n' f'ADPM: {max_vs.adpm} ( {max_vs.vs}vs ) By: {latest_data.high_vs[0]["name"].upper()}\n'
'\n' '\n'
f'数据更新时间: {(latest_data.create_time+timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")}' f'数据更新时间: {latest_data.create_time.replace(tzinfo=ZoneInfo("UTC")).astimezone(ZoneInfo("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")}'
) )
await matcher.finish(message) await matcher.finish(message)
@alc.handle() add_default_handlers(alc)
async def _(matcher: Matcher, account: MessageFormatError):
await matcher.finish(str(account))

View File

@@ -29,9 +29,9 @@ class SuccessModel(BaseSuccessModel):
prev_at: Literal[-1] prev_at: Literal[-1]
percentile: Literal[-1] percentile: Literal[-1]
percentile_rank: Literal['z'] percentile_rank: Literal['z']
apm: None apm: None = Field(None)
pps: None pps: None = Field(None)
vs: None vs: None = Field(None)
decaying: bool decaying: bool
class NeverRatedLeague(BaseModel): class NeverRatedLeague(BaseModel):
@@ -111,7 +111,7 @@ class SuccessModel(BaseSuccessModel):
Ignore this field if the user is not a supporter.""" Ignore this field if the user is not a supporter."""
bio: str | None bio: str | None
connections: Connections connections: Connections
friend_count: int friend_count: int | None
distinguishment: Distinguishment | None distinguishment: Distinguishment | None
user: User user: User

View File

@@ -1,13 +1,14 @@
from arclet.alconna import Alconna, Arg, ArgFlag, Args, CommandMeta, Option from arclet.alconna import Alconna, AllParam, Arg, ArgFlag, Args, CommandMeta, Option
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot_plugin_alconna import At, on_alconna from nonebot_plugin_alconna import At, on_alconna
from nonebot_plugin_orm import get_session from nonebot_plugin_orm import get_session
from ...db import query_bind_info from ...db import query_bind_info
from ...utils.exception import MessageFormatError, NeedCatchError from ...utils.exception import NeedCatchError
from ...utils.platform import get_platform from ...utils.platform import get_platform
from ...utils.typing import Me from ...utils.typing import Me
from .. import add_default_handlers
from ..constant import BIND_COMMAND, QUERY_COMMAND from ..constant import BIND_COMMAND, QUERY_COMMAND
from .constant import GAME_TYPE from .constant import GAME_TYPE
from .processor import Processor, User, identify_user_info from .processor import Processor, User, identify_user_info
@@ -51,6 +52,7 @@ alc = on_alconna(
dest='query', dest='query',
help_text='查询 TOP 游戏信息', help_text='查询 TOP 游戏信息',
), ),
Arg('other', AllParam, flags=[ArgFlag.HIDDEN, ArgFlag.OPTIONAL]),
meta=CommandMeta( meta=CommandMeta(
description='查询 TetrisOnline波兰服 的信息', description='查询 TetrisOnline波兰服 的信息',
example='top绑定scdhh\ntop查我', example='top绑定scdhh\ntop查我',
@@ -113,6 +115,4 @@ async def _(event: Event, matcher: Matcher, account: User):
await matcher.finish(str(e)) await matcher.finish(str(e))
@alc.handle() add_default_handlers(alc)
async def _(matcher: Matcher, account: MessageFormatError):
await matcher.finish(str(account))

View File

@@ -1,13 +1,14 @@
from arclet.alconna import Alconna, Arg, ArgFlag, Args, CommandMeta, Option from arclet.alconna import Alconna, AllParam, Arg, ArgFlag, Args, CommandMeta, Option
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot_plugin_alconna import At, on_alconna from nonebot_plugin_alconna import At, on_alconna
from nonebot_plugin_orm import get_session from nonebot_plugin_orm import get_session
from ...db import query_bind_info from ...db import query_bind_info
from ...utils.exception import MessageFormatError, NeedCatchError from ...utils.exception import NeedCatchError
from ...utils.platform import get_platform from ...utils.platform import get_platform
from ...utils.typing import Me from ...utils.typing import Me
from .. import add_default_handlers
from ..constant import BIND_COMMAND, QUERY_COMMAND from ..constant import BIND_COMMAND, QUERY_COMMAND
from .constant import GAME_TYPE from .constant import GAME_TYPE
from .processor import Processor, User, identify_user_info from .processor import Processor, User, identify_user_info
@@ -52,6 +53,7 @@ alc = on_alconna(
dest='query', dest='query',
help_text='查询 茶服 游戏信息', help_text='查询 茶服 游戏信息',
), ),
Arg('other', AllParam, flags=[ArgFlag.HIDDEN, ArgFlag.OPTIONAL]),
meta=CommandMeta( meta=CommandMeta(
description='查询 TetrisOnline茶服 的信息', description='查询 TetrisOnline茶服 的信息',
example='茶服查我', example='茶服查我',
@@ -138,6 +140,4 @@ async def _(event: Event, matcher: Matcher, account: User):
await matcher.finish(str(e)) await matcher.finish(str(e))
@alc.handle() add_default_handlers(alc)
async def _(matcher: Matcher, account: MessageFormatError):
await matcher.finish(str(account))

View File

@@ -1,6 +1,7 @@
import sys import sys
from os import environ from os import environ
from platform import system from platform import system
from re import sub
from nonebot import get_driver from nonebot import get_driver
from nonebot.log import logger from nonebot.log import logger
@@ -33,12 +34,12 @@ class BrowserManager:
raise ImportError('加载失败, Windows 必须设置 FASTAPI_RELOAD=false 才能正常运行 playwright') raise ImportError('加载失败, Windows 必须设置 FASTAPI_RELOAD=false 才能正常运行 playwright')
logger.info('开始 安装/更新 playwright 浏览器') logger.info('开始 安装/更新 playwright 浏览器')
environ['PLAYWRIGHT_DOWNLOAD_HOST'] = 'https://npmmirror.com/mirrors/playwright/' environ['PLAYWRIGHT_DOWNLOAD_HOST'] = 'https://npmmirror.com/mirrors/playwright/'
if cls._handle_error(cls._call_playwright(['', 'install', 'firefox'])): if cls._call_playwright(['', 'install', 'firefox']):
logger.success('安装/更新 playwright 浏览器成功') logger.success('安装/更新 playwright 浏览器成功')
else: else:
logger.warning('playwright 浏览器 安装/更新 失败, 尝试使用原始仓库下载') logger.warning('playwright 浏览器 安装/更新 失败, 尝试使用原始仓库下载')
del environ['PLAYWRIGHT_DOWNLOAD_HOST'] del environ['PLAYWRIGHT_DOWNLOAD_HOST']
if cls._handle_error(cls._call_playwright(['', 'install', 'firefox'])): if cls._call_playwright(['', 'install', 'firefox']):
logger.success('安装/更新 playwright 浏览器成功') logger.success('安装/更新 playwright 浏览器成功')
else: else:
logger.error('安装/更新 playwright 浏览器失败') logger.error('安装/更新 playwright 浏览器失败')
@@ -52,26 +53,20 @@ class BrowserManager:
logger.success('playwright 启动成功') logger.success('playwright 启动成功')
@classmethod @classmethod
def _call_playwright(cls, argv: list[str]) -> BaseException: def _call_playwright(cls, argv: list[str]) -> bool:
"""等价于调用 playwright 的命令行程序""" """等价于调用 playwright 的命令行程序"""
argv_backup = sys.argv.copy() argv_backup = sys.argv.copy()
from re import sub
sys.argv[0] = sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) sys.argv[0] = sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.argv = argv sys.argv = argv
try: try:
main() main()
except BaseException as e: # noqa: BLE001 不在这里处理 playwright 的异常 except SystemExit as e:
return e return e.code == 0
except BaseException: # noqa: BLE001
return False
finally: finally:
sys.argv = argv_backup sys.argv = argv_backup
return SystemExit(0) return True
@classmethod
def _handle_error(cls, error: BaseException) -> bool:
if isinstance(error, SystemExit) and error.code == 0:
return True
return False
@classmethod @classmethod
async def _start_browser(cls) -> Browser: async def _start_browser(cls) -> Browser:

View File

@@ -15,6 +15,7 @@ driver = get_driver()
class Recorder: class Recorder:
matchers: ClassVar[set[type[Matcher]]] = set() matchers: ClassVar[set[type[Matcher]]] = set()
historical_data: ClassVar[dict[int, tuple[HistoricalData, bool]]] = {} historical_data: ClassVar[dict[int, tuple[HistoricalData, bool]]] = {}
error_event: ClassVar[set[int]] = set()
@classmethod @classmethod
def create_historical_data(cls, event_id: int, historical_data: HistoricalData) -> None: def create_historical_data(cls, event_id: int, historical_data: HistoricalData) -> None:
@@ -32,17 +33,27 @@ class Recorder:
@classmethod @classmethod
async def save_historical_data(cls, event_id: int) -> None: async def save_historical_data(cls, event_id: int) -> None:
if event_id not in cls.historical_data: historical_data, completed = cls.del_historical_data(event_id)
raise KeyError
historical_data, completed = cls.historical_data.pop(event_id)
if completed: if completed:
async with get_session() as session: async with get_session() as session:
session.add(historical_data) session.add(historical_data)
await session.commit() await session.commit()
@classmethod @classmethod
def del_historical_data(cls, event_id: int) -> None: def del_historical_data(cls, event_id: int) -> tuple[HistoricalData, bool]:
cls.historical_data.pop(event_id) return cls.historical_data.pop(event_id)
@classmethod
def add_error_event(cls, event_id: int) -> None:
cls.error_event.add(event_id)
@classmethod
def del_error_event(cls, event_id: int) -> None:
cls.error_event.remove(event_id)
@classmethod
def is_error_event(cls, event_id: int) -> bool:
return event_id in cls.error_event
@driver.on_startup @driver.on_startup
@@ -73,7 +84,9 @@ def _(bot: Bot, event: Event, matcher: Matcher):
@run_postprocessor @run_postprocessor
async def _(event: Event, matcher: Matcher, exception: Exception | None): async def _(event: Event, matcher: Matcher, exception: Exception | None):
if isinstance(matcher, tuple(Recorder.matchers)): if isinstance(matcher, tuple(Recorder.matchers)):
event_id = id(event)
if exception is not None: if exception is not None:
Recorder.del_historical_data(id(event)) Recorder.add_error_event(event_id)
Recorder.del_historical_data(event_id)
else: else:
await Recorder.save_historical_data(id(event)) await Recorder.save_historical_data(event_id)

View File

@@ -7,11 +7,12 @@ from nonebot.log import logger
from playwright.async_api import Response from playwright.async_api import Response
from ujson import JSONDecodeError, dumps, loads from ujson import JSONDecodeError, dumps, loads
from ..config.config import CACHE_PATH from ..config.config import CACHE_PATH, Config
from .browser import BrowserManager from .browser import BrowserManager
from .exception import RequestError from .exception import RequestError
driver = get_driver() driver = get_driver()
config = Config.parse_obj(driver.config)
@driver.on_startup @driver.on_startup
@@ -115,7 +116,7 @@ class Request:
async def request(cls, url: str, *, is_json: bool = True) -> bytes: async def request(cls, url: str, *, is_json: bool = True) -> bytes:
"""请求api""" """请求api"""
try: try:
async with AsyncClient(cookies=cls._cookies) as session: async with AsyncClient(cookies=cls._cookies, timeout=config.tetris_req_timeout) as session:
response = await session.get(url, headers=cls._headers) response = await session.get(url, headers=cls._headers)
if is_json: if is_json:
loads(response.content) loads(response.content)

47
poetry.lock generated
View File

@@ -926,13 +926,13 @@ typing-extensions = ">=4.0.0"
[[package]] [[package]]
name = "nonebot-plugin-orm" name = "nonebot-plugin-orm"
version = "0.5.0" version = "0.5.1"
description = "SQLAlchemy ORM support for nonebot" description = "SQLAlchemy ORM support for nonebot"
optional = false optional = false
python-versions = "<4.0,>=3.8" python-versions = "<4.0,>=3.8"
files = [ files = [
{file = "nonebot_plugin_orm-0.5.0-py3-none-any.whl", hash = "sha256:e8d0e3b11c592e8d7cef3d635f500a5f7bf45b042eb225907c40dd23e4e2b2bd"}, {file = "nonebot_plugin_orm-0.5.1-py3-none-any.whl", hash = "sha256:5f1f74aed93a56ea3743b40b9a6b4ffb1d53e6359928f51ef7ffad1ae3d83181"},
{file = "nonebot_plugin_orm-0.5.0.tar.gz", hash = "sha256:2bf51bdc30ee3dc797c5032dc92dbcf34d7eb42d09dd6b527228033807d33a56"}, {file = "nonebot_plugin_orm-0.5.1.tar.gz", hash = "sha256:7e3f84fcc932f28f4c235bf2f1bd26da11988f4245bc499dfb781d379816b2d9"},
] ]
[package.dependencies] [package.dependencies]
@@ -985,47 +985,6 @@ httpx = ["httpx[http2] (>=0.20.0,<1.0.0)"]
quart = ["Quart (>=0.18.0,<1.0.0)", "uvicorn[standard] (>=0.20.0,<1.0.0)"] quart = ["Quart (>=0.18.0,<1.0.0)", "uvicorn[standard] (>=0.20.0,<1.0.0)"]
websockets = ["websockets (>=10.0)"] websockets = ["websockets (>=10.0)"]
[[package]]
name = "numpy"
version = "1.26.1"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = "<3.13,>=3.9"
files = [
{file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"},
{file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"},
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"},
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"},
{file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"},
{file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"},
{file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"},
{file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"},
{file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"},
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"},
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"},
{file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"},
{file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"},
{file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"},
{file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"},
{file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"},
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"},
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"},
{file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"},
{file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"},
{file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"},
{file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"},
{file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"},
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"},
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"},
{file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"},
{file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"},
{file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"},
{file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"},
]
[[package]] [[package]]
name = "numpy" name = "numpy"
version = "1.26.2" version = "1.26.2"

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = 'nonebot-plugin-tetris-stats' name = 'nonebot-plugin-tetris-stats'
version = '1.0.0.a4' version = '1.0.0.a7'
description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件' description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件'
authors = ['scdhh <wallfjjd@gmail.com>'] authors = ['scdhh <wallfjjd@gmail.com>']
readme = 'README.md' readme = 'README.md'