mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
Compare commits
2 Commits
1.0.0.a8
...
1.0.0.a1.p
| Author | SHA1 | Date | |
|---|---|---|---|
| 800b9fd66e | |||
| ee058d4a88 |
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -7,6 +7,6 @@ version: 2
|
|||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "pip" # See documentation for possible values
|
- package-ecosystem: "pip" # See documentation for possible values
|
||||||
directory: "/" # Location of package manifests
|
directory: "/" # Location of package manifests
|
||||||
target-branch: "main"
|
target-branch: "dev"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
|||||||
40
.github/workflows/Release.yml
vendored
40
.github/workflows/Release.yml
vendored
@@ -8,42 +8,18 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
contents: write
|
|
||||||
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"
|
- name: Install Poetry
|
||||||
|
|
||||||
- run: poetry install
|
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Get Version
|
|
||||||
id: version
|
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(poetry version -s)" >> $GITHUB_OUTPUT
|
pip install poetry
|
||||||
echo "TAG_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
- name: Build
|
||||||
echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
shell: bash
|
||||||
|
run: |
|
||||||
- name: Check Version
|
poetry install
|
||||||
if: steps.version.outputs.VERSION != steps.version.outputs.TAG_VERSION
|
poetry env use python
|
||||||
run: exit 1
|
poetry publish --build -u ${{ secrets.USERNAME }} -p ${{ secrets.PASSWORD }} -n
|
||||||
|
|
||||||
- name: Build Package
|
|
||||||
run: poetry build
|
|
||||||
|
|
||||||
- name: Publish Package to PyPI
|
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
|
||||||
|
|
||||||
- name: Publish Package to GitHub Release
|
|
||||||
run: gh release create ${{ steps.version.outputs.TAG_NAME }} dist/*.tar.gz dist/*.whl -t "🔖 ${{ steps.version.outputs.TAG_NAME }}" --generate-notes
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,6 +5,6 @@ Untitled*
|
|||||||
*copy*
|
*copy*
|
||||||
.vscode
|
.vscode
|
||||||
*dev*
|
*dev*
|
||||||
*_cache*
|
*cache*
|
||||||
*backup*
|
*backup*
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ CACHE_PATH: Path = get_cache_dir('nonebot_plugin_tetris_stats')
|
|||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
"""配置类"""
|
"""配置类"""
|
||||||
|
|
||||||
tetris_req_timeout: float = 30.0
|
db_url: str = 'sqlite://data/nonebot_plugin_tetris_stats/data.db'
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ def upgrade(name: str = '') -> None:
|
|||||||
if name:
|
if name:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
db_path = Path(config.db_url)
|
db_path = Path(config.db_path)
|
||||||
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:
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
"""Recreate HistoricalData
|
|
||||||
|
|
||||||
迁移 ID: 9f6582279ce2
|
|
||||||
父迁移: 9cd1647db502
|
|
||||||
创建时间: 2023-11-21 08:35:50.393246
|
|
||||||
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
|
||||||
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from alembic import op
|
|
||||||
from sqlalchemy.dialects import sqlite
|
|
||||||
|
|
||||||
from nonebot_plugin_tetris_stats.db.models import PydanticType
|
|
||||||
|
|
||||||
revision: str = '9f6582279ce2'
|
|
||||||
down_revision: str | Sequence[str] | None = '9cd1647db502'
|
|
||||||
branch_labels: str | Sequence[str] | None = None
|
|
||||||
depends_on: str | Sequence[str] | None = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade(name: str = '') -> None:
|
|
||||||
if name:
|
|
||||||
return
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
|
|
||||||
batch_op.drop_index('ix_nonebot_plugin_tetris_stats_historicaldata_command_type')
|
|
||||||
batch_op.drop_index('ix_nonebot_plugin_tetris_stats_historicaldata_game_platform')
|
|
||||||
batch_op.drop_index('ix_nonebot_plugin_tetris_stats_historicaldata_source_account')
|
|
||||||
batch_op.drop_index('ix_nonebot_plugin_tetris_stats_historicaldata_source_type')
|
|
||||||
|
|
||||||
op.drop_table('nonebot_plugin_tetris_stats_historicaldata')
|
|
||||||
|
|
||||||
op.create_table(
|
|
||||||
'nonebot_plugin_tetris_stats_historicaldata',
|
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
|
||||||
sa.Column('trigger_time', sa.DateTime(), nullable=False),
|
|
||||||
sa.Column('bot_platform', sa.String(length=32), nullable=True),
|
|
||||||
sa.Column('bot_account', sa.String(), nullable=True),
|
|
||||||
sa.Column('source_type', sa.String(length=32), nullable=True),
|
|
||||||
sa.Column('source_account', sa.String(), nullable=True),
|
|
||||||
sa.Column('message', sa.PickleType(), nullable=True),
|
|
||||||
sa.Column('game_platform', sa.String(length=32), nullable=False),
|
|
||||||
sa.Column('command_type', sa.String(length=16), nullable=False),
|
|
||||||
sa.Column('command_args', sa.JSON(), nullable=False),
|
|
||||||
sa.Column('game_user', PydanticType(), nullable=False),
|
|
||||||
sa.Column('processed_data', PydanticType(), nullable=False),
|
|
||||||
sa.Column('finish_time', sa.DateTime(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_nonebot_plugin_tetris_stats_historicaldata')),
|
|
||||||
)
|
|
||||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
|
|
||||||
batch_op.create_index(
|
|
||||||
batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_command_type'), ['command_type'], unique=False
|
|
||||||
)
|
|
||||||
batch_op.create_index(
|
|
||||||
batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_game_platform'), ['game_platform'], unique=False
|
|
||||||
)
|
|
||||||
batch_op.create_index(
|
|
||||||
batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_source_account'), ['source_account'], unique=False
|
|
||||||
)
|
|
||||||
batch_op.create_index(
|
|
||||||
batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_source_type'), ['source_type'], unique=False
|
|
||||||
)
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade(name: str = '') -> None:
|
|
||||||
if name:
|
|
||||||
return
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
|
|
||||||
batch_op.drop_index(batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_source_type'))
|
|
||||||
batch_op.drop_index(batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_source_account'))
|
|
||||||
batch_op.drop_index(batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_game_platform'))
|
|
||||||
batch_op.drop_index(batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_command_type'))
|
|
||||||
|
|
||||||
op.drop_table('nonebot_plugin_tetris_stats_historicaldata')
|
|
||||||
|
|
||||||
op.create_table(
|
|
||||||
'nonebot_plugin_tetris_stats_historicaldata',
|
|
||||||
sa.Column('id', sa.INTEGER(), nullable=False),
|
|
||||||
sa.Column('trigger_time', sa.DATETIME(), nullable=False),
|
|
||||||
sa.Column('bot_platform', sa.VARCHAR(length=32), nullable=True),
|
|
||||||
sa.Column('bot_account', sa.VARCHAR(), nullable=True),
|
|
||||||
sa.Column('source_type', sa.VARCHAR(length=32), nullable=True),
|
|
||||||
sa.Column('source_account', sa.VARCHAR(), nullable=True),
|
|
||||||
sa.Column('message', sa.BLOB(), nullable=True),
|
|
||||||
sa.Column('game_platform', sa.VARCHAR(length=32), nullable=False),
|
|
||||||
sa.Column('command_type', sa.VARCHAR(length=16), nullable=False),
|
|
||||||
sa.Column('command_args', sqlite.JSON(), nullable=False),
|
|
||||||
sa.Column('game_user', sa.BLOB(), nullable=False),
|
|
||||||
sa.Column('processed_data', sa.BLOB(), nullable=False),
|
|
||||||
sa.Column('finish_time', sa.DATETIME(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint('id', name='pk_nonebot_plugin_tetris_stats_historicaldata'),
|
|
||||||
)
|
|
||||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
|
|
||||||
batch_op.create_index(
|
|
||||||
'ix_nonebot_plugin_tetris_stats_historicaldata_source_type', ['source_type'], unique=False
|
|
||||||
)
|
|
||||||
batch_op.create_index(
|
|
||||||
'ix_nonebot_plugin_tetris_stats_historicaldata_source_account', ['source_account'], unique=False
|
|
||||||
)
|
|
||||||
batch_op.create_index(
|
|
||||||
'ix_nonebot_plugin_tetris_stats_historicaldata_game_platform', ['game_platform'], unique=False
|
|
||||||
)
|
|
||||||
batch_op.create_index(
|
|
||||||
'ix_nonebot_plugin_tetris_stats_historicaldata_command_type', ['command_type'], unique=False
|
|
||||||
)
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
@@ -1,32 +1,14 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from nonebot.adapters import Message
|
from nonebot.adapters import Message
|
||||||
from nonebot_plugin_orm import Model
|
from nonebot_plugin_orm import Model
|
||||||
from pydantic import BaseModel
|
from sqlalchemy import JSON, DateTime, PickleType, String
|
||||||
from sqlalchemy import JSON, DateTime, Dialect, PickleType, String, TypeDecorator
|
|
||||||
from sqlalchemy.orm import Mapped, MappedAsDataclass, mapped_column
|
from sqlalchemy.orm import Mapped, MappedAsDataclass, mapped_column
|
||||||
|
|
||||||
from ..game_data_processor.schemas import BaseProcessedData, BaseUser
|
from ..game_data_processor import ProcessedData, User
|
||||||
from ..utils.typing import CommandType, GameType
|
from ..utils.typing import CommandType, GameType
|
||||||
|
|
||||||
|
|
||||||
class PydanticType(TypeDecorator):
|
|
||||||
impl = JSON
|
|
||||||
|
|
||||||
def process_bind_param(self, value: Any | None, dialect: Dialect) -> str: # noqa: ANN401
|
|
||||||
# 将 Pydantic 模型实例转换为 JSON
|
|
||||||
if isinstance(value, BaseModel):
|
|
||||||
return value.json()
|
|
||||||
raise TypeError
|
|
||||||
|
|
||||||
def process_result_value(self, value: Any | None, dialect: Dialect) -> BaseModel: # noqa: ANN401
|
|
||||||
# 将 JSON 转换回 Pydantic 模型实例
|
|
||||||
if isinstance(value, str | bytes):
|
|
||||||
return BaseModel.parse_raw(value)
|
|
||||||
raise TypeError
|
|
||||||
|
|
||||||
|
|
||||||
class Bind(MappedAsDataclass, Model):
|
class Bind(MappedAsDataclass, Model):
|
||||||
id: Mapped[int] = mapped_column(init=False, primary_key=True)
|
id: Mapped[int] = mapped_column(init=False, primary_key=True)
|
||||||
chat_platform: Mapped[str] = mapped_column(String(32), index=True)
|
chat_platform: Mapped[str] = mapped_column(String(32), index=True)
|
||||||
@@ -46,6 +28,6 @@ class HistoricalData(MappedAsDataclass, Model):
|
|||||||
game_platform: Mapped[GameType] = mapped_column(String(32), index=True, init=False)
|
game_platform: Mapped[GameType] = mapped_column(String(32), index=True, init=False)
|
||||||
command_type: Mapped[CommandType] = mapped_column(String(16), index=True, init=False)
|
command_type: Mapped[CommandType] = mapped_column(String(16), index=True, init=False)
|
||||||
command_args: Mapped[list[str]] = mapped_column(JSON, init=False)
|
command_args: Mapped[list[str]] = mapped_column(JSON, init=False)
|
||||||
game_user: Mapped[BaseUser] = mapped_column(PydanticType, init=False)
|
game_user: Mapped[User] = mapped_column(PickleType, init=False)
|
||||||
processed_data: Mapped[BaseProcessedData] = mapped_column(PydanticType, init=False)
|
processed_data: Mapped[ProcessedData] = mapped_column(PickleType, init=False)
|
||||||
finish_time: Mapped[datetime] = mapped_column(DateTime, init=False)
|
finish_time: Mapped[datetime] = mapped_column(DateTime, init=False)
|
||||||
|
|||||||
@@ -1,16 +1,26 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
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.recorder import Recorder
|
|
||||||
from ..utils.typing import CommandType, GameType
|
from ..utils.typing import CommandType, GameType
|
||||||
from .schemas import BaseProcessedData as ProcessedData
|
|
||||||
from .schemas import BaseRawResponse as RawResponse
|
|
||||||
from .schemas import BaseUser as User
|
@dataclass
|
||||||
|
class User:
|
||||||
|
"""游戏用户"""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RawResponse:
|
||||||
|
"""原始请求数据"""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProcessedData:
|
||||||
|
"""处理/验证后的数据"""
|
||||||
|
|
||||||
|
|
||||||
|
from ..utils.recorder import Recorder # noqa: E402 避免循环导入
|
||||||
|
|
||||||
|
|
||||||
class Processor(ABC):
|
class Processor(ABC):
|
||||||
@@ -55,9 +65,6 @@ 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
|
||||||
@@ -68,24 +75,6 @@ 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,
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
from datetime import UTC, datetime, timedelta
|
from datetime import timedelta
|
||||||
from zoneinfo import ZoneInfo
|
|
||||||
|
|
||||||
from arclet.alconna import Alconna, AllParam, Arg, ArgFlag, Args, CommandMeta, Option
|
from arclet.alconna import Alconna, 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 AlcMatches, At, on_alconna
|
||||||
from nonebot_plugin_orm import get_session
|
from nonebot_plugin_orm import get_session
|
||||||
from sqlalchemy import func, select
|
from sqlalchemy import select
|
||||||
|
|
||||||
from ...db import query_bind_info
|
from ...db import query_bind_info
|
||||||
from ...utils.exception import NeedCatchError
|
from ...utils.exception import MessageFormatError, 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
|
||||||
from .processor import Processor, User, identify_user_info
|
from .processor import Processor, User, check_rank_data, identify_user_info
|
||||||
from .typing import Rank
|
from .typing import Rank
|
||||||
|
|
||||||
alc = on_alconna(
|
alc = on_alconna(
|
||||||
@@ -67,7 +65,6 @@ 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',
|
||||||
@@ -133,32 +130,21 @@ async def _(event: Event, matcher: Matcher, account: User):
|
|||||||
|
|
||||||
|
|
||||||
@alc.assign('rank')
|
@alc.assign('rank')
|
||||||
async def _(matcher: Matcher, rank: Rank):
|
async def _(event: Event, matcher: Matcher, rank: Rank):
|
||||||
if rank == 'z':
|
if rank == 'z':
|
||||||
await matcher.finish('暂不支持查询未知段位')
|
await matcher.finish('暂不支持查询未知段位')
|
||||||
|
try:
|
||||||
|
await check_rank_data()
|
||||||
|
except NeedCatchError as e:
|
||||||
|
await matcher.finish(str(f'段位信息获取失败\n{e}'))
|
||||||
async with get_session() as session:
|
async with get_session() as session:
|
||||||
latest_data = (
|
data = (
|
||||||
await session.scalars(select(IORank).where(IORank.rank == rank).order_by(IORank.id.desc()).limit(1))
|
await session.scalars(select(IORank).where(IORank.rank == rank).order_by(IORank.id.desc()).limit(5))
|
||||||
).one()
|
).all()
|
||||||
compare_data = (
|
latest_data = data[0]
|
||||||
await session.scalars(
|
message = f'{rank.upper()} 段 分数线 {latest_data.tr_line:.2f} TR, {latest_data.player_count} 名玩家\n'
|
||||||
select(IORank)
|
if len(data) > 1:
|
||||||
.where(IORank.rank == rank)
|
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 "→"}'
|
||||||
.order_by(
|
|
||||||
func.abs(
|
|
||||||
func.julianday(IORank.create_time)
|
|
||||||
- func.julianday(latest_data.create_time - timedelta(hours=24))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.limit(1)
|
|
||||||
)
|
|
||||||
).one()
|
|
||||||
message = ''
|
|
||||||
if (datetime.now(UTC) - latest_data.create_time) > timedelta(hours=7):
|
|
||||||
message += 'Warning: 数据超过7小时未更新, 请联系Bot主人查看后台\n'
|
|
||||||
message += f'{rank.upper()} 段 分数线 {latest_data.tr_line:.2f} TR, {latest_data.player_count} 名玩家\n'
|
|
||||||
if compare_data.id != latest_data.id:
|
|
||||||
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)
|
||||||
@@ -183,9 +169,19 @@ async def _(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.replace(tzinfo=ZoneInfo("UTC")).astimezone(ZoneInfo("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")}'
|
f'数据更新时间: {(latest_data.create_time+timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")}'
|
||||||
)
|
)
|
||||||
await matcher.finish(message)
|
await matcher.finish(message)
|
||||||
|
|
||||||
|
|
||||||
add_default_handlers(alc)
|
@alc.handle()
|
||||||
|
async def _(matcher: Matcher, account: MessageFormatError):
|
||||||
|
await matcher.finish(str(account))
|
||||||
|
|
||||||
|
|
||||||
|
@alc.handle()
|
||||||
|
async def _(matcher: Matcher, matches: AlcMatches):
|
||||||
|
if matches.head_matched:
|
||||||
|
await matcher.finish(
|
||||||
|
f'{matches.error_info!r}\n' if matches.error_info is not None else '' + '输入"io --help"查看帮助'
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
from datetime import UTC, datetime
|
|
||||||
|
|
||||||
from aiocache import Cache as ACache # type: ignore[import-untyped]
|
|
||||||
from nonebot.log import logger
|
|
||||||
from pydantic import parse_raw_as
|
|
||||||
|
|
||||||
from ...utils.request import Request
|
|
||||||
from .schemas.base import FailedModel, SuccessModel
|
|
||||||
|
|
||||||
|
|
||||||
class Cache:
|
|
||||||
cache = ACache(ACache.MEMORY)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def get(cls, url: str) -> bytes:
|
|
||||||
cached_data = await cls.cache.get(url)
|
|
||||||
if cached_data is None:
|
|
||||||
response_data = await Request.request(url)
|
|
||||||
parsed_data: SuccessModel | FailedModel = parse_raw_as(SuccessModel | FailedModel, response_data) # type: ignore[arg-type]
|
|
||||||
if isinstance(parsed_data, SuccessModel):
|
|
||||||
await cls.cache.add(
|
|
||||||
url,
|
|
||||||
response_data,
|
|
||||||
(parsed_data.cache.cached_until - datetime.now(UTC)).total_seconds(),
|
|
||||||
)
|
|
||||||
return response_data
|
|
||||||
logger.debug(f'{url}: Cache hit!')
|
|
||||||
return cached_data
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
|
from dataclasses import asdict, dataclass
|
||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
from math import floor
|
from math import floor
|
||||||
from re import match
|
from re import match
|
||||||
@@ -13,20 +14,23 @@ from sqlalchemy import select
|
|||||||
|
|
||||||
from ...db import create_or_update_bind
|
from ...db import create_or_update_bind
|
||||||
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
||||||
from ...utils.request import splice_url
|
from ...utils.request import Request, splice_url
|
||||||
from ...utils.retry import retry
|
|
||||||
from ...utils.typing import GameType
|
from ...utils.typing import GameType
|
||||||
|
from .. import ProcessedData as ProcessedDataMeta
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from .cache import Cache
|
from .. import RawResponse as RawResponseMeta
|
||||||
|
from .. import User as UserMeta
|
||||||
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
|
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
|
||||||
from .model import IORank
|
from .model import IORank
|
||||||
from .schemas.league_all import FailedModel as LeagueAllFailed
|
from .schemas.league_all import FailedModel as LeagueAllFailed
|
||||||
from .schemas.league_all import LeagueAll
|
from .schemas.league_all import LeagueAll
|
||||||
from .schemas.league_all import ValidUser as LeagueAllUser
|
from .schemas.league_all import ValidUser as LeagueAllUser
|
||||||
from .schemas.response import ProcessedData, RawResponse
|
|
||||||
from .schemas.user import User
|
|
||||||
from .schemas.user_info import FailedModel as InfoFailed
|
from .schemas.user_info import FailedModel as InfoFailed
|
||||||
from .schemas.user_info import NeverPlayedLeague, NeverRatedLeague, UserInfo
|
from .schemas.user_info import (
|
||||||
|
NeverPlayedLeague,
|
||||||
|
NeverRatedLeague,
|
||||||
|
UserInfo,
|
||||||
|
)
|
||||||
from .schemas.user_info import SuccessModel as InfoSuccess
|
from .schemas.user_info import SuccessModel as InfoSuccess
|
||||||
from .schemas.user_records import FailedModel as RecordsFailed
|
from .schemas.user_records import FailedModel as RecordsFailed
|
||||||
from .schemas.user_records import SoloRecord, UserRecords
|
from .schemas.user_records import SoloRecord, UserRecords
|
||||||
@@ -36,6 +40,24 @@ from .typing import Rank
|
|||||||
driver = get_driver()
|
driver = get_driver()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class User(UserMeta):
|
||||||
|
ID: str | None = None
|
||||||
|
name: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RawResponse(RawResponseMeta):
|
||||||
|
user_info: bytes | None = None
|
||||||
|
user_records: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProcessedData(ProcessedDataMeta):
|
||||||
|
user_info: InfoSuccess | None = None
|
||||||
|
user_records: RecordsSuccess | None = None
|
||||||
|
|
||||||
|
|
||||||
def identify_user_info(info: str) -> User | MessageFormatError:
|
def identify_user_info(info: str) -> User | MessageFormatError:
|
||||||
if match(r'^[a-f0-9]{24}$', info):
|
if match(r'^[a-f0-9]{24}$', info):
|
||||||
return User(ID=info)
|
return User(ID=info)
|
||||||
@@ -91,7 +113,7 @@ class Processor(ProcessorMeta):
|
|||||||
async def get_user_info(self) -> InfoSuccess:
|
async def get_user_info(self) -> InfoSuccess:
|
||||||
"""获取用户数据"""
|
"""获取用户数据"""
|
||||||
if self.processed_data.user_info is None:
|
if self.processed_data.user_info is None:
|
||||||
self.raw_response.user_info = await Cache.get(
|
self.raw_response.user_info = await Request.request(
|
||||||
splice_url([BASE_URL, 'users/', f'{self.user.ID or self.user.name}'])
|
splice_url([BASE_URL, 'users/', f'{self.user.ID or self.user.name}'])
|
||||||
)
|
)
|
||||||
user_info: UserInfo = parse_raw_as(UserInfo, self.raw_response.user_info) # type: ignore[arg-type]
|
user_info: UserInfo = parse_raw_as(UserInfo, self.raw_response.user_info) # type: ignore[arg-type]
|
||||||
@@ -103,10 +125,20 @@ class Processor(ProcessorMeta):
|
|||||||
async def get_user_records(self) -> RecordsSuccess:
|
async def get_user_records(self) -> RecordsSuccess:
|
||||||
"""获取Solo数据"""
|
"""获取Solo数据"""
|
||||||
if self.processed_data.user_records is None:
|
if self.processed_data.user_records is None:
|
||||||
self.raw_response.user_records = await Cache.get(
|
self.raw_response.user_records = await Request.request(
|
||||||
splice_url([BASE_URL, 'users/', f'{self.user.ID or self.user.name}/', 'records'])
|
splice_url(
|
||||||
|
[
|
||||||
|
BASE_URL,
|
||||||
|
'users/',
|
||||||
|
f'{self.user.ID or self.user.name}/',
|
||||||
|
'records',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
user_records: UserRecords = parse_raw_as(
|
||||||
|
UserRecords, # type: ignore[arg-type]
|
||||||
|
self.raw_response.user_records,
|
||||||
)
|
)
|
||||||
user_records: UserRecords = parse_raw_as(UserRecords, self.raw_response.user_records) # type: ignore[arg-type]
|
|
||||||
if isinstance(user_records, RecordsFailed):
|
if isinstance(user_records, RecordsFailed):
|
||||||
raise RequestError(f'用户Solo数据请求错误:\n{user_records.error}')
|
raise RequestError(f'用户Solo数据请求错误:\n{user_records.error}')
|
||||||
self.processed_data.user_records = user_records
|
self.processed_data.user_records = user_records
|
||||||
@@ -123,13 +155,12 @@ class Processor(ProcessorMeta):
|
|||||||
else:
|
else:
|
||||||
if isinstance(league, NeverRatedLeague):
|
if isinstance(league, NeverRatedLeague):
|
||||||
ret_message += f'用户 {user_name} 暂未完成定级赛, 最近十场的数据:'
|
ret_message += f'用户 {user_name} 暂未完成定级赛, 最近十场的数据:'
|
||||||
|
elif league.rank == 'z':
|
||||||
|
ret_message += f'用户 {user_name} 暂无段位, {round(league.rating,2)} TR'
|
||||||
else:
|
else:
|
||||||
if league.rank == 'z':
|
ret_message += (
|
||||||
ret_message += f'用户 {user_name} 暂无段位, {round(league.rating,2)} TR'
|
f'{league.rank.upper()} 段用户 {user_name} {round(league.rating,2)} TR (#{league.standing})'
|
||||||
else:
|
)
|
||||||
ret_message += (
|
|
||||||
f'{league.rank.upper()} 段用户 {user_name} {round(league.rating,2)} TR (#{league.standing})'
|
|
||||||
)
|
|
||||||
ret_message += f', 段位分 {round(league.glicko,2)}±{round(league.rd,2)}, 最近十场的数据:'
|
ret_message += f', 段位分 {round(league.glicko,2)}±{round(league.rd,2)}, 最近十场的数据:'
|
||||||
lpm = league.pps * 24
|
lpm = league.pps * 24
|
||||||
ret_message += f"\nL'PM: {round(lpm, 2)} ( {league.pps} pps )"
|
ret_message += f"\nL'PM: {round(lpm, 2)} ( {league.pps} pps )"
|
||||||
@@ -154,11 +185,13 @@ class Processor(ProcessorMeta):
|
|||||||
|
|
||||||
|
|
||||||
@scheduler.scheduled_job('cron', hour='0,6,12,18', minute=0)
|
@scheduler.scheduled_job('cron', hour='0,6,12,18', minute=0)
|
||||||
@retry(exception_type=RequestError, delay=timedelta(minutes=15))
|
|
||||||
async def get_io_rank_data() -> None:
|
async def get_io_rank_data() -> None:
|
||||||
league_all: LeagueAll = parse_raw_as(LeagueAll, await Cache.get(splice_url([BASE_URL, 'users/lists/league/all']))) # type: ignore[arg-type]
|
league_all: LeagueAll = parse_raw_as(
|
||||||
|
LeagueAll, # type: ignore[arg-type]
|
||||||
|
await Request.request(splice_url([BASE_URL, 'users/lists/league/all'])),
|
||||||
|
)
|
||||||
if isinstance(league_all, LeagueAllFailed):
|
if isinstance(league_all, LeagueAllFailed):
|
||||||
raise RequestError(f'排行榜数据请求错误:\n{league_all.error}')
|
raise RequestError(f'用户Solo数据请求错误:\n{league_all.error}')
|
||||||
|
|
||||||
def pps(user: LeagueAllUser) -> float:
|
def pps(user: LeagueAllUser) -> float:
|
||||||
return user.league.pps
|
return user.league.pps
|
||||||
@@ -181,7 +214,7 @@ async def get_io_rank_data() -> None:
|
|||||||
sort: Callable[[list[LeagueAllUser], Callable[[LeagueAllUser], float]], LeagueAllUser],
|
sort: Callable[[list[LeagueAllUser], Callable[[LeagueAllUser], float]], LeagueAllUser],
|
||||||
) -> tuple[dict[str, str], float]:
|
) -> tuple[dict[str, str], float]:
|
||||||
user = sort(users, field)
|
user = sort(users, field)
|
||||||
return User(ID=user.id, name=user.username).dict(), field(user)
|
return asdict(User(ID=user.id, name=user.username)), field(user)
|
||||||
|
|
||||||
users = [i for i in league_all.data.users if isinstance(i, LeagueAllUser)]
|
users = [i for i in league_all.data.users if isinstance(i, LeagueAllUser)]
|
||||||
rank_to_users: defaultdict[Rank, list[LeagueAllUser]] = defaultdict(list)
|
rank_to_users: defaultdict[Rank, list[LeagueAllUser]] = defaultdict(list)
|
||||||
@@ -214,8 +247,8 @@ async def get_io_rank_data() -> None:
|
|||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
@driver.on_startup
|
||||||
async def _() -> None:
|
async def check_rank_data() -> None:
|
||||||
async with get_session() as session:
|
async with get_session() as session:
|
||||||
latest_time = await session.scalar(select(IORank.create_time).order_by(IORank.id.desc()).limit(1))
|
latest_time = await session.scalar(select(IORank.create_time).order_by(IORank.id.desc()).limit(1))
|
||||||
if latest_time is None or datetime.now(tz=UTC) - latest_time.replace(tzinfo=UTC) > timedelta(hours=6):
|
if latest_time is None or datetime.now(tz=UTC) - latest_time.replace(tzinfo=UTC) > timedelta(hours=6):
|
||||||
await get_io_rank_data()
|
await get_io_rank_data()
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
from ... import ProcessedData as ProcessedDataMeta
|
|
||||||
from ... import RawResponse as RawResponseMeta
|
|
||||||
from .user_info import SuccessModel as InfoSuccess
|
|
||||||
from .user_records import SuccessModel as RecordsSuccess
|
|
||||||
|
|
||||||
|
|
||||||
class RawResponse(RawResponseMeta):
|
|
||||||
user_info: bytes | None = None
|
|
||||||
user_records: bytes | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessedData(ProcessedDataMeta):
|
|
||||||
user_info: InfoSuccess | None = None
|
|
||||||
user_records: RecordsSuccess | None = None
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
from ...schemas import BaseUser
|
|
||||||
|
|
||||||
|
|
||||||
class User(BaseUser):
|
|
||||||
ID: str | None = None
|
|
||||||
name: str | None = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_identifier(self) -> str:
|
|
||||||
if self.ID is None:
|
|
||||||
raise ValueError('不完整的User!')
|
|
||||||
return self.ID
|
|
||||||
@@ -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 = Field(None)
|
apm: None
|
||||||
pps: None = Field(None)
|
pps: None
|
||||||
vs: None = Field(None)
|
vs: 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 | None
|
friend_count: int
|
||||||
distinguishment: Distinguishment | None
|
distinguishment: Distinguishment | None
|
||||||
|
|
||||||
user: User
|
user: User
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class EndContext(BaseModel):
|
|||||||
doubles: int
|
doubles: int
|
||||||
triples: int
|
triples: int
|
||||||
quads: int
|
quads: int
|
||||||
pentas: int | None
|
|
||||||
realtspins: int
|
realtspins: int
|
||||||
minitspins: int
|
minitspins: int
|
||||||
minitspinsingles: int
|
minitspinsingles: int
|
||||||
@@ -33,7 +32,7 @@ class EndContext(BaseModel):
|
|||||||
class Garbage(BaseModel):
|
class Garbage(BaseModel):
|
||||||
sent: int
|
sent: int
|
||||||
received: int
|
received: int
|
||||||
attack: int | None
|
attack: int
|
||||||
cleared: int
|
cleared: int
|
||||||
|
|
||||||
class Finesse(BaseModel):
|
class Finesse(BaseModel):
|
||||||
@@ -46,18 +45,18 @@ class EndContext(BaseModel):
|
|||||||
level_lines: int
|
level_lines: int
|
||||||
level_lines_needed: int
|
level_lines_needed: int
|
||||||
inputs: int
|
inputs: int
|
||||||
holds: int | None
|
holds: int
|
||||||
time: Time
|
time: Time
|
||||||
score: int
|
score: int
|
||||||
zenlevel: int
|
zenlevel: int
|
||||||
zenprogress: int
|
zenprogress: int
|
||||||
level: int
|
level: int
|
||||||
combo: int
|
combo: int
|
||||||
currentcombopower: int | None # WTF
|
currentcombopower: int # WTF
|
||||||
topcombo: int
|
topcombo: int
|
||||||
btb: int
|
btb: int
|
||||||
topbtb: int
|
topbtb: int
|
||||||
currentbtbchainpower: int | None # WTF * 2
|
currentbtbchainpower: int | None # WTF * 2 40l 里有 但是 blitz 没有
|
||||||
tspins: int
|
tspins: int
|
||||||
piecesplaced: int
|
piecesplaced: int
|
||||||
clears: Clears
|
clears: Clears
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
|
|
||||||
class BaseUser(ABC, BaseModel):
|
|
||||||
"""游戏用户"""
|
|
||||||
|
|
||||||
def __eq__(self, __value: object) -> bool:
|
|
||||||
if isinstance(__value, BaseUser):
|
|
||||||
return self.unique_identifier == __value.unique_identifier
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def unique_identifier(self) -> str:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class BaseRawResponse(BaseModel):
|
|
||||||
"""原始请求数据"""
|
|
||||||
|
|
||||||
|
|
||||||
class BaseProcessedData(BaseModel):
|
|
||||||
"""处理/验证后的数据"""
|
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
from arclet.alconna import Alconna, AllParam, Arg, ArgFlag, Args, CommandMeta, Option
|
from arclet.alconna import Alconna, 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 AlcMatches, 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 NeedCatchError
|
from ...utils.exception import MessageFormatError, 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,7 +51,6 @@ 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查我',
|
||||||
@@ -115,4 +113,14 @@ async def _(event: Event, matcher: Matcher, account: User):
|
|||||||
await matcher.finish(str(e))
|
await matcher.finish(str(e))
|
||||||
|
|
||||||
|
|
||||||
add_default_handlers(alc)
|
@alc.handle()
|
||||||
|
async def _(matcher: Matcher, account: MessageFormatError):
|
||||||
|
await matcher.finish(str(account))
|
||||||
|
|
||||||
|
|
||||||
|
@alc.handle()
|
||||||
|
async def _(matcher: Matcher, matches: AlcMatches):
|
||||||
|
if matches.head_matched:
|
||||||
|
await matcher.finish(
|
||||||
|
f'{matches.error_info!r}\n' if matches.error_info is not None else '' + '输入"top --help"查看帮助'
|
||||||
|
)
|
||||||
|
|||||||
@@ -13,18 +13,26 @@ from ...db import create_or_update_bind
|
|||||||
from ...utils.exception import MessageFormatError, RequestError
|
from ...utils.exception import MessageFormatError, RequestError
|
||||||
from ...utils.request import Request, splice_url
|
from ...utils.request import Request, splice_url
|
||||||
from ...utils.typing import GameType
|
from ...utils.typing import GameType
|
||||||
|
from .. import ProcessedData as ProcessedDataMeta
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from ..schemas import BaseUser
|
from .. import RawResponse as RawResponseMeta
|
||||||
|
from .. import User as UserMeta
|
||||||
from .constant import BASE_URL, GAME_TYPE
|
from .constant import BASE_URL, GAME_TYPE
|
||||||
from .schemas.response import ProcessedData, RawResponse
|
|
||||||
|
|
||||||
|
|
||||||
class User(BaseUser):
|
@dataclass
|
||||||
|
class User(UserMeta):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_identifier(self) -> str:
|
@dataclass
|
||||||
return self.name
|
class RawResponse(RawResponseMeta):
|
||||||
|
user_profile: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProcessedData(ProcessedDataMeta):
|
||||||
|
user_profile: str | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
from ...schemas import BaseProcessedData, BaseRawResponse
|
|
||||||
|
|
||||||
|
|
||||||
class RawResponse(BaseRawResponse):
|
|
||||||
user_profile: bytes | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessedData(BaseProcessedData):
|
|
||||||
user_profile: str | None = None
|
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
from arclet.alconna import Alconna, AllParam, Arg, ArgFlag, Args, CommandMeta, Option
|
from arclet.alconna import Alconna, 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 AlcMatches, 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 NeedCatchError
|
from ...utils.exception import MessageFormatError, 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
|
||||||
@@ -53,7 +52,6 @@ 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='茶服查我',
|
||||||
@@ -140,4 +138,14 @@ async def _(event: Event, matcher: Matcher, account: User):
|
|||||||
await matcher.finish(str(e))
|
await matcher.finish(str(e))
|
||||||
|
|
||||||
|
|
||||||
add_default_handlers(alc)
|
@alc.handle()
|
||||||
|
async def _(matcher: Matcher, account: MessageFormatError):
|
||||||
|
await matcher.finish(str(account))
|
||||||
|
|
||||||
|
|
||||||
|
@alc.handle()
|
||||||
|
async def _(matcher: Matcher, matches: AlcMatches):
|
||||||
|
if matches.head_matched:
|
||||||
|
await matcher.finish(
|
||||||
|
f'{matches.error_info!r}\n' if matches.error_info is not None else '' + '输入"茶服 --help"查看帮助'
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from re import match
|
from re import match
|
||||||
|
from typing import Any
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from nonebot_plugin_orm import get_session
|
from nonebot_plugin_orm import get_session
|
||||||
@@ -9,24 +10,32 @@ from ...db import create_or_update_bind
|
|||||||
from ...utils.exception import MessageFormatError, RequestError
|
from ...utils.exception import MessageFormatError, RequestError
|
||||||
from ...utils.request import Request, splice_url
|
from ...utils.request import Request, splice_url
|
||||||
from ...utils.typing import GameType
|
from ...utils.typing import GameType
|
||||||
|
from .. import ProcessedData as ProcessedDataMeta
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from ..schemas import BaseUser
|
from .. import RawResponse as RawResponseMeta
|
||||||
|
from .. import User as UserMeta
|
||||||
from .constant import BASE_URL, GAME_TYPE
|
from .constant import BASE_URL, GAME_TYPE
|
||||||
from .schemas.response import ProcessedData, RawResponse
|
|
||||||
from .schemas.user_info import SuccessModel as InfoSuccess
|
from .schemas.user_info import SuccessModel as InfoSuccess
|
||||||
from .schemas.user_info import UserInfo
|
from .schemas.user_info import UserInfo
|
||||||
from .schemas.user_profile import UserProfile
|
from .schemas.user_profile import UserProfile
|
||||||
|
|
||||||
|
|
||||||
class User(BaseUser):
|
@dataclass
|
||||||
|
class User(UserMeta):
|
||||||
teaid: str | None = None
|
teaid: str | None = None
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_identifier(self) -> str:
|
@dataclass
|
||||||
if self.teaid is None:
|
class RawResponse(RawResponseMeta):
|
||||||
raise ValueError('不完整的User!')
|
user_profile: dict[frozenset[tuple[str, Any]], bytes]
|
||||||
return self.teaid
|
user_info: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProcessedData(ProcessedDataMeta):
|
||||||
|
user_profile: dict[frozenset[tuple[str, Any]], UserProfile]
|
||||||
|
user_info: InfoSuccess | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -126,23 +135,23 @@ class Processor(ProcessorMeta):
|
|||||||
self.processed_data.user_info = user_info
|
self.processed_data.user_info = user_info
|
||||||
return self.processed_data.user_info
|
return self.processed_data.user_info
|
||||||
|
|
||||||
async def get_user_profile(self, other_parameter: dict[str, str | bytes] | None = None) -> UserProfile:
|
async def get_user_profile(self, other_parameter: dict[str, Any] | None = None) -> UserProfile:
|
||||||
"""获取用户数据"""
|
"""获取用户数据"""
|
||||||
if other_parameter is None:
|
if other_parameter is None:
|
||||||
other_parameter = {}
|
other_parameter = {}
|
||||||
params = urlencode(dict(sorted(other_parameter.items())))
|
fset = frozenset(other_parameter.items())
|
||||||
if self.processed_data.user_profile.get(params) is None:
|
if self.processed_data.user_profile.get(fset) is None:
|
||||||
self.raw_response.user_profile[params] = await Request.request(
|
self.raw_response.user_profile[fset] = await Request.request(
|
||||||
splice_url(
|
splice_url(
|
||||||
[
|
[
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
'getProfile',
|
'getProfile',
|
||||||
f'?{urlencode({"id":self.user.teaid or self.user.name,**other_parameter})}',
|
f'?{urlencode({"id":self.user.teaid or self.user.name},**other_parameter)}',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.processed_data.user_profile[params] = UserProfile.parse_raw(self.raw_response.user_profile[params])
|
self.processed_data.user_profile[fset] = UserProfile.parse_raw(self.raw_response.user_profile[fset])
|
||||||
return self.processed_data.user_profile[params]
|
return self.processed_data.user_profile[fset]
|
||||||
|
|
||||||
async def get_game_data(self) -> GameData | None:
|
async def get_game_data(self) -> GameData | None:
|
||||||
"""获取游戏数据"""
|
"""获取游戏数据"""
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
from ...schemas import BaseProcessedData, BaseRawResponse
|
|
||||||
from .user_info import SuccessModel as InfoSuccess
|
|
||||||
from .user_profile import UserProfile
|
|
||||||
|
|
||||||
|
|
||||||
class RawResponse(BaseRawResponse):
|
|
||||||
user_profile: dict[str, bytes]
|
|
||||||
user_info: bytes | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessedData(BaseProcessedData):
|
|
||||||
user_profile: dict[str, UserProfile]
|
|
||||||
user_info: InfoSuccess | None = None
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
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
|
||||||
@@ -34,12 +33,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._call_playwright(['', 'install', 'firefox']):
|
if cls._handle_error(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._call_playwright(['', 'install', 'firefox']):
|
if cls._handle_error(cls._call_playwright(['', 'install', 'firefox'])):
|
||||||
logger.success('安装/更新 playwright 浏览器成功')
|
logger.success('安装/更新 playwright 浏览器成功')
|
||||||
else:
|
else:
|
||||||
logger.error('安装/更新 playwright 浏览器失败')
|
logger.error('安装/更新 playwright 浏览器失败')
|
||||||
@@ -53,20 +52,26 @@ class BrowserManager:
|
|||||||
logger.success('playwright 启动成功')
|
logger.success('playwright 启动成功')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _call_playwright(cls, argv: list[str]) -> bool:
|
def _call_playwright(cls, argv: list[str]) -> BaseException:
|
||||||
"""等价于调用 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 SystemExit as e:
|
except BaseException as e: # noqa: BLE001 不在这里处理 playwright 的异常
|
||||||
return e.code == 0
|
return e
|
||||||
except BaseException: # noqa: BLE001
|
|
||||||
return False
|
|
||||||
finally:
|
finally:
|
||||||
sys.argv = argv_backup
|
sys.argv = argv_backup
|
||||||
return True
|
return SystemExit(0)
|
||||||
|
|
||||||
|
@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:
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ 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:
|
||||||
@@ -33,27 +32,17 @@ class Recorder:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def save_historical_data(cls, event_id: int) -> None:
|
async def save_historical_data(cls, event_id: int) -> None:
|
||||||
historical_data, completed = cls.del_historical_data(event_id)
|
if event_id not in cls.historical_data:
|
||||||
|
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) -> tuple[HistoricalData, bool]:
|
def del_historical_data(cls, event_id: int) -> None:
|
||||||
return cls.historical_data.pop(event_id)
|
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
|
||||||
@@ -84,9 +73,7 @@ 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.add_error_event(event_id)
|
Recorder.del_historical_data(id(event))
|
||||||
Recorder.del_historical_data(event_id)
|
|
||||||
else:
|
else:
|
||||||
await Recorder.save_historical_data(event_id)
|
await Recorder.save_historical_data(id(event))
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ 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, Config
|
from ..config.config import CACHE_PATH
|
||||||
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
|
||||||
@@ -116,7 +115,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, timeout=config.tetris_req_timeout) as session:
|
async with AsyncClient(cookies=cls._cookies) 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)
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
from asyncio import sleep
|
|
||||||
from collections.abc import Awaitable, Callable
|
|
||||||
from datetime import timedelta
|
|
||||||
from functools import wraps
|
|
||||||
from typing import TypeVar, cast
|
|
||||||
|
|
||||||
from nonebot.log import logger
|
|
||||||
|
|
||||||
T = TypeVar('T')
|
|
||||||
|
|
||||||
|
|
||||||
def retry(
|
|
||||||
max_attempts: int = 3,
|
|
||||||
exception_type: type[BaseException] | tuple[type[BaseException], ...] = Exception,
|
|
||||||
delay: timedelta | None = None,
|
|
||||||
) -> Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]:
|
|
||||||
def decorator(func: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
|
|
||||||
@wraps(func)
|
|
||||||
async def wrapper(*args, **kwargs) -> T: # noqa: ANN002, ANN003
|
|
||||||
attempts = 0
|
|
||||||
while attempts < max_attempts + 1:
|
|
||||||
try:
|
|
||||||
return await func(*args, **kwargs)
|
|
||||||
except exception_type as e: # noqa: PERF203
|
|
||||||
logger.exception(e)
|
|
||||||
attempts += 1
|
|
||||||
if attempts <= max_attempts:
|
|
||||||
if delay is not None:
|
|
||||||
await sleep(delay.total_seconds())
|
|
||||||
logger.debug(f'Retrying: {func.__name__} ({attempts}/{max_attempts})')
|
|
||||||
continue
|
|
||||||
raise
|
|
||||||
raise RuntimeError('Unexpectedly reached the end of the retry loop')
|
|
||||||
|
|
||||||
return cast(Callable[..., Awaitable[T]], wrapper)
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
219
poetry.lock
generated
219
poetry.lock
generated
@@ -1,21 +1,5 @@
|
|||||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiocache"
|
|
||||||
version = "0.12.2"
|
|
||||||
description = "multi backend asyncio cache"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "aiocache-0.12.2-py2.py3-none-any.whl", hash = "sha256:9b6fa30634ab0bfc3ecc44928a91ff07c6ea16d27d55469636b296ebc6eb5918"},
|
|
||||||
{file = "aiocache-0.12.2.tar.gz", hash = "sha256:b41c9a145b050a5dcbae1599f847db6dd445193b1f3bd172d8e0fe0cb9e96684"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
memcached = ["aiomcache (>=0.5.2)"]
|
|
||||||
msgpack = ["msgpack (>=0.5.5)"]
|
|
||||||
redis = ["redis (>=4.2.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiofiles"
|
name = "aiofiles"
|
||||||
version = "23.2.1"
|
version = "23.2.1"
|
||||||
@@ -213,16 +197,6 @@ typing-extensions = ">=4.5.0"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
|
all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fleep"
|
|
||||||
version = "1.0.1"
|
|
||||||
description = "File format determination library"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.1"
|
|
||||||
files = [
|
|
||||||
{file = "fleep-1.0.1.tar.gz", hash = "sha256:c8f62b258ee5364d7f6c1ed1f3f278e99020fc3f0a60a24ad1e10846e31d104c"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "greenlet"
|
name = "greenlet"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
@@ -880,13 +854,13 @@ typing-extensions = ">=4.0.0,<5.0.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonebot-adapter-satori"
|
name = "nonebot-adapter-satori"
|
||||||
version = "0.8.0"
|
version = "0.7.0"
|
||||||
description = "Satori Protocol Adapter for Nonebot2"
|
description = "Satori Protocol Adapter for Nonebot2"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "nonebot_adapter_satori-0.8.0-py3-none-any.whl", hash = "sha256:25d9726a961b73b6900a4dba3a8ec4f5d228a6cb96078b542379c9d6c9d3cefe"},
|
{file = "nonebot_adapter_satori-0.7.0-py3-none-any.whl", hash = "sha256:14a6e846c0f4e46077c28ca403e5f16d18162b63b6aa4eb68f9e6f52153ab138"},
|
||||||
{file = "nonebot_adapter_satori-0.8.0.tar.gz", hash = "sha256:267c5b708ec2dd77b405d3ec779e817506e6d6914cc06688b529b43fe4288727"},
|
{file = "nonebot_adapter_satori-0.7.0.tar.gz", hash = "sha256:0f62b87182359beaf477e77b12a0ca665273de7a24833695514ff18817b23618"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -894,19 +868,18 @@ nonebot2 = ">=2.1.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonebot-plugin-alconna"
|
name = "nonebot-plugin-alconna"
|
||||||
version = "0.33.6"
|
version = "0.32.0"
|
||||||
description = "Alconna Adapter for Nonebot"
|
description = "Alconna Adapter for Nonebot"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "nonebot_plugin_alconna-0.33.6-py3-none-any.whl", hash = "sha256:89989dd6dc1bccd8a1603159b57e9e96da438eb0bbbdbbcd2bfcf747594e12c3"},
|
{file = "nonebot_plugin_alconna-0.32.0-py3-none-any.whl", hash = "sha256:3126b845ebbb4118a46513977a6ce91783a4c6158febba03a4b00ac565a6756b"},
|
||||||
{file = "nonebot_plugin_alconna-0.33.6.tar.gz", hash = "sha256:54e761ef621c8285cd9ea2f81324f9f52f6fb6292d3ddb87387dbdcaeaa8dc1b"},
|
{file = "nonebot_plugin_alconna-0.32.0.tar.gz", hash = "sha256:ab53fadec56f2a5fcf75adb95a5312db48620217c3b3dcd90878ab0394062ff8"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
arclet-alconna = ">=1.7.31,<2.0.0"
|
arclet-alconna = ">=1.7.31,<2.0.0"
|
||||||
arclet-alconna-tools = ">=0.6.7,<0.7.0"
|
arclet-alconna-tools = ">=0.6.7,<0.7.0"
|
||||||
fleep = ">=1.0.1"
|
|
||||||
nepattern = ">=0.5.14,<0.6.0"
|
nepattern = ">=0.5.14,<0.6.0"
|
||||||
nonebot2 = ">=2.1.0"
|
nonebot2 = ">=2.1.0"
|
||||||
|
|
||||||
@@ -942,13 +915,13 @@ typing-extensions = ">=4.0.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonebot-plugin-orm"
|
name = "nonebot-plugin-orm"
|
||||||
version = "0.6.0"
|
version = "0.5.0"
|
||||||
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.6.0-py3-none-any.whl", hash = "sha256:482f35d102749eda93cd635608ec79e81718d080a80fa325c24d8fa7316f7d83"},
|
{file = "nonebot_plugin_orm-0.5.0-py3-none-any.whl", hash = "sha256:e8d0e3b11c592e8d7cef3d635f500a5f7bf45b042eb225907c40dd23e4e2b2bd"},
|
||||||
{file = "nonebot_plugin_orm-0.6.0.tar.gz", hash = "sha256:e1b4db52da60b53f33eac95bb4b9875d7000d71f47ec6a034aa908adde41c33e"},
|
{file = "nonebot_plugin_orm-0.5.0.tar.gz", hash = "sha256:2bf51bdc30ee3dc797c5032dc92dbcf34d7eb42d09dd6b527228033807d33a56"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -959,7 +932,7 @@ importlib-resources = {version = ">=6.1,<7.0", markers = "python_version < \"3.1
|
|||||||
nonebot-plugin-localstore = ">=0.5,<1.0"
|
nonebot-plugin-localstore = ">=0.5,<1.0"
|
||||||
nonebot2 = ">=2.1,<3.0"
|
nonebot2 = ">=2.1,<3.0"
|
||||||
sqlalchemy = ">=2.0,<3.0"
|
sqlalchemy = ">=2.0,<3.0"
|
||||||
typing-extensions = {version = ">=4.8,<5.0", markers = "python_version < \"3.11\""}
|
typing-extensions = {version = ">=4.8,<5.0", markers = "python_version < \"3.12\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
aiomysql = ["aiomysql (>=0.2,<1.0)"]
|
aiomysql = ["aiomysql (>=0.2,<1.0)"]
|
||||||
@@ -1003,47 +976,43 @@ websockets = ["websockets (>=10.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "1.26.2"
|
version = "1.26.1"
|
||||||
description = "Fundamental package for array computing in Python"
|
description = "Fundamental package for array computing in Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = "<3.13,>=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"},
|
{file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"},
|
{file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"},
|
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"},
|
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"},
|
{file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"},
|
{file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"},
|
{file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"},
|
||||||
{file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"},
|
{file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"},
|
{file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"},
|
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"},
|
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"},
|
{file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"},
|
{file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"},
|
{file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"},
|
{file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"},
|
||||||
{file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"},
|
{file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"},
|
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"},
|
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"},
|
{file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"},
|
{file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"},
|
{file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"},
|
{file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"},
|
{file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"},
|
||||||
{file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"},
|
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"},
|
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"},
|
{file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"},
|
{file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"},
|
{file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"},
|
{file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"},
|
{file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"},
|
{file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"},
|
||||||
{file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"},
|
{file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"},
|
||||||
{file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"},
|
|
||||||
{file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"},
|
|
||||||
{file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"},
|
|
||||||
{file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1059,50 +1028,50 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pandas"
|
name = "pandas"
|
||||||
version = "2.1.3"
|
version = "2.1.1"
|
||||||
description = "Powerful data structures for data analysis, time series, and statistics"
|
description = "Powerful data structures for data analysis, time series, and statistics"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "pandas-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acf08a73b5022b479c1be155d4988b72f3020f308f7a87c527702c5f8966d34f"},
|
{file = "pandas-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4"},
|
||||||
{file = "pandas-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3cc4469ff0cf9aa3a005870cb49ab8969942b7156e0a46cc3f5abd6b11051dfb"},
|
{file = "pandas-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614"},
|
||||||
{file = "pandas-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35172bff95f598cc5866c047f43c7f4df2c893acd8e10e6653a4b792ed7f19bb"},
|
{file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363"},
|
||||||
{file = "pandas-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59dfe0e65a2f3988e940224e2a70932edc964df79f3356e5f2997c7d63e758b4"},
|
{file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4"},
|
||||||
{file = "pandas-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0296a66200dee556850d99b24c54c7dfa53a3264b1ca6f440e42bad424caea03"},
|
{file = "pandas-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb"},
|
||||||
{file = "pandas-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:465571472267a2d6e00657900afadbe6097c8e1dc43746917db4dfc862e8863e"},
|
{file = "pandas-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2"},
|
||||||
{file = "pandas-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04d4c58e1f112a74689da707be31cf689db086949c71828ef5da86727cfe3f82"},
|
{file = "pandas-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d"},
|
||||||
{file = "pandas-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7fa2ad4ff196768ae63a33f8062e6838efed3a319cf938fdf8b95e956c813042"},
|
{file = "pandas-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8"},
|
||||||
{file = "pandas-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4441ac94a2a2613e3982e502ccec3bdedefe871e8cea54b8775992485c5660ef"},
|
{file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0"},
|
||||||
{file = "pandas-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ded6ff28abbf0ea7689f251754d3789e1edb0c4d0d91028f0b980598418a58"},
|
{file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e"},
|
||||||
{file = "pandas-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca5680368a5139d4920ae3dc993eb5106d49f814ff24018b64d8850a52c6ed2"},
|
{file = "pandas-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2"},
|
||||||
{file = "pandas-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:de21e12bf1511190fc1e9ebc067f14ca09fccfb189a813b38d63211d54832f5f"},
|
{file = "pandas-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a"},
|
||||||
{file = "pandas-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a5d53c725832e5f1645e7674989f4c106e4b7249c1d57549023ed5462d73b140"},
|
{file = "pandas-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49"},
|
||||||
{file = "pandas-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7cf4cf26042476e39394f1f86868d25b265ff787c9b2f0d367280f11afbdee6d"},
|
{file = "pandas-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea"},
|
||||||
{file = "pandas-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72c84ec1b1d8e5efcbff5312abe92bfb9d5b558f11e0cf077f5496c4f4a3c99e"},
|
{file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317"},
|
||||||
{file = "pandas-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f539e113739a3e0cc15176bf1231a553db0239bfa47a2c870283fd93ba4f683"},
|
{file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0"},
|
||||||
{file = "pandas-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc77309da3b55732059e484a1efc0897f6149183c522390772d3561f9bf96c00"},
|
{file = "pandas-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa"},
|
||||||
{file = "pandas-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:08637041279b8981a062899da0ef47828df52a1838204d2b3761fbd3e9fcb549"},
|
{file = "pandas-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6"},
|
||||||
{file = "pandas-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b99c4e51ef2ed98f69099c72c75ec904dd610eb41a32847c4fcbc1a975f2d2b8"},
|
{file = "pandas-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750"},
|
||||||
{file = "pandas-2.1.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7ea8ae8004de0381a2376662c0505bb0a4f679f4c61fbfd122aa3d1b0e5f09d"},
|
{file = "pandas-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e"},
|
||||||
{file = "pandas-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd76d67ca2d48f56e2db45833cf9d58f548f97f61eecd3fdc74268417632b8a"},
|
{file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd"},
|
||||||
{file = "pandas-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1329dbe93a880a3d7893149979caa82d6ba64a25e471682637f846d9dbc10dd2"},
|
{file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98"},
|
||||||
{file = "pandas-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:321ecdb117bf0f16c339cc6d5c9a06063854f12d4d9bc422a84bb2ed3207380a"},
|
{file = "pandas-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97"},
|
||||||
{file = "pandas-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:11a771450f36cebf2a4c9dbd3a19dfa8c46c4b905a3ea09dc8e556626060fe71"},
|
{file = "pandas-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2"},
|
||||||
{file = "pandas-2.1.3.tar.gz", hash = "sha256:22929f84bca106921917eb73c1521317ddd0a4c71b395bcf767a106e3494209f"},
|
{file = "pandas-2.1.1.tar.gz", hash = "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
numpy = [
|
numpy = [
|
||||||
{version = ">=1.22.4,<2", markers = "python_version < \"3.11\""},
|
{version = ">=1.22.4", markers = "python_version < \"3.11\""},
|
||||||
{version = ">=1.23.2,<2", markers = "python_version == \"3.11\""},
|
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
||||||
{version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""},
|
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
||||||
]
|
]
|
||||||
python-dateutil = ">=2.8.2"
|
python-dateutil = ">=2.8.2"
|
||||||
pytz = ">=2020.1"
|
pytz = ">=2020.1"
|
||||||
tzdata = ">=2022.1"
|
tzdata = ">=2022.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"]
|
all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"]
|
||||||
aws = ["s3fs (>=2022.05.0)"]
|
aws = ["s3fs (>=2022.05.0)"]
|
||||||
clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"]
|
clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"]
|
||||||
compression = ["zstandard (>=0.17.0)"]
|
compression = ["zstandard (>=0.17.0)"]
|
||||||
@@ -1122,7 +1091,7 @@ plot = ["matplotlib (>=3.6.1)"]
|
|||||||
postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"]
|
postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"]
|
||||||
spss = ["pyreadstat (>=1.1.5)"]
|
spss = ["pyreadstat (>=1.1.5)"]
|
||||||
sql-other = ["SQLAlchemy (>=1.4.36)"]
|
sql-other = ["SQLAlchemy (>=1.4.36)"]
|
||||||
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"]
|
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"]
|
||||||
xml = ["lxml (>=4.8.0)"]
|
xml = ["lxml (>=4.8.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1341,28 +1310,28 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.1.6"
|
version = "0.1.5"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"},
|
{file = "ruff-0.1.5-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:32d47fc69261c21a4c48916f16ca272bf2f273eb635d91c65d5cd548bf1f3d96"},
|
||||||
{file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"},
|
{file = "ruff-0.1.5-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:171276c1df6c07fa0597fb946139ced1c2978f4f0b8254f201281729981f3c17"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ef33cd0bb7316ca65649fc748acc1406dfa4da96a3d0cde6d52f2e866c7b39"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b2c205827b3f8c13b4a432e9585750b93fd907986fe1aec62b2a02cf4401eee6"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb408e3a2ad8f6881d0f2e7ad70cddb3ed9f200eb3517a91a245bbe27101d379"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f20dc5e5905ddb407060ca27267c7174f532375c08076d1a953cf7bb016f5a24"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aafb9d2b671ed934998e881e2c0f5845a4295e84e719359c71c39a5363cccc91"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4894dddb476597a0ba4473d72a23151b8b3b0b5f958f2cf4d3f1c572cdb7af7"},
|
||||||
{file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"},
|
{file = "ruff-0.1.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00a7ec893f665ed60008c70fe9eeb58d210e6b4d83ec6654a9904871f982a2a"},
|
||||||
{file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"},
|
{file = "ruff-0.1.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8c11206b47f283cbda399a654fd0178d7a389e631f19f51da15cbe631480c5b"},
|
||||||
{file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"},
|
{file = "ruff-0.1.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fa29e67b3284b9a79b1a85ee66e293a94ac6b7bb068b307a8a373c3d343aa8ec"},
|
||||||
{file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"},
|
{file = "ruff-0.1.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9b97fd6da44d6cceb188147b68db69a5741fbc736465b5cea3928fdac0bc1aeb"},
|
||||||
{file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"},
|
{file = "ruff-0.1.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:721f4b9d3b4161df8dc9f09aa8562e39d14e55a4dbaa451a8e55bdc9590e20f4"},
|
||||||
{file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"},
|
{file = "ruff-0.1.5-py3-none-win32.whl", hash = "sha256:f80c73bba6bc69e4fdc73b3991db0b546ce641bdcd5b07210b8ad6f64c79f1ab"},
|
||||||
{file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"},
|
{file = "ruff-0.1.5-py3-none-win_amd64.whl", hash = "sha256:c21fe20ee7d76206d290a76271c1af7a5096bc4c73ab9383ed2ad35f852a0087"},
|
||||||
{file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"},
|
{file = "ruff-0.1.5-py3-none-win_arm64.whl", hash = "sha256:82bfcb9927e88c1ed50f49ac6c9728dab3ea451212693fe40d08d314663e412f"},
|
||||||
{file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"},
|
{file = "ruff-0.1.5.tar.gz", hash = "sha256:5cbec0ef2ae1748fb194f420fb03fb2c25c3258c86129af7172ff8f198f125ab"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2124,4 +2093,4 @@ multidict = ">=4.0"
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "e523f1239c9c0373499c2ee7a9c04a7400334ea94bec5105a8497bdb7da29f98"
|
content-hash = "fe5add372ec41e79b27a990ab27afbdcceb625dc81f3ebd20a28e0b8129f6942"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = 'nonebot-plugin-tetris-stats'
|
name = 'nonebot-plugin-tetris-stats'
|
||||||
version = '1.0.0.a8'
|
version = '1.0.0.a1.post1'
|
||||||
description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件'
|
description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件'
|
||||||
authors = ['scdhh <wallfjjd@gmail.com>']
|
authors = ['scdhh <wallfjjd@gmail.com>']
|
||||||
readme = 'README.md'
|
readme = 'README.md'
|
||||||
@@ -16,24 +16,23 @@ pandas = '>=1.4.3,<3.0.0'
|
|||||||
playwright = '^1.24.1'
|
playwright = '^1.24.1'
|
||||||
ujson = '^5.4.0'
|
ujson = '^5.4.0'
|
||||||
aiofiles = "^23.2.1"
|
aiofiles = "^23.2.1"
|
||||||
nonebot-plugin-orm = ">=0.1.1,<0.7.0"
|
nonebot-plugin-orm = ">=0.1.1,<0.6.0"
|
||||||
nonebot-plugin-localstore = "^0.5.1"
|
nonebot-plugin-localstore = "^0.5.1"
|
||||||
httpx = "^0.25.0"
|
httpx = "^0.25.0"
|
||||||
nonebot-plugin-alconna = ">=0.30,<0.34"
|
nonebot-plugin-alconna = ">=0.30,<0.33"
|
||||||
nonebot-plugin-apscheduler = "^0.3.0"
|
nonebot-plugin-apscheduler = "^0.3.0"
|
||||||
aiocache = "^0.12.2"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
mypy = '>=0.991,<1.8'
|
mypy = '>=0.991,<1.8'
|
||||||
types-ujson = '^5.7.0'
|
types-ujson = '^5.7.0'
|
||||||
pandas-stubs = '>=1.5.2,<3.0.0'
|
pandas-stubs = '>=1.5.2,<3.0.0'
|
||||||
ruff = '>=0.0.239,<0.1.7'
|
ruff = '>=0.0.239,<0.1.6'
|
||||||
types-aiofiles = "^23.2.0.0"
|
types-aiofiles = "^23.2.0.0"
|
||||||
nonebot2 = { extras = ["fastapi"], version = "^2.1.1" }
|
nonebot2 = { extras = ["fastapi"], version = "^2.1.1" }
|
||||||
types-lxml = "^2023.3.28"
|
types-lxml = "^2023.3.28"
|
||||||
nonebot-plugin-orm = { extras = ["default"], version = ">=0.3,<0.7" }
|
nonebot-plugin-orm = { extras = ["default"], version = ">=0.3,<0.6" }
|
||||||
nonebot-adapter-onebot = "^2.3.1"
|
nonebot-adapter-onebot = "^2.3.1"
|
||||||
nonebot-adapter-satori = "^0.8.0"
|
nonebot-adapter-satori = "^0.7.0"
|
||||||
|
|
||||||
[tool.poetry.group.debug.dependencies]
|
[tool.poetry.group.debug.dependencies]
|
||||||
objprint = '^0.2.2'
|
objprint = '^0.2.2'
|
||||||
|
|||||||
Reference in New Issue
Block a user