From 7b5a50493a91931ce2c8c2a4a5f116d06006f48a Mon Sep 17 00:00:00 2001 From: MingxuanGame Date: Wed, 23 Jul 2025 18:03:30 +0800 Subject: [PATCH] use uv & make lint happy --- app/auth.py | 100 +++-- app/config.py | 23 +- app/database copy.py | 212 ++++++---- app/database.py | 231 ++++++---- app/dependencies.py | 5 + app/models.py | 45 +- app/utils.py | 191 +++++---- create_sample_data.py | 358 +++++++++++----- main.py | 242 ++++++----- osu_api_example.py | 15 +- pyproject.toml | 86 ++++ quick_sync.py | 80 ++-- sync_data.py | 125 +++--- test_api.py | 51 ++- test_lazer.py | 57 +-- test_password.py | 24 +- uv.lock | 964 ++++++++++++++++++++++++++++++++++++++++++ 17 files changed, 2117 insertions(+), 692 deletions(-) create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/app/auth.py b/app/auth.py index 3dccc11..45afba7 100644 --- a/app/auth.py +++ b/app/auth.py @@ -1,14 +1,21 @@ +from __future__ import annotations + from datetime import datetime, timedelta +import hashlib +import secrets +import string from typing import Optional + +from app.config import settings +from app.database import ( + OAuthToken, + User as DBUser, +) + +import bcrypt from jose import JWTError, jwt from passlib.context import CryptContext from sqlalchemy.orm import Session -from app.database import User as DBUser, OAuthToken -from app.config import settings -import secrets -import string -import hashlib -import bcrypt # 密码哈希上下文 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") @@ -16,6 +23,7 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # bcrypt 缓存(模拟应用状态缓存) bcrypt_cache = {} + def verify_password_legacy(plain_password: str, bcrypt_hash: str) -> bool: """ 验证密码 - 使用 osu! 的验证方式 @@ -24,34 +32,36 @@ def verify_password_legacy(plain_password: str, bcrypt_hash: str) -> bool: """ # 1. 明文密码转 MD5 pw_md5 = hashlib.md5(plain_password.encode()).hexdigest().encode() - + # 2. 检查缓存 if bcrypt_hash in bcrypt_cache: return bcrypt_cache[bcrypt_hash] == pw_md5 - + # 3. 如果缓存中没有,进行 bcrypt 验证 try: # 验证 MD5 哈希与 bcrypt 哈希 is_valid = bcrypt.checkpw(pw_md5, bcrypt_hash.encode()) - + # 如果验证成功,将结果缓存 if is_valid: bcrypt_cache[bcrypt_hash] = pw_md5 - + return is_valid except Exception as e: print(f"Password verification error: {e}") return False + def verify_password(plain_password: str, hashed_password: str) -> bool: """验证密码(向后兼容)""" # 首先尝试新的验证方式 if verify_password_legacy(plain_password, hashed_password): return True - + # 如果失败,尝试标准 bcrypt 验证 return pwd_context.verify(plain_password, hashed_password) + def get_password_hash(password: str) -> str: """生成密码哈希 - 使用 osu! 的方式""" # 1. 明文密码 -> MD5 @@ -60,29 +70,30 @@ def get_password_hash(password: str) -> str: pw_bcrypt = bcrypt.hashpw(pw_md5, bcrypt.gensalt()) return pw_bcrypt.decode() + def authenticate_user_legacy(db: Session, name: str, password: str) -> Optional[DBUser]: """ 验证用户身份 - 使用类似 from_login 的逻辑 """ # 1. 明文密码转 MD5 pw_md5 = hashlib.md5(password.encode()).hexdigest() - + # 2. 根据用户名查找用户 user = db.query(DBUser).filter(DBUser.name == name).first() if not user: return None - + # 3. 验证密码 if not user.pw_bcrypt: return None - + # 4. 检查缓存 if user.pw_bcrypt in bcrypt_cache: if bcrypt_cache[user.pw_bcrypt] == pw_md5.encode(): return user else: return None - + # 5. 验证 bcrypt try: is_valid = bcrypt.checkpw(pw_md5.encode(), user.pw_bcrypt.encode()) @@ -92,68 +103,91 @@ def authenticate_user_legacy(db: Session, name: str, password: str) -> Optional[ return user except Exception as e: print(f"Authentication error for user {name}: {e}") - + return None + def authenticate_user(db: Session, username: str, password: str) -> Optional[DBUser]: """验证用户身份""" return authenticate_user_legacy(db, username, password) + def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: """创建访问令牌""" to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: - expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) - + expire = datetime.utcnow() + timedelta( + minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES + ) + to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) + encoded_jwt = jwt.encode( + to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM + ) return encoded_jwt + def generate_refresh_token() -> str: """生成刷新令牌""" length = 64 characters = string.ascii_letters + string.digits - return ''.join(secrets.choice(characters) for _ in range(length)) + return "".join(secrets.choice(characters) for _ in range(length)) + def verify_token(token: str) -> Optional[dict]: """验证访问令牌""" try: - payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) + payload = jwt.decode( + token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) return payload except JWTError: return None -def store_token(db: Session, user_id: int, access_token: str, refresh_token: str, expires_in: int) -> OAuthToken: + +def store_token( + db: Session, user_id: int, access_token: str, refresh_token: str, expires_in: int +) -> OAuthToken: """存储令牌到数据库""" expires_at = datetime.utcnow() + timedelta(seconds=expires_in) - + # 删除用户的旧令牌 db.query(OAuthToken).filter(OAuthToken.user_id == user_id).delete() - + # 创建新令牌记录 token_record = OAuthToken( user_id=user_id, access_token=access_token, refresh_token=refresh_token, - expires_at=expires_at + expires_at=expires_at, ) db.add(token_record) db.commit() db.refresh(token_record) return token_record + def get_token_by_access_token(db: Session, access_token: str) -> Optional[OAuthToken]: """根据访问令牌获取令牌记录""" - return db.query(OAuthToken).filter( - OAuthToken.access_token == access_token, - OAuthToken.expires_at > datetime.utcnow() - ).first() + return ( + db.query(OAuthToken) + .filter( + OAuthToken.access_token == access_token, + OAuthToken.expires_at > datetime.utcnow(), + ) + .first() + ) + def get_token_by_refresh_token(db: Session, refresh_token: str) -> Optional[OAuthToken]: """根据刷新令牌获取令牌记录""" - return db.query(OAuthToken).filter( - OAuthToken.refresh_token == refresh_token, - OAuthToken.expires_at > datetime.utcnow() - ).first() + return ( + db.query(OAuthToken) + .filter( + OAuthToken.refresh_token == refresh_token, + OAuthToken.expires_at > datetime.utcnow(), + ) + .first() + ) diff --git a/app/config.py b/app/config.py index c1310e8..1e347c7 100644 --- a/app/config.py +++ b/app/config.py @@ -1,25 +1,36 @@ +from __future__ import annotations + import os + from dotenv import load_dotenv load_dotenv() + class Settings: # 数据库设置 - DATABASE_URL: str = os.getenv("DATABASE_URL", "mysql+pymysql://root:password@localhost:3306/osu_api") + DATABASE_URL: str = os.getenv( + "DATABASE_URL", "mysql+pymysql://root:password@localhost:3306/osu_api" + ) REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379/0") - + # JWT 设置 SECRET_KEY: str = os.getenv("SECRET_KEY", "your-secret-key-here") ALGORITHM: str = os.getenv("ALGORITHM", "HS256") - ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "1440")) - + ACCESS_TOKEN_EXPIRE_MINUTES: int = int( + os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "1440") + ) + # OAuth 设置 OSU_CLIENT_ID: str = os.getenv("OSU_CLIENT_ID", "5") - OSU_CLIENT_SECRET: str = os.getenv("OSU_CLIENT_SECRET", "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk") - + OSU_CLIENT_SECRET: str = os.getenv( + "OSU_CLIENT_SECRET", "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" + ) + # 服务器设置 HOST: str = os.getenv("HOST", "0.0.0.0") PORT: int = int(os.getenv("PORT", "8000")) DEBUG: bool = os.getenv("DEBUG", "True").lower() == "true" + settings = Settings() diff --git a/app/database copy.py b/app/database copy.py index 7ba80bc..457e349 100644 --- a/app/database copy.py +++ b/app/database copy.py @@ -1,35 +1,51 @@ -from sqlalchemy import Column, Integer, String, Boolean, DateTime, Float, Text, JSON, ForeignKey, Date, DECIMAL +from __future__ import annotations + +from datetime import datetime + +from sqlalchemy import ( + DECIMAL, + JSON, + Boolean, + Column, + DateTime, + Float, + ForeignKey, + Integer, + String, + Text, +) from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship -from datetime import datetime Base = declarative_base() class User(Base): __tablename__ = "users" - + # 主键 id = Column(Integer, primary_key=True, index=True) - + # 基本信息(匹配 migrations 中的结构) name = Column(String(32), unique=True, index=True, nullable=False) # 用户名 - safe_name = Column(String(32), unique=True, index=True, nullable=False) # 安全用户名 + safe_name = Column( + String(32), unique=True, index=True, nullable=False + ) # 安全用户名 email = Column(String(254), unique=True, index=True, nullable=False) priv = Column(Integer, default=1, nullable=False) # 权限 pw_bcrypt = Column(String(60), nullable=False) # bcrypt 哈希密码 - country = Column(String(2), default='CN', nullable=False) # 国家代码 - + country = Column(String(2), default="CN", nullable=False) # 国家代码 + # 状态和时间 silence_end = Column(Integer, default=0, nullable=False) donor_end = Column(Integer, default=0, nullable=False) creation_time = Column(Integer, default=0, nullable=False) # Unix 时间戳 latest_activity = Column(Integer, default=0, nullable=False) # Unix 时间戳 - + # 游戏相关 preferred_mode = Column(Integer, default=0, nullable=False) # 偏好游戏模式 play_style = Column(Integer, default=0, nullable=False) # 游戏风格 - + # 扩展信息 clan_id = Column(Integer, default=0, nullable=False) clan_priv = Column(Integer, default=0, nullable=False) @@ -37,39 +53,57 @@ class User(Base): custom_badge_icon = Column(String(64)) userpage_content = Column(String(2048)) api_key = Column(String(36), unique=True) - + # 虚拟字段用于兼容性 @property def username(self): return self.name - + @property def country_code(self): return self.country - + @property def join_date(self): - return datetime.fromtimestamp(self.creation_time) if self.creation_time > 0 else datetime.utcnow() - + return ( + datetime.fromtimestamp(self.creation_time) + if self.creation_time > 0 + else datetime.utcnow() + ) + @property def last_visit(self): - return datetime.fromtimestamp(self.latest_activity) if self.latest_activity > 0 else None - + return ( + datetime.fromtimestamp(self.latest_activity) + if self.latest_activity > 0 + else None + ) + # 关联关系 - lazer_profile = relationship("LazerUserProfile", back_populates="user", uselist=False, cascade="all, delete-orphan") - lazer_statistics = relationship("LazerUserStatistics", back_populates="user", cascade="all, delete-orphan") - lazer_achievements = relationship("LazerUserAchievement", back_populates="user", cascade="all, delete-orphan") + lazer_profile = relationship( + "LazerUserProfile", + back_populates="user", + uselist=False, + cascade="all, delete-orphan", + ) + lazer_statistics = relationship( + "LazerUserStatistics", back_populates="user", cascade="all, delete-orphan" + ) + lazer_achievements = relationship( + "LazerUserAchievement", back_populates="user", cascade="all, delete-orphan" + ) # ============================================ # Lazer API 专用表模型 # ============================================ + class LazerUserProfile(Base): __tablename__ = "lazer_user_profiles" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - + # 基本状态字段 is_active = Column(Boolean, default=True) is_bot = Column(Boolean, default=False) @@ -80,14 +114,14 @@ class LazerUserProfile(Base): session_verified = Column(Boolean, default=False) has_supported = Column(Boolean, default=False) pm_friends_only = Column(Boolean, default=False) - + # 基本资料字段 - default_group = Column(String(50), default='default') + default_group = Column(String(50), default="default") last_visit = Column(DateTime) join_date = Column(DateTime) profile_colour = Column(String(7)) profile_hue = Column(Integer) - + # 社交媒体和个人资料字段 avatar_url = Column(String(500)) cover_url = Column(String(500)) @@ -99,52 +133,52 @@ class LazerUserProfile(Base): interests = Column(Text) location = Column(String(100)) occupation = Column(String(100)) - + # 游戏相关字段 - playmode = Column(String(10), default='osu') + playmode = Column(String(10), default="osu") support_level = Column(Integer, default=0) max_blocks = Column(Integer, default=100) max_friends = Column(Integer, default=500) post_count = Column(Integer, default=0) - + # 页面内容 page_html = Column(Text) page_raw = Column(Text) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + # 关联关系 user = relationship("User", back_populates="lazer_profile") class LazerUserCountry(Base): __tablename__ = "lazer_user_countries" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) code = Column(String(2), nullable=False) name = Column(String(100), nullable=False) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class LazerUserKudosu(Base): __tablename__ = "lazer_user_kudosu" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) available = Column(Integer, default=0) total = Column(Integer, default=0) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class LazerUserCounts(Base): __tablename__ = "lazer_user_counts" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - + # 统计计数字段 beatmap_playcounts_count = Column(Integer, default=0) comments_count = Column(Integer, default=0) @@ -163,32 +197,32 @@ class LazerUserCounts(Base): scores_first_count = Column(Integer, default=0) scores_pinned_count = Column(Integer, default=0) scores_recent_count = Column(Integer, default=0) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class LazerUserStatistics(Base): __tablename__ = "lazer_user_statistics" - + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) - mode = Column(String(10), nullable=False, default='osu') - + mode = Column(String(10), nullable=False, default="osu") + # 基本命中统计 count_100 = Column(Integer, default=0) count_300 = Column(Integer, default=0) count_50 = Column(Integer, default=0) count_miss = Column(Integer, default=0) - + # 等级信息 level_current = Column(Integer, default=1) level_progress = Column(Integer, default=0) - + # 排名信息 global_rank = Column(Integer) global_rank_exp = Column(Integer) country_rank = Column(Integer) - + # PP 和分数 pp = Column(DECIMAL(10, 2), default=0.00) pp_exp = Column(DECIMAL(10, 2), default=0.00) @@ -197,32 +231,35 @@ class LazerUserStatistics(Base): total_score = Column(Integer, default=0) total_hits = Column(Integer, default=0) maximum_combo = Column(Integer, default=0) + + # ============================================ # 旧的兼容性表模型(保留以便向后兼容) # ============================================ + class LegacyUserStatistics(Base): __tablename__ = "user_statistics" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) mode = Column(String(10), nullable=False) # osu, taiko, fruits, mania - + # 基本统计 count_100 = Column(Integer, default=0) count_300 = Column(Integer, default=0) count_50 = Column(Integer, default=0) count_miss = Column(Integer, default=0) - + # 等级信息 level_current = Column(Integer, default=1) level_progress = Column(Integer, default=0) - + # 排名信息 global_rank = Column(Integer) global_rank_exp = Column(Integer) country_rank = Column(Integer) - + # PP 和分数 pp = Column(Float, default=0.0) pp_exp = Column(Float, default=0.0) @@ -231,13 +268,13 @@ class LegacyUserStatistics(Base): total_score = Column(Integer, default=0) total_hits = Column(Integer, default=0) maximum_combo = Column(Integer, default=0) - + # 游戏统计 play_count = Column(Integer, default=0) play_time = Column(Integer, default=0) replays_watched_by_others = Column(Integer, default=0) is_ranked = Column(Boolean, default=False) - + # 成绩等级计数 grade_ss = Column(Integer, default=0) grade_ssh = Column(Integer, default=0) @@ -248,7 +285,7 @@ class LegacyUserStatistics(Base): class OAuthToken(Base): __tablename__ = "oauth_tokens" - + id = Column(Integer, primary_key=True, autoincrement=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) access_token = Column(String(255), nullable=False, index=True) @@ -258,37 +295,50 @@ class OAuthToken(Base): updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) previous_usernames = Column(JSON, default=list) replays_watched_counts = Column(JSON, default=list) - + # 关联关系 - statistics = relationship("UserStatistics", back_populates="user", cascade="all, delete-orphan") - achievements = relationship("UserAchievement", back_populates="user", cascade="all, delete-orphan") - team_membership = relationship("TeamMember", back_populates="user", cascade="all, delete-orphan") - daily_challenge_stats = relationship("DailyChallengeStats", back_populates="user", uselist=False, cascade="all, delete-orphan") - rank_history = relationship("RankHistory", back_populates="user", cascade="all, delete-orphan") + statistics = relationship( + "UserStatistics", back_populates="user", cascade="all, delete-orphan" + ) + achievements = relationship( + "UserAchievement", back_populates="user", cascade="all, delete-orphan" + ) + team_membership = relationship( + "TeamMember", back_populates="user", cascade="all, delete-orphan" + ) + daily_challenge_stats = relationship( + "DailyChallengeStats", + back_populates="user", + uselist=False, + cascade="all, delete-orphan", + ) + rank_history = relationship( + "RankHistory", back_populates="user", cascade="all, delete-orphan" + ) class UserStatistics(Base): __tablename__ = "user_statistics" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) mode = Column(String(10), nullable=False) # osu, taiko, fruits, mania - + # 基本统计 count_100 = Column(Integer, default=0) count_300 = Column(Integer, default=0) count_50 = Column(Integer, default=0) count_miss = Column(Integer, default=0) - + # 等级信息 level_current = Column(Integer, default=1) level_progress = Column(Integer, default=0) - + # 排名信息 global_rank = Column(Integer) global_rank_exp = Column(Integer) country_rank = Column(Integer) - + # PP 和分数 pp = Column(Float, default=0.0) pp_exp = Column(Float, default=0.0) @@ -297,72 +347,74 @@ class UserStatistics(Base): total_score = Column(Integer, default=0) total_hits = Column(Integer, default=0) maximum_combo = Column(Integer, default=0) - + # 游戏统计 play_count = Column(Integer, default=0) play_time = Column(Integer, default=0) # 秒 replays_watched_by_others = Column(Integer, default=0) is_ranked = Column(Boolean, default=False) - + # 成绩等级计数 grade_ss = Column(Integer, default=0) grade_ssh = Column(Integer, default=0) grade_s = Column(Integer, default=0) grade_sh = Column(Integer, default=0) grade_a = Column(Integer, default=0) - + # 最高排名记录 rank_highest = Column(Integer) rank_highest_updated_at = Column(DateTime) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + # 关联关系 user = relationship("User", back_populates="statistics") class UserAchievement(Base): __tablename__ = "user_achievements" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) achievement_id = Column(Integer, nullable=False) achieved_at = Column(DateTime, default=datetime.utcnow) - + user = relationship("User", back_populates="achievements") class Team(Base): __tablename__ = "teams" - + id = Column(Integer, primary_key=True, index=True) name = Column(String(100), nullable=False) short_name = Column(String(10), nullable=False) flag_url = Column(String(500)) created_at = Column(DateTime, default=datetime.utcnow) - - members = relationship("TeamMember", back_populates="team", cascade="all, delete-orphan") + + members = relationship( + "TeamMember", back_populates="team", cascade="all, delete-orphan" + ) class TeamMember(Base): __tablename__ = "team_members" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) team_id = Column(Integer, ForeignKey("teams.id"), nullable=False) joined_at = Column(DateTime, default=datetime.utcnow) - + user = relationship("User", back_populates="team_membership") team = relationship("Team", back_populates="members") class DailyChallengeStats(Base): __tablename__ = "daily_challenge_stats" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False, unique=True) - + daily_streak_best = Column(Integer, default=0) daily_streak_current = Column(Integer, default=0) last_update = Column(DateTime) @@ -372,25 +424,25 @@ class DailyChallengeStats(Base): top_50p_placements = Column(Integer, default=0) weekly_streak_best = Column(Integer, default=0) weekly_streak_current = Column(Integer, default=0) - + user = relationship("User", back_populates="daily_challenge_stats") class RankHistory(Base): __tablename__ = "rank_history" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) mode = Column(String(10), nullable=False) rank_data = Column(JSON, nullable=False) # Array of ranks date_recorded = Column(DateTime, default=datetime.utcnow) - + user = relationship("User", back_populates="rank_history") class OAuthToken(Base): __tablename__ = "oauth_tokens" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) access_token = Column(String(500), unique=True, nullable=False) @@ -399,5 +451,5 @@ class OAuthToken(Base): scope = Column(String(100), default="*") expires_at = Column(DateTime, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) - + user = relationship("User") diff --git a/app/database.py b/app/database.py index ed2ba61..449ca98 100644 --- a/app/database.py +++ b/app/database.py @@ -1,36 +1,52 @@ -from sqlalchemy import Column, Integer, String, Boolean, DateTime, Float, Text, JSON, ForeignKey, Date, DECIMAL +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime + +from sqlalchemy import ( + DECIMAL, + JSON, + Boolean, + Column, + DateTime, + Float, + ForeignKey, + Integer, + String, + Text, +) from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship -from datetime import datetime -from dataclasses import dataclass Base = declarative_base() class User(Base): __tablename__ = "users" - + # 主键 id = Column(Integer, primary_key=True, index=True) - + # 基本信息(匹配 migrations 中的结构) name = Column(String(32), unique=True, index=True, nullable=False) # 用户名 - safe_name = Column(String(32), unique=True, index=True, nullable=False) # 安全用户名 + safe_name = Column( + String(32), unique=True, index=True, nullable=False + ) # 安全用户名 email = Column(String(254), unique=True, index=True, nullable=False) priv = Column(Integer, default=1, nullable=False) # 权限 pw_bcrypt = Column(String(60), nullable=False) # bcrypt 哈希密码 - country = Column(String(2), default='CN', nullable=False) # 国家代码 - + country = Column(String(2), default="CN", nullable=False) # 国家代码 + # 状态和时间 silence_end = Column(Integer, default=0, nullable=False) donor_end = Column(Integer, default=0, nullable=False) creation_time = Column(Integer, default=0, nullable=False) # Unix 时间戳 latest_activity = Column(Integer, default=0, nullable=False) # Unix 时间戳 - + # 游戏相关 preferred_mode = Column(Integer, default=0, nullable=False) # 偏好游戏模式 play_style = Column(Integer, default=0, nullable=False) # 游戏风格 - + # 扩展信息 clan_id = Column(Integer, default=0, nullable=False) clan_priv = Column(Integer, default=0, nullable=False) @@ -38,46 +54,79 @@ class User(Base): custom_badge_icon = Column(String(64)) userpage_content = Column(String(2048)) api_key = Column(String(36), unique=True) - + # 虚拟字段用于兼容性 @property def username(self): return self.name - + @property def country_code(self): return self.country - + @property def join_date(self): - creation_time = getattr(self, 'creation_time', 0) - return datetime.fromtimestamp(creation_time) if creation_time > 0 else datetime.utcnow() + creation_time = getattr(self, "creation_time", 0) + return ( + datetime.fromtimestamp(creation_time) + if creation_time > 0 + else datetime.utcnow() + ) + @property def last_visit(self): - latest_activity = getattr(self, 'latest_activity', 0) + latest_activity = getattr(self, "latest_activity", 0) return datetime.fromtimestamp(latest_activity) if latest_activity > 0 else None - + # 关联关系 - lazer_profile = relationship("LazerUserProfile", back_populates="user", uselist=False, cascade="all, delete-orphan") - lazer_statistics = relationship("LazerUserStatistics", back_populates="user", cascade="all, delete-orphan") - lazer_achievements = relationship("LazerUserAchievement", back_populates="user", cascade="all, delete-orphan") - statistics = relationship("LegacyUserStatistics", back_populates="user", cascade="all, delete-orphan") - achievements = relationship("LazerUserAchievement", back_populates="user", cascade="all, delete-orphan") - team_membership = relationship("TeamMember", back_populates="user", cascade="all, delete-orphan") - daily_challenge_stats = relationship("DailyChallengeStats", back_populates="user", uselist=False, cascade="all, delete-orphan") - rank_history = relationship("RankHistory", back_populates="user", cascade="all, delete-orphan") - avatar = relationship("UserAvatar", back_populates="user", primaryjoin="and_(User.id==UserAvatar.user_id, UserAvatar.is_active==True)", uselist=False) + lazer_profile = relationship( + "LazerUserProfile", + back_populates="user", + uselist=False, + cascade="all, delete-orphan", + ) + lazer_statistics = relationship( + "LazerUserStatistics", back_populates="user", cascade="all, delete-orphan" + ) + lazer_achievements = relationship( + "LazerUserAchievement", back_populates="user", cascade="all, delete-orphan" + ) + statistics = relationship( + "LegacyUserStatistics", back_populates="user", cascade="all, delete-orphan" + ) + achievements = relationship( + "LazerUserAchievement", back_populates="user", cascade="all, delete-orphan" + ) + team_membership = relationship( + "TeamMember", back_populates="user", cascade="all, delete-orphan" + ) + daily_challenge_stats = relationship( + "DailyChallengeStats", + back_populates="user", + uselist=False, + cascade="all, delete-orphan", + ) + rank_history = relationship( + "RankHistory", back_populates="user", cascade="all, delete-orphan" + ) + avatar = relationship( + "UserAvatar", + back_populates="user", + primaryjoin="and_(User.id==UserAvatar.user_id, UserAvatar.is_active==True)", + uselist=False, + ) # ============================================ # Lazer API 专用表模型 # ============================================ + class LazerUserProfile(Base): __tablename__ = "lazer_user_profiles" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - + # 基本状态字段 is_active = Column(Boolean, default=True) is_bot = Column(Boolean, default=False) @@ -88,14 +137,14 @@ class LazerUserProfile(Base): session_verified = Column(Boolean, default=False) has_supported = Column(Boolean, default=False) pm_friends_only = Column(Boolean, default=False) - + # 基本资料字段 - default_group = Column(String(50), default='default') + default_group = Column(String(50), default="default") last_visit = Column(DateTime) join_date = Column(DateTime) profile_colour = Column(String(7)) profile_hue = Column(Integer) - + # 社交媒体和个人资料字段 avatar_url = Column(String(500)) cover_url = Column(String(500)) @@ -108,52 +157,52 @@ class LazerUserProfile(Base): location = Column(String(100)) occupation = None # 职业字段,默认为 None - + # 游戏相关字段 - playmode = Column(String(10), default='osu') + playmode = Column(String(10), default="osu") support_level = Column(Integer, default=0) max_blocks = Column(Integer, default=100) max_friends = Column(Integer, default=500) post_count = Column(Integer, default=0) - + # 页面内容 page_html = Column(Text) page_raw = Column(Text) - - #created_at = Column(DateTime, default=datetime.utcnow) - #updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + + # created_at = Column(DateTime, default=datetime.utcnow) + # updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + # 关联关系 user = relationship("User", back_populates="lazer_profile") class LazerUserCountry(Base): __tablename__ = "lazer_user_countries" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) code = Column(String(2), nullable=False) name = Column(String(100), nullable=False) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class LazerUserKudosu(Base): __tablename__ = "lazer_user_kudosu" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) available = Column(Integer, default=0) total = Column(Integer, default=0) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class LazerUserCounts(Base): __tablename__ = "lazer_user_counts" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - + # 统计计数字段 beatmap_playcounts_count = Column(Integer, default=0) comments_count = Column(Integer, default=0) @@ -172,32 +221,32 @@ class LazerUserCounts(Base): scores_first_count = Column(Integer, default=0) scores_pinned_count = Column(Integer, default=0) scores_recent_count = Column(Integer, default=0) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class LazerUserStatistics(Base): __tablename__ = "lazer_user_statistics" - + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - mode = Column(String(10), nullable=False, default='osu', primary_key=True) - + mode = Column(String(10), nullable=False, default="osu", primary_key=True) + # 基本命中统计 count_100 = Column(Integer, default=0) count_300 = Column(Integer, default=0) count_50 = Column(Integer, default=0) count_miss = Column(Integer, default=0) - + # 等级信息 level_current = Column(Integer, default=1) level_progress = Column(Integer, default=0) - + # 排名信息 global_rank = Column(Integer) global_rank_exp = Column(Integer) country_rank = Column(Integer) - + # PP 和分数 pp = Column(DECIMAL(10, 2), default=0.00) pp_exp = Column(DECIMAL(10, 2), default=0.00) @@ -206,70 +255,72 @@ class LazerUserStatistics(Base): total_score = Column(Integer, default=0) total_hits = Column(Integer, default=0) maximum_combo = Column(Integer, default=0) - + # 游戏统计 play_count = Column(Integer, default=0) play_time = Column(Integer, default=0) # 秒 replays_watched_by_others = Column(Integer, default=0) is_ranked = Column(Boolean, default=False) - + # 成绩等级计数 grade_ss = Column(Integer, default=0) grade_ssh = Column(Integer, default=0) grade_s = Column(Integer, default=0) grade_sh = Column(Integer, default=0) grade_a = Column(Integer, default=0) - + # 最高排名记录 rank_highest = Column(Integer) rank_highest_updated_at = Column(DateTime) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + # 关联关系 user = relationship("User", back_populates="lazer_statistics") class LazerUserAchievement(Base): __tablename__ = "lazer_user_achievements" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) achievement_id = Column(Integer, nullable=False) achieved_at = Column(DateTime, default=datetime.utcnow) - - #created_at = Column(DateTime, default=datetime.utcnow) - #updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + + # created_at = Column(DateTime, default=datetime.utcnow) + # updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + user = relationship("User", back_populates="lazer_achievements") + # ============================================ # 旧的兼容性表模型(保留以便向后兼容) # ============================================ + class LegacyUserStatistics(Base): __tablename__ = "user_statistics" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) mode = Column(String(10), nullable=False) # osu, taiko, fruits, mania - + # 基本统计 count_100 = Column(Integer, default=0) count_300 = Column(Integer, default=0) count_50 = Column(Integer, default=0) count_miss = Column(Integer, default=0) - + # 等级信息 level_current = Column(Integer, default=1) level_progress = Column(Integer, default=0) - + # 排名信息 global_rank = Column(Integer) global_rank_exp = Column(Integer) country_rank = Column(Integer) - + # PP 和分数 pp = Column(Float, default=0.0) pp_exp = Column(Float, default=0.0) @@ -278,34 +329,34 @@ class LegacyUserStatistics(Base): total_score = Column(Integer, default=0) total_hits = Column(Integer, default=0) maximum_combo = Column(Integer, default=0) - + # 游戏统计 play_count = Column(Integer, default=0) play_time = Column(Integer, default=0) replays_watched_by_others = Column(Integer, default=0) is_ranked = Column(Boolean, default=False) - + # 成绩等级计数 grade_ss = Column(Integer, default=0) grade_ssh = Column(Integer, default=0) grade_s = Column(Integer, default=0) grade_sh = Column(Integer, default=0) grade_a = Column(Integer, default=0) - + # 最高排名记录 rank_highest = Column(Integer) rank_highest_updated_at = Column(DateTime) - + created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + # 关联关系 user = relationship("User", back_populates="statistics") class LegacyOAuthToken(Base): __tablename__ = "legacy_oauth_tokens" - + id = Column(Integer, primary_key=True, autoincrement=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) access_token = Column(String(255), nullable=False, index=True) @@ -315,19 +366,19 @@ class LegacyOAuthToken(Base): updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) previous_usernames = Column(JSON, default=list) replays_watched_counts = Column(JSON, default=list) - + # 用户关系 user = relationship("User") # class UserAchievement(Base): # __tablename__ = "lazer_user_achievements" - + # id = Column(Integer, primary_key=True, index=True) # user_id = Column(Integer, ForeignKey("users.id"), nullable=False) # achievement_id = Column(Integer, nullable=False) # achieved_at = Column(DateTime, default=datetime.utcnow) - + # user = relationship("User", back_populates="achievements") @@ -340,34 +391,36 @@ class UserAchievement: class Team(Base): __tablename__ = "teams" - + id = Column(Integer, primary_key=True, index=True) name = Column(String(100), nullable=False) short_name = Column(String(10), nullable=False) flag_url = Column(String(500)) created_at = Column(DateTime, default=datetime.utcnow) - - members = relationship("TeamMember", back_populates="team", cascade="all, delete-orphan") + + members = relationship( + "TeamMember", back_populates="team", cascade="all, delete-orphan" + ) class TeamMember(Base): __tablename__ = "team_members" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) team_id = Column(Integer, ForeignKey("teams.id"), nullable=False) joined_at = Column(DateTime, default=datetime.utcnow) - + user = relationship("User", back_populates="team_membership") team = relationship("Team", back_populates="members") class DailyChallengeStats(Base): __tablename__ = "daily_challenge_stats" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False, unique=True) - + daily_streak_best = Column(Integer, default=0) daily_streak_current = Column(Integer, default=0) last_update = Column(DateTime) @@ -377,25 +430,25 @@ class DailyChallengeStats(Base): top_50p_placements = Column(Integer, default=0) weekly_streak_best = Column(Integer, default=0) weekly_streak_current = Column(Integer, default=0) - + user = relationship("User", back_populates="daily_challenge_stats") class RankHistory(Base): __tablename__ = "rank_history" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) mode = Column(String(10), nullable=False) rank_data = Column(JSON, nullable=False) # Array of ranks date_recorded = Column(DateTime, default=datetime.utcnow) - + user = relationship("User", back_populates="rank_history") class OAuthToken(Base): __tablename__ = "oauth_tokens" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) access_token = Column(String(500), unique=True, nullable=False) @@ -404,13 +457,13 @@ class OAuthToken(Base): scope = Column(String(100), default="*") expires_at = Column(DateTime, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) - + user = relationship("User") class UserAvatar(Base): __tablename__ = "user_avatars" - + id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) filename = Column(String(255), nullable=False) @@ -422,5 +475,5 @@ class UserAvatar(Base): updated_at = Column(Integer, default=lambda: int(datetime.now().timestamp())) r2_original_url = Column(String(500)) r2_game_url = Column(String(500)) - + user = relationship("User", back_populates="avatar") diff --git a/app/dependencies.py b/app/dependencies.py index d3c6cb8..2eb3fce 100644 --- a/app/dependencies.py +++ b/app/dependencies.py @@ -1,5 +1,8 @@ +from __future__ import annotations + from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker + try: import redis except ImportError: @@ -16,6 +19,7 @@ if redis: else: redis_client = None + # 数据库依赖 def get_db(): db = SessionLocal() @@ -24,6 +28,7 @@ def get_db(): finally: db.close() + # Redis 依赖 def get_redis(): return redis_client diff --git a/app/models.py b/app/models.py index 620e2a3..ca42b27 100644 --- a/app/models.py +++ b/app/models.py @@ -1,7 +1,10 @@ -from pydantic import BaseModel, Field -from typing import Optional, List +from __future__ import annotations + from datetime import datetime from enum import Enum +from typing import Optional + +from pydantic import BaseModel class GameMode(str, Enum): @@ -88,7 +91,7 @@ class RankHighest(BaseModel): class RankHistory(BaseModel): mode: str - data: List[int] + data: list[int] class DailyChallengeStats(BaseModel): @@ -132,7 +135,7 @@ class User(BaseModel): last_visit: Optional[datetime] = None pm_friends_only: bool = False profile_colour: Optional[str] = None - + # 个人资料 cover_url: Optional[str] = None discord: Optional[str] = None @@ -144,24 +147,32 @@ class User(BaseModel): max_friends: int = 500 occupation: Optional[str] = None playmode: GameMode = GameMode.OSU - playstyle: List[PlayStyle] = [] + playstyle: list[PlayStyle] = [] post_count: int = 0 profile_hue: Optional[int] = None - profile_order: List[str] = ["me", "recent_activity", "top_ranks", "medals", "historical", "beatmaps", "kudosu"] + profile_order: list[str] = [ + "me", + "recent_activity", + "top_ranks", + "medals", + "historical", + "beatmaps", + "kudosu", + ] title: Optional[str] = None title_url: Optional[str] = None twitter: Optional[str] = None website: Optional[str] = None session_verified: bool = False support_level: int = 0 - + # 关联对象 country: Country cover: Cover kudosu: Kudosu statistics: Statistics statistics_rulesets: dict[str, Statistics] - + # 计数信息 beatmap_playcounts_count: int = 0 comments_count: int = 0 @@ -180,24 +191,24 @@ class User(BaseModel): scores_first_count: int = 0 scores_pinned_count: int = 0 scores_recent_count: int = 0 - + # 历史数据 - account_history: List[dict] = [] + account_history: list[dict] = [] active_tournament_banner: Optional[dict] = None - active_tournament_banners: List[dict] = [] - badges: List[dict] = [] + active_tournament_banners: list[dict] = [] + badges: list[dict] = [] current_season_stats: Optional[dict] = None daily_challenge_user_stats: Optional[DailyChallengeStats] = None - groups: List[dict] = [] - monthly_playcounts: List[MonthlyPlaycount] = [] + groups: list[dict] = [] + monthly_playcounts: list[MonthlyPlaycount] = [] page: Page = Page() - previous_usernames: List[str] = [] + previous_usernames: list[str] = [] rank_highest: Optional[RankHighest] = None rank_history: Optional[RankHistory] = None rankHistory: Optional[RankHistory] = None # 兼容性别名 - replays_watched_counts: List[dict] = [] + replays_watched_counts: list[dict] = [] team: Optional[Team] = None - user_achievements: List[UserAchievement] = [] + user_achievements: list[UserAchievement] = [] # OAuth 相关模型 diff --git a/app/utils.py b/app/utils.py index c762bff..ec7e6aa 100644 --- a/app/utils.py +++ b/app/utils.py @@ -1,48 +1,68 @@ -from typing import Dict, List, Optional +from __future__ import annotations + from datetime import datetime -from app.models import * -from app.database import User as DBUser, LazerUserStatistics, LazerUserProfile, LazerUserCountry, LazerUserKudosu, LazerUserCounts, LazerUserAchievement + +from app.database import User as DBUser +from app.models import ( + Country, + Cover, + DailyChallengeStats, + GameMode, + GradeCounts, + Kudosu, + Level, + Page, + PlayStyle, + RankHighest, + RankHistory, + Statistics, + Team, + User, + UserAchievement, +) + from sqlalchemy.orm import Session -def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_session: Session = None) -> User: +def convert_db_user_to_api_user( + db_user: DBUser, ruleset: str = "osu", db_session: Session | None = None +) -> User: """将数据库用户模型转换为API用户模型(使用 Lazer 表)""" - + # 从db_user获取基本字段值 - user_id = getattr(db_user, 'id') - user_name = getattr(db_user, 'name') - user_country = getattr(db_user, 'country') + user_id = getattr(db_user, "id") + user_name = getattr(db_user, "name") + user_country = getattr(db_user, "country") user_country_code = user_country # 在User模型中,country字段就是country_code - + # 获取 Lazer 用户资料 profile = db_user.lazer_profile if not profile: # 如果没有 lazer 资料,使用默认值 profile = create_default_profile(db_user) - + # 获取指定模式的统计信息 user_stats = None for stat in db_user.lazer_statistics: if stat.mode == ruleset: user_stats = stat break - + if not user_stats: # 如果没有找到指定模式的统计,创建默认统计 user_stats = create_default_lazer_statistics(ruleset) - + # 获取国家信息 country = Country( - code=db_user.country_code, - name=get_country_name(db_user.country_code) + code=user_country_code, name=get_country_name(user_country_code) ) - + # 获取 Kudosu 信息 kudosu = Kudosu(available=0, total=0) - + # 获取计数信息 counts = create_default_counts() - + # 转换统计信息 statistics = Statistics( count_100=user_stats.count_100, @@ -50,8 +70,7 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio count_50=user_stats.count_50, count_miss=user_stats.count_miss, level=Level( - current=user_stats.level_current, - progress=user_stats.level_progress + current=user_stats.level_current, progress=user_stats.level_progress ), global_rank=user_stats.global_rank, global_rank_exp=user_stats.global_rank_exp, @@ -71,12 +90,12 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio ssh=user_stats.grade_ssh, s=user_stats.grade_s, sh=user_stats.grade_sh, - a=user_stats.grade_a + a=user_stats.grade_a, ), country_rank=user_stats.country_rank, - rank={"country": user_stats.country_rank} if user_stats.country_rank else None + rank={"country": user_stats.country_rank} if user_stats.country_rank else None, ) - + # 转换所有模式的统计信息 statistics_rulesets = {} for stat in db_user.statistics: @@ -104,35 +123,36 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio ssh=stat.grade_ssh, s=stat.grade_s, sh=stat.grade_sh, - a=stat.grade_a - ) + a=stat.grade_a, + ), ) - + # 转换国家信息 - country = Country( - code=user_country_code, - name=get_country_name(user_country_code) - ) - + country = Country(code=user_country_code, name=get_country_name(user_country_code)) + # 转换封面信息 - cover_url = profile.cover_url if profile and profile.cover_url else "https://assets.ppy.sh/user-profile-covers/default.jpeg" - cover = Cover( - custom_url=profile.cover_url if profile else None, - url=str(cover_url), - id=None + cover_url = ( + profile.cover_url + if profile and profile.cover_url + else "https://assets.ppy.sh/user-profile-covers/default.jpeg" ) - + cover = Cover( + custom_url=profile.cover_url if profile else None, url=str(cover_url), id=None + ) + # 转换 Kudosu 信息 kudosu = Kudosu(available=0, total=0) - + # 转换成就信息 user_achievements = [] if db_user.lazer_achievements: for achievement in db_user.lazer_achievements: - user_achievements.append(UserAchievement( - achieved_at=achievement.achieved_at, - achievement_id=achievement.achievement_id - )) + user_achievements.append( + UserAchievement( + achieved_at=achievement.achieved_at, + achievement_id=achievement.achievement_id, + ) + ) # 转换排名历史 rank_history = None @@ -141,10 +161,10 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio if rh.mode == ruleset: rank_history_data = rh.rank_data break - + if rank_history_data: rank_history = RankHistory(mode=ruleset, data=rank_history_data) - + # 转换每日挑战统计 daily_challenge_stats = None if db_user.daily_challenge_stats: @@ -159,17 +179,17 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio top_50p_placements=dcs.top_50p_placements, user_id=dcs.user_id, weekly_streak_best=dcs.weekly_streak_best, - weekly_streak_current=dcs.weekly_streak_current + weekly_streak_current=dcs.weekly_streak_current, ) - + # 转换最高排名 rank_highest = None if user_stats.rank_highest: rank_highest = RankHighest( rank=user_stats.rank_highest, - updated_at=user_stats.rank_highest_updated_at or datetime.utcnow() + updated_at=user_stats.rank_highest_updated_at or datetime.utcnow(), ) - + # 转换团队信息 team = None if db_user.team_membership: @@ -178,39 +198,43 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio flag_url=team_member.team.flag_url or "", id=team_member.team.id, name=team_member.team.name, - short_name=team_member.team.short_name + short_name=team_member.team.short_name, ) - + # 创建用户对象 # 从db_user获取基本字段值 - user_id = getattr(db_user, 'id') - user_name = getattr(db_user, 'name') - user_country = getattr(db_user, 'country') - + user_id = getattr(db_user, "id") + user_name = getattr(db_user, "name") + user_country = getattr(db_user, "country") + # 获取用户头像URL avatar_url = None # 首先检查 profile 中的 avatar_url - if profile and hasattr(profile, 'avatar_url') and profile.avatar_url: + if profile and hasattr(profile, "avatar_url") and profile.avatar_url: avatar_url = str(profile.avatar_url) - + # 然后检查是否有关联的头像记录 - if avatar_url is None and hasattr(db_user, 'avatar') and db_user.avatar is not None: + if avatar_url is None and hasattr(db_user, "avatar") and db_user.avatar is not None: if db_user.avatar.r2_game_url: # 优先使用游戏用的头像URL avatar_url = str(db_user.avatar.r2_game_url) elif db_user.avatar.r2_original_url: # 其次使用原始头像URL avatar_url = str(db_user.avatar.r2_original_url) - + # 如果还是没有找到,通过查询获取 if db_session and avatar_url is None: try: # 导入UserAvatar模型 from app.database import UserAvatar - + # 尝试查找用户的头像记录 - avatar_record = db_session.query(UserAvatar).filter_by(user_id=user_id, is_active=True).first() + avatar_record = ( + db_session.query(UserAvatar) + .filter_by(user_id=user_id, is_active=True) + .first() + ) if avatar_record is not None: if avatar_record.r2_game_url is not None: # 优先使用游戏用的头像URL @@ -223,7 +247,7 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio print(f"最终头像URL: {avatar_url}") # 如果仍然没有找到头像URL,则使用默认URL if avatar_url is None: - avatar_url = f"https://a.gu-osu.gmoe.cc/api/users/avatar/1" + avatar_url = "https://a.gu-osu.gmoe.cc/api/users/avatar/1" user = User( id=user_id, @@ -248,21 +272,25 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio location=profile.location if profile else None, max_blocks=profile.max_blocks if profile else 100, max_friends=profile.max_friends if profile else 500, - occupation=None, # 职业字段,默认为 None #待修改 - - #playmode=GameMode(db_user.playmode), - playmode=GameMode("osu"), #待修改 - - playstyle=[PlayStyle.MOUSE, PlayStyle.KEYBOARD, PlayStyle.TABLET], #待修改 - + # playmode=GameMode(db_user.playmode), + playmode=GameMode("osu"), # 待修改 + playstyle=[PlayStyle.MOUSE, PlayStyle.KEYBOARD, PlayStyle.TABLET], # 待修改 post_count=0, profile_hue=None, - profile_order= ['me', 'recent_activity', 'top_ranks', 'medals', 'historical', 'beatmaps', 'kudosu'], + profile_order=[ + "me", + "recent_activity", + "top_ranks", + "medals", + "historical", + "beatmaps", + "kudosu", + ], title=None, title_url=None, twitter=None, - website='https://gmoe.cc', + website="https://gmoe.cc", session_verified=True, support_level=0, country=country, @@ -295,7 +323,7 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio daily_challenge_user_stats=None, groups=[], monthly_playcounts=[], - #page=Page(html=db_user.page_html, raw=db_user.page_raw), + # page=Page(html=db_user.page_html, raw=db_user.page_raw), page=Page(), # Provide a default Page object previous_usernames=[], rank_highest=rank_highest, @@ -303,9 +331,9 @@ def convert_db_user_to_api_user(db_user: DBUser, ruleset: str = "osu", db_sessio rankHistory=rank_history, # 兼容性别名 replays_watched_counts=[], team=team, - user_achievements=user_achievements + user_achievements=user_achievements, ) - + return user @@ -329,6 +357,7 @@ def get_country_name(country_code: str) -> str: def create_default_profile(db_user: DBUser): """创建默认的用户资料""" + class MockProfile: def __init__(self): self.is_active = True @@ -340,7 +369,7 @@ def create_default_profile(db_user: DBUser): self.session_verified = False self.has_supported = False self.pm_friends_only = False - self.default_group = 'default' + self.default_group = "default" self.last_visit = None self.join_date = db_user.join_date self.profile_colour = None @@ -355,19 +384,20 @@ def create_default_profile(db_user: DBUser): self.interests = None self.location = None self.occupation = None - self.playmode = 'osu' + self.playmode = "osu" self.support_level = 0 self.max_blocks = 100 self.max_friends = 500 self.post_count = 0 self.page_html = None self.page_raw = None - + return MockProfile() def create_default_lazer_statistics(mode: str): """创建默认的 Lazer 统计信息""" + class MockLazerStatistics: def __init__(self, mode: str): self.mode = mode @@ -398,32 +428,35 @@ def create_default_lazer_statistics(mode: str): self.country_rank = None self.rank_highest = None self.rank_highest_updated_at = None - + return MockLazerStatistics(mode) def create_default_country(country_code: str): """创建默认的国家信息""" + class MockCountry: def __init__(self, code: str): self.code = code self.name = get_country_name(code) - + return MockCountry(country_code) def create_default_kudosu(): """创建默认的 Kudosu 信息""" + class MockKudosu: def __init__(self): self.available = 0 self.total = 0 - + return MockKudosu() def create_default_counts(): """创建默认的计数信息""" + class MockCounts: def __init__(self): self.beatmap_playcounts_count = 0 @@ -443,5 +476,5 @@ def create_default_counts(): self.scores_first_count = 0 self.scores_pinned_count = 0 self.scores_recent_count = 0 - + return MockCounts() diff --git a/create_sample_data.py b/create_sample_data.py index e6bf457..ce8695b 100644 --- a/create_sample_data.py +++ b/create_sample_data.py @@ -3,31 +3,41 @@ osu! API 模拟服务器的示例数据填充脚本 """ -from datetime import datetime, timedelta +from __future__ import annotations + +from datetime import datetime import time -from sqlalchemy.orm import Session -from app.dependencies import get_db, engine -from app.database import Base, User, UserStatistics, UserAchievement, DailyChallengeStats, RankHistory + from app.auth import get_password_hash +from app.database import ( + Base, + DailyChallengeStats, + LazerUserStatistics as UserStatistics, + RankHistory, + User, + UserAchievement, +) +from app.dependencies import engine, get_db # 创建所有表 Base.metadata.create_all(bind=engine) + def create_sample_user(): """创建示例用户数据""" db = next(get_db()) - + # 检查用户是否已存在 existing_user = db.query(User).filter(User.name == "Googujiang").first() if existing_user: print("示例用户已存在,跳过创建") return existing_user - + # 当前时间戳 current_timestamp = int(time.time()) join_timestamp = int(datetime(2019, 11, 29, 17, 23, 13).timestamp()) last_visit_timestamp = int(datetime(2025, 7, 18, 16, 31, 29).timestamp()) - + # 创建用户 user = User( name="Googujiang", @@ -48,91 +58,98 @@ def create_sample_user(): custom_badge_icon=None, userpage_content="「世界に忘れられた」", api_key=None, - - # 兼容性字段 - avatar_url="https://a.ppy.sh/15651670?1732362658.jpeg", - cover_url="https://assets.ppy.sh/user-profile-covers/15651670/0fc7b77adef39765a570e7f535bc383e5a848850d41a8943f8857984330b8bc6.jpeg", - has_supported=True, - interests="「世界に忘れられた」", - location="咕谷国", - website="https://gmoe.cc", - playstyle=["mouse", "keyboard", "tablet"], - profile_order=["me", "recent_activity", "top_ranks", "medals", "historical", "beatmaps", "kudosu"], - beatmap_playcounts_count=3306, - favourite_beatmapset_count=15, - follower_count=98, - graveyard_beatmapset_count=7, - mapping_follower_count=1, - previous_usernames=["hehejun"], - monthly_playcounts=[ - {"start_date": "2019-11-01", "count": 43}, - {"start_date": "2020-04-01", "count": 216}, - {"start_date": "2020-05-01", "count": 656}, - {"start_date": "2020-07-01", "count": 158}, - {"start_date": "2020-08-01", "count": 174}, - {"start_date": "2020-10-01", "count": 13}, - {"start_date": "2020-11-01", "count": 52}, - {"start_date": "2020-12-01", "count": 140}, - {"start_date": "2021-01-01", "count": 359}, - {"start_date": "2021-02-01", "count": 452}, - {"start_date": "2021-03-01", "count": 77}, - {"start_date": "2021-04-01", "count": 114}, - {"start_date": "2021-05-01", "count": 270}, - {"start_date": "2021-06-01", "count": 148}, - {"start_date": "2021-07-01", "count": 246}, - {"start_date": "2021-08-01", "count": 56}, - {"start_date": "2021-09-01", "count": 136}, - {"start_date": "2021-10-01", "count": 45}, - {"start_date": "2021-11-01", "count": 98}, - {"start_date": "2021-12-01", "count": 54}, - {"start_date": "2022-01-01", "count": 88}, - {"start_date": "2022-02-01", "count": 45}, - {"start_date": "2022-03-01", "count": 6}, - {"start_date": "2022-04-01", "count": 54}, - {"start_date": "2022-05-01", "count": 105}, - {"start_date": "2022-06-01", "count": 37}, - {"start_date": "2022-07-01", "count": 88}, - {"start_date": "2022-08-01", "count": 7}, - {"start_date": "2022-09-01", "count": 9}, - {"start_date": "2022-10-01", "count": 6}, - {"start_date": "2022-11-01", "count": 2}, - {"start_date": "2022-12-01", "count": 16}, - {"start_date": "2023-01-01", "count": 7}, - {"start_date": "2023-04-01", "count": 16}, - {"start_date": "2023-05-01", "count": 3}, - {"start_date": "2023-06-01", "count": 8}, - {"start_date": "2023-07-01", "count": 23}, - {"start_date": "2023-08-01", "count": 3}, - {"start_date": "2023-09-01", "count": 1}, - {"start_date": "2023-10-01", "count": 25}, - {"start_date": "2023-11-01", "count": 160}, - {"start_date": "2023-12-01", "count": 306}, - {"start_date": "2024-01-01", "count": 735}, - {"start_date": "2024-02-01", "count": 420}, - {"start_date": "2024-03-01", "count": 549}, - {"start_date": "2024-04-01", "count": 466}, - {"start_date": "2024-05-01", "count": 333}, - {"start_date": "2024-06-01", "count": 1126}, - {"start_date": "2024-07-01", "count": 534}, - {"start_date": "2024-08-01", "count": 280}, - {"start_date": "2024-09-01", "count": 116}, - {"start_date": "2024-10-01", "count": 120}, - {"start_date": "2024-11-01", "count": 332}, - {"start_date": "2024-12-01", "count": 243}, - {"start_date": "2025-01-01", "count": 122}, - {"start_date": "2025-02-01", "count": 379}, - {"start_date": "2025-03-01", "count": 278}, - {"start_date": "2025-04-01", "count": 296}, - {"start_date": "2025-05-01", "count": 964}, - {"start_date": "2025-06-01", "count": 821}, - {"start_date": "2025-07-01", "count": 230} - ] + # # 兼容性字段 + # avatar_url="https://a.ppy.sh/15651670?1732362658.jpeg", + # cover_url="https://assets.ppy.sh/user-profile-covers/15651670/0fc7b77adef39765a570e7f535bc383e5a848850d41a8943f8857984330b8bc6.jpeg", + # has_supported=True, + # interests="「世界に忘れられた」", + # location="咕谷国", + # website="https://gmoe.cc", + # playstyle=["mouse", "keyboard", "tablet"], + # profile_order=[ + # "me", + # "recent_activity", + # "top_ranks", + # "medals", + # "historical", + # "beatmaps", + # "kudosu", + # ], + # beatmap_playcounts_count=3306, + # favourite_beatmapset_count=15, + # follower_count=98, + # graveyard_beatmapset_count=7, + # mapping_follower_count=1, + # previous_usernames=["hehejun"], + # monthly_playcounts=[ + # {"start_date": "2019-11-01", "count": 43}, + # {"start_date": "2020-04-01", "count": 216}, + # {"start_date": "2020-05-01", "count": 656}, + # {"start_date": "2020-07-01", "count": 158}, + # {"start_date": "2020-08-01", "count": 174}, + # {"start_date": "2020-10-01", "count": 13}, + # {"start_date": "2020-11-01", "count": 52}, + # {"start_date": "2020-12-01", "count": 140}, + # {"start_date": "2021-01-01", "count": 359}, + # {"start_date": "2021-02-01", "count": 452}, + # {"start_date": "2021-03-01", "count": 77}, + # {"start_date": "2021-04-01", "count": 114}, + # {"start_date": "2021-05-01", "count": 270}, + # {"start_date": "2021-06-01", "count": 148}, + # {"start_date": "2021-07-01", "count": 246}, + # {"start_date": "2021-08-01", "count": 56}, + # {"start_date": "2021-09-01", "count": 136}, + # {"start_date": "2021-10-01", "count": 45}, + # {"start_date": "2021-11-01", "count": 98}, + # {"start_date": "2021-12-01", "count": 54}, + # {"start_date": "2022-01-01", "count": 88}, + # {"start_date": "2022-02-01", "count": 45}, + # {"start_date": "2022-03-01", "count": 6}, + # {"start_date": "2022-04-01", "count": 54}, + # {"start_date": "2022-05-01", "count": 105}, + # {"start_date": "2022-06-01", "count": 37}, + # {"start_date": "2022-07-01", "count": 88}, + # {"start_date": "2022-08-01", "count": 7}, + # {"start_date": "2022-09-01", "count": 9}, + # {"start_date": "2022-10-01", "count": 6}, + # {"start_date": "2022-11-01", "count": 2}, + # {"start_date": "2022-12-01", "count": 16}, + # {"start_date": "2023-01-01", "count": 7}, + # {"start_date": "2023-04-01", "count": 16}, + # {"start_date": "2023-05-01", "count": 3}, + # {"start_date": "2023-06-01", "count": 8}, + # {"start_date": "2023-07-01", "count": 23}, + # {"start_date": "2023-08-01", "count": 3}, + # {"start_date": "2023-09-01", "count": 1}, + # {"start_date": "2023-10-01", "count": 25}, + # {"start_date": "2023-11-01", "count": 160}, + # {"start_date": "2023-12-01", "count": 306}, + # {"start_date": "2024-01-01", "count": 735}, + # {"start_date": "2024-02-01", "count": 420}, + # {"start_date": "2024-03-01", "count": 549}, + # {"start_date": "2024-04-01", "count": 466}, + # {"start_date": "2024-05-01", "count": 333}, + # {"start_date": "2024-06-01", "count": 1126}, + # {"start_date": "2024-07-01", "count": 534}, + # {"start_date": "2024-08-01", "count": 280}, + # {"start_date": "2024-09-01", "count": 116}, + # {"start_date": "2024-10-01", "count": 120}, + # {"start_date": "2024-11-01", "count": 332}, + # {"start_date": "2024-12-01", "count": 243}, + # {"start_date": "2025-01-01", "count": 122}, + # {"start_date": "2025-02-01", "count": 379}, + # {"start_date": "2025-03-01", "count": 278}, + # {"start_date": "2025-04-01", "count": 296}, + # {"start_date": "2025-05-01", "count": 964}, + # {"start_date": "2025-06-01", "count": 821}, + # {"start_date": "2025-07-01", "count": 230}, + # ], ) - + db.add(user) db.commit() db.refresh(user) - + # 创建 osu! 模式统计 osu_stats = UserStatistics( user_id=user.id, @@ -161,9 +178,9 @@ def create_sample_user(): grade_sh=11, grade_a=757, rank_highest=295701, - rank_highest_updated_at=datetime(2025, 7, 2, 17, 30, 21) + rank_highest_updated_at=datetime(2025, 7, 2, 17, 30, 21), ) - + # 创建 taiko 模式统计 taiko_stats = UserStatistics( user_id=user.id, @@ -184,9 +201,9 @@ def create_sample_user(): total_hits=314, maximum_combo=0, replays_watched_by_others=0, - is_ranked=False + is_ranked=False, ) - + # 创建 fruits 模式统计 fruits_stats = UserStatistics( user_id=user.id, @@ -208,9 +225,9 @@ def create_sample_user(): maximum_combo=75, replays_watched_by_others=0, is_ranked=False, - grade_a=1 + grade_a=1, ) - + # 创建 mania 模式统计 mania_stats = UserStatistics( user_id=user.id, @@ -232,11 +249,11 @@ def create_sample_user(): maximum_combo=573, replays_watched_by_others=0, is_ranked=True, - grade_a=1 + grade_a=1, ) - + db.add_all([osu_stats, taiko_stats, fruits_stats, mania_stats]) - + # 创建每日挑战统计 daily_challenge = DailyChallengeStats( user_id=user.id, @@ -248,33 +265,140 @@ def create_sample_user(): top_10p_placements=0, top_50p_placements=0, weekly_streak_best=1, - weekly_streak_current=0 + weekly_streak_current=0, ) - + db.add(daily_challenge) - + # 创建排名历史 (最近90天的数据) - rank_data = [322806, 323092, 323341, 323616, 323853, 324106, 324378, 324676, 324958, 325254, 325492, 325780, 326075, 326356, 326586, 326845, 327067, 327286, 327526, 327778, 328039, 328347, 328631, 328858, 329323, 329557, 329809, 329911, 330188, 330425, 330650, 330881, 331068, 331325, 331575, 331816, 332061, 328959, 315648, 315881, 308784, 309023, 309252, 309433, 309537, 309364, 309548, 308957, 309182, 309426, 309607, 309831, 310054, 310269, 310485, 310714, 310956, 310924, 311125, 311203, 311422, 311640, 303091, 303309, 303500, 303691, 303758, 303750, 303957, 299867, 300088, 300273, 300457, 295799, 295976, 296153, 296350, 296566, 296756, 296933, 297141, 297314, 297480, 297114, 297296, 297480, 297645, 297815, 297993, 298026] - - rank_history = RankHistory( - user_id=user.id, - mode="osu", - rank_data=rank_data - ) - + rank_data = [ + 322806, + 323092, + 323341, + 323616, + 323853, + 324106, + 324378, + 324676, + 324958, + 325254, + 325492, + 325780, + 326075, + 326356, + 326586, + 326845, + 327067, + 327286, + 327526, + 327778, + 328039, + 328347, + 328631, + 328858, + 329323, + 329557, + 329809, + 329911, + 330188, + 330425, + 330650, + 330881, + 331068, + 331325, + 331575, + 331816, + 332061, + 328959, + 315648, + 315881, + 308784, + 309023, + 309252, + 309433, + 309537, + 309364, + 309548, + 308957, + 309182, + 309426, + 309607, + 309831, + 310054, + 310269, + 310485, + 310714, + 310956, + 310924, + 311125, + 311203, + 311422, + 311640, + 303091, + 303309, + 303500, + 303691, + 303758, + 303750, + 303957, + 299867, + 300088, + 300273, + 300457, + 295799, + 295976, + 296153, + 296350, + 296566, + 296756, + 296933, + 297141, + 297314, + 297480, + 297114, + 297296, + 297480, + 297645, + 297815, + 297993, + 298026, + ] + + rank_history = RankHistory(user_id=user.id, mode="osu", rank_data=rank_data) + db.add(rank_history) - + # 创建一些成就 achievements = [ - UserAchievement(user_id=user.id, achievement_id=336, achieved_at=datetime(2025, 6, 21, 19, 6, 32)), - UserAchievement(user_id=user.id, achievement_id=319, achieved_at=datetime(2025, 6, 1, 0, 52, 0)), - UserAchievement(user_id=user.id, achievement_id=222, achieved_at=datetime(2025, 5, 28, 12, 24, 37)), - UserAchievement(user_id=user.id, achievement_id=38, achieved_at=datetime(2024, 7, 5, 15, 43, 23)), - UserAchievement(user_id=user.id, achievement_id=67, achieved_at=datetime(2024, 6, 24, 5, 6, 44)), + UserAchievement( + # user_id=user.id, + achievement_id=336, + achieved_at=datetime(2025, 6, 21, 19, 6, 32), + ), + UserAchievement( + # user_id=user.id, + achievement_id=319, + achieved_at=datetime(2025, 6, 1, 0, 52, 0), + ), + UserAchievement( + # user_id=user.id, + achievement_id=222, + achieved_at=datetime(2025, 5, 28, 12, 24, 37), + ), + UserAchievement( + # user_id=user.id, + achievement_id=38, + achieved_at=datetime(2024, 7, 5, 15, 43, 23), + ), + UserAchievement( + # user_id=user.id, + achievement_id=67, + achieved_at=datetime(2024, 6, 24, 5, 6, 44), + ), ] - + db.add_all(achievements) - + db.commit() print(f"成功创建示例用户: {user.name} (ID: {user.id})") print(f"安全用户名: {user.safe_name}") @@ -288,5 +412,5 @@ if __name__ == "__main__": user = create_sample_user() print("示例数据创建完成!") print(f"用户名: {user.name}") - print(f"密码: password123") + print("密码: password123") print("现在您可以使用这些凭据来测试API了。") diff --git a/main.py b/main.py index 12780fb..ce95a4e 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,32 @@ -from fastapi import FastAPI, Depends, HTTPException, Form -from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials -from fastapi.responses import JSONResponse -from sqlalchemy.orm import Session -from typing import Optional -from datetime import datetime, timedelta +from __future__ import annotations +from datetime import datetime, timedelta +from typing import Optional + +from app.auth import ( + authenticate_user, + create_access_token, + generate_refresh_token, + get_token_by_access_token, + get_token_by_refresh_token, + store_token, +) from app.config import settings -from app.dependencies import get_db, get_redis, engine -from app.models import TokenRequest, TokenResponse, User as ApiUser -from app.database import Base, User as DBUser -from app.auth import authenticate_user, create_access_token, generate_refresh_token, store_token -from app.auth import get_token_by_access_token, get_token_by_refresh_token, verify_token +from app.database import ( + User as DBUser, +) +from app.dependencies import get_db +from app.models import ( + TokenResponse, + User as ApiUser, +) from app.utils import convert_db_user_to_api_user +from fastapi import Depends, FastAPI, Form, HTTPException +from fastapi.responses import JSONResponse +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer +from sqlalchemy.orm import Session + # 注意: 表结构现在通过 migrations 管理,不再自动创建 # 如需创建表,请运行: python quick_sync.py @@ -30,110 +44,114 @@ async def oauth_token( username: Optional[str] = Form(None), password: Optional[str] = Form(None), refresh_token: Optional[str] = Form(None), - db: Session = Depends(get_db) + db: Session = Depends(get_db), ): """OAuth 令牌端点""" # 验证客户端凭据 - if client_id != settings.OSU_CLIENT_ID or client_secret != settings.OSU_CLIENT_SECRET: + if ( + client_id != settings.OSU_CLIENT_ID + or client_secret != settings.OSU_CLIENT_SECRET + ): raise HTTPException(status_code=401, detail="Invalid client credentials") - + if grant_type == "password": # 密码授权流程 if not username or not password: - raise HTTPException(status_code=400, detail="Username and password required") - + raise HTTPException( + status_code=400, detail="Username and password required" + ) + # 验证用户 user = authenticate_user(db, username, password) if not user: raise HTTPException(status_code=401, detail="Invalid username or password") - + # 生成令牌 access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": str(user.id)}, expires_delta=access_token_expires ) refresh_token_str = generate_refresh_token() - + # 存储令牌 store_token( - db, - user.id, - access_token, - refresh_token_str, - settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60 + db, + user.id, + access_token, + refresh_token_str, + settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60, ) - + return TokenResponse( access_token=access_token, token_type="Bearer", expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60, refresh_token=refresh_token_str, - scope=scope + scope=scope, ) - + elif grant_type == "refresh_token": # 刷新令牌流程 if not refresh_token: raise HTTPException(status_code=400, detail="Refresh token required") - + # 验证刷新令牌 token_record = get_token_by_refresh_token(db, refresh_token) if not token_record: raise HTTPException(status_code=401, detail="Invalid refresh token") - + # 生成新的访问令牌 access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": str(token_record.user_id)}, expires_delta=access_token_expires ) new_refresh_token = generate_refresh_token() - + # 更新令牌 store_token( db, token_record.user_id, access_token, new_refresh_token, - settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60 + settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60, ) - + return TokenResponse( access_token=access_token, token_type="Bearer", expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60, refresh_token=new_refresh_token, - scope=scope + scope=scope, ) - + else: raise HTTPException(status_code=400, detail="Unsupported grant type") async def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(security), - db: Session = Depends(get_db) + db: Session = Depends(get_db), ) -> DBUser: """获取当前认证用户""" token = credentials.credentials - + # 验证令牌 token_record = get_token_by_access_token(db, token) if not token_record: raise HTTPException(status_code=401, detail="Invalid or expired token") - + # 获取用户 user = db.query(DBUser).filter(DBUser.id == token_record.user_id).first() if not user: raise HTTPException(status_code=404, detail="User not found") - + return user @app.get("/api/v2/me", response_model=ApiUser) @app.get("/api/v2/me/", response_model=ApiUser) async def get_user_info_default( - current_user: DBUser = Depends(get_current_user), - db: Session = Depends(get_db) + current_user: DBUser = Depends(get_current_user), db: Session = Depends(get_db) ): """获取当前用户信息(默认使用osu模式)""" # 默认使用osu模式 @@ -145,15 +163,17 @@ async def get_user_info_default( async def get_user_info( ruleset: str = "osu", current_user: DBUser = Depends(get_current_user), - db: Session = Depends(get_db) + db: Session = Depends(get_db), ): """获取当前用户信息""" - + # 验证游戏模式 valid_rulesets = ["osu", "taiko", "fruits", "mania"] if ruleset not in valid_rulesets: - raise HTTPException(status_code=400, detail=f"Invalid ruleset. Must be one of: {valid_rulesets}") - + raise HTTPException( + status_code=400, detail=f"Invalid ruleset. Must be one of: {valid_rulesets}" + ) + # 转换用户数据 api_user = convert_db_user_to_api_user(current_user, ruleset, db) return api_user @@ -171,26 +191,24 @@ async def health_check(): return {"status": "ok", "timestamp": datetime.utcnow().isoformat()} - @app.get("/api/v2/friends") async def get_friends(): - return JSONResponse(content=[ - { - "id": 123456, - "username": "BestFriend", - "is_online": True, - "is_supporter": False, - "country": {"code": "US", "name": "United States"} - } - ]) + return JSONResponse( + content=[ + { + "id": 123456, + "username": "BestFriend", + "is_online": True, + "is_supporter": False, + "country": {"code": "US", "name": "United States"}, + } + ] + ) @app.get("/api/v2/notifications") async def get_notifications(): - return JSONResponse(content={ - "notifications": [], - "unread_count": 0 - }) + return JSONResponse(content={"notifications": [], "unread_count": 0}) @app.post("/api/v2/chat/ack") @@ -200,80 +218,80 @@ async def chat_ack(): @app.get("/api/v2/users/{user_id}/{mode}") async def get_user_mode(user_id: int, mode: str): - return JSONResponse(content={ - "id": user_id, - "username": "测试测试测", - "statistics": { - "level": {"current": 97, "progress": 96}, - "pp": 114514, - "global_rank": 666, - "country_rank": 1, - "hit_accuracy": 100 - }, - "country": {"code": "JP", "name": "Japan"} - }) + return JSONResponse( + content={ + "id": user_id, + "username": "测试测试测", + "statistics": { + "level": {"current": 97, "progress": 96}, + "pp": 114514, + "global_rank": 666, + "country_rank": 1, + "hit_accuracy": 100, + }, + "country": {"code": "JP", "name": "Japan"}, + } + ) @app.get("/api/v2/me") async def get_me(): - return JSONResponse(content={ - "id": 15651670, - "username": "Googujiang", - "is_online": True, - "country": {"code": "JP", "name": "Japan"}, - "statistics": { - "level": {"current": 97, "progress": 96}, - "pp": 2826.26, - "global_rank": 298026, - "country_rank": 11220, - "hit_accuracy": 95.7168 + return JSONResponse( + content={ + "id": 15651670, + "username": "Googujiang", + "is_online": True, + "country": {"code": "JP", "name": "Japan"}, + "statistics": { + "level": {"current": 97, "progress": 96}, + "pp": 2826.26, + "global_rank": 298026, + "country_rank": 11220, + "hit_accuracy": 95.7168, + }, } - }) + ) @app.post("/signalr/metadata/negotiate") async def metadata_negotiate(negotiateVersion: int = 1): - return JSONResponse(content={ - "connectionId": "abc123", - "availableTransports": [ - { - "transport": "WebSockets", - "transferFormats": ["Text", "Binary"] - } - ] - }) + return JSONResponse( + content={ + "connectionId": "abc123", + "availableTransports": [ + {"transport": "WebSockets", "transferFormats": ["Text", "Binary"]} + ], + } + ) @app.post("/signalr/spectator/negotiate") async def spectator_negotiate(negotiateVersion: int = 1): - return JSONResponse(content={ - "connectionId": "spec456", - "availableTransports": [ - { - "transport": "WebSockets", - "transferFormats": ["Text", "Binary"] - } - ] - }) + return JSONResponse( + content={ + "connectionId": "spec456", + "availableTransports": [ + {"transport": "WebSockets", "transferFormats": ["Text", "Binary"]} + ], + } + ) @app.post("/signalr/multiplayer/negotiate") async def multiplayer_negotiate(negotiateVersion: int = 1): - return JSONResponse(content={ - "connectionId": "multi789", - "availableTransports": [ - { - "transport": "WebSockets", - "transferFormats": ["Text", "Binary"] - } - ] - }) + return JSONResponse( + content={ + "connectionId": "multi789", + "availableTransports": [ + {"transport": "WebSockets", "transferFormats": ["Text", "Binary"]} + ], + } + ) + if __name__ == "__main__": import uvicorn + uvicorn.run( - "main:app", - host=settings.HOST, - port=settings.PORT, - reload=settings.DEBUG + "main:app", host=settings.HOST, port=settings.PORT, reload=settings.DEBUG ) diff --git a/osu_api_example.py b/osu_api_example.py index c07e776..342d522 100644 --- a/osu_api_example.py +++ b/osu_api_example.py @@ -1,9 +1,14 @@ -import requests +from __future__ import annotations + import os -CLIENT_ID = os.environ.get('OSU_CLIENT_ID', '5') -CLIENT_SECRET = os.environ.get('OSU_CLIENT_SECRET', 'FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk') -API_URL = os.environ.get('OSU_API_URL', 'https://osu.ppy.sh') +import requests + +CLIENT_ID = os.environ.get("OSU_CLIENT_ID", "5") +CLIENT_SECRET = os.environ.get( + "OSU_CLIENT_SECRET", "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" +) +API_URL = os.environ.get("OSU_API_URL", "https://osu.ppy.sh") def authenticate(username: str, password: str): @@ -56,4 +61,4 @@ if __name__ == "__main__": print("Access Token:", token["access_token"]) user = get_current_user(token["access_token"]) - print(user) \ No newline at end of file + print(user) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3327269 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,86 @@ +[project] +name = "osu-lazer-api" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "alembic>=1.12.1", + "bcrypt>=4.1.2", + "cryptography>=41.0.7", + "fastapi>=0.104.1", + "passlib[bcrypt]>=1.7.4", + "pydantic[email]>=2.5.0", + "pymysql>=1.1.0", + "python-dotenv>=1.0.0", + "python-jose[cryptography]>=3.3.0", + "python-multipart>=0.0.6", + "redis>=5.0.1", + "sqlalchemy>=2.0.23", + "uvicorn[standard]>=0.24.0", +] + +[tool.ruff] +line-length = 88 +target-version = "py39" + +[tool.ruff.format] +line-ending = "lf" + +[tool.ruff.lint] +select = [ + "F", # Pyflakes + "W", # pycodestyle warnings + "E", # pycodestyle errors + "I", # isort + "UP", # pyupgrade + "ASYNC", # flake8-async + "C4", # flake8-comprehensions + "T10", # flake8-debugger + # "T20", # flake8-print + "PYI", # flake8-pyi + "PT", # flake8-pytest-style + "Q", # flake8-quotes + "TID", # flake8-tidy-imports + "RUF", # Ruff-specific rules +] +ignore = [ + "E402", # module-import-not-at-top-of-file + "UP037", # quoted-annotation + "RUF001", # ambiguous-unicode-character-string + "RUF002", # ambiguous-unicode-character-docstring + "RUF003", # ambiguous-unicode-character-comment +] + + +[tool.ruff.lint.isort] +force-sort-within-sections = true +force-wrap-aliases = true +combine-as-imports = true +order-by-type = true +relative-imports-order = "closest-to-furthest" +required-imports = ["from __future__ import annotations"] +extra-standard-library = ["typing_extensions"] +section-order = ["future", "standard-library", "first-party", "local-folder", "third-party"] + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.pyupgrade] +keep-runtime-typing = true + +[tool.pyright] +pythonVersion = "3.11" +pythonPlatform = "All" + +typeCheckingMode = "standard" +reportShadowedImports = false +disableBytesTypePromotions = true +reportIncompatibleMethodOverride = false +reportIncompatibleVariableOverride = false + +[dependency-groups] +dev = [ + "ruff>=0.12.4", +] diff --git a/quick_sync.py b/quick_sync.py index 4a0ed17..7014ed4 100644 --- a/quick_sync.py +++ b/quick_sync.py @@ -4,63 +4,63 @@ 直接使用项目配置执行数据同步 """ +from __future__ import annotations + import os -import sys import subprocess from urllib.parse import urlparse + from app.config import settings + def parse_database_url(): """解析数据库 URL""" url = urlparse(settings.DATABASE_URL) return { - 'host': url.hostname or 'localhost', - 'port': url.port or 3306, - 'user': url.username or 'root', - 'password': url.password or '', - 'database': url.path.lstrip('/') if url.path else 'osu_api' + "host": url.hostname or "localhost", + "port": url.port or 3306, + "user": url.username or "root", + "password": url.password or "", + "database": url.path.lstrip("/") if url.path else "osu_api", } + def run_sql_script(script_path: str): """使用 mysql 命令行执行 SQL 脚本""" if not os.path.exists(script_path): print(f"错误: SQL 脚本不存在 - {script_path}") return False - + # 解析数据库配置 db_config = parse_database_url() - + # 构建 mysql 命令 cmd = [ - 'mysql', - f'--host={db_config["host"]}', - f'--port={db_config["port"]}', - f'--user={db_config["user"]}', - db_config['database'] + "mysql", + f"--host={db_config['host']}", + f"--port={db_config['port']}", + f"--user={db_config['user']}", + db_config["database"], ] - + # 添加密码(如果有的话) - if db_config['password']: - cmd.insert(-1, f'--password={db_config["password"]}') - + if db_config["password"]: + cmd.insert(-1, f"--password={db_config['password']}") + try: print(f"执行 SQL 脚本: {script_path}") - with open(script_path, 'r', encoding='utf-8') as f: + with open(script_path, encoding="utf-8") as f: result = subprocess.run( - cmd, - stdin=f, - capture_output=True, - text=True, - check=True + cmd, stdin=f, capture_output=True, text=True, check=True ) - + if result.stdout: print("执行结果:") print(result.stdout) - + print(f"✓ 成功执行: {script_path}") return True - + except subprocess.CalledProcessError as e: print(f"✗ 执行失败: {script_path}") print(f"错误信息: {e.stderr}") @@ -70,57 +70,59 @@ def run_sql_script(script_path: str): print("请确保 MySQL 客户端已安装并添加到 PATH 环境变量中") return False + def main(): """主函数""" print("Lazer API 快速数据同步") print("=" * 40) - + db_config = parse_database_url() print(f"数据库: {db_config['host']}:{db_config['port']}/{db_config['database']}") print() - + # 确认是否继续 print("这将执行以下操作:") print("1. 创建 lazer 专用表结构") print("2. 同步现有用户数据到新表") print("3. 不会修改现有的原始表数据") print() - + confirm = input("是否继续? (y/N): ").strip().lower() - if confirm != 'y': + if confirm != "y": print("操作已取消") return - + # 获取脚本路径 script_dir = os.path.dirname(__file__) - migrations_dir = os.path.join(script_dir, 'migrations') - + migrations_dir = os.path.join(script_dir, "migrations") + # 第一步: 创建表结构 print("\n步骤 1: 创建 lazer 专用表结构...") - add_fields_script = os.path.join(migrations_dir, 'add_missing_fields.sql') + add_fields_script = os.path.join(migrations_dir, "add_missing_fields.sql") if not run_sql_script(add_fields_script): print("表结构创建失败,停止执行") return - + # 第二步: 同步数据 print("\n步骤 2: 同步历史数据...") - sync_script = os.path.join(migrations_dir, 'sync_legacy_data.sql') + sync_script = os.path.join(migrations_dir, "sync_legacy_data.sql") if not run_sql_script(sync_script): print("数据同步失败") return - + # 第三步: 添加缺失的字段 print("\n步骤 3: 添加缺失的字段...") - add_rank_fields_script = os.path.join(migrations_dir, 'add_lazer_rank_fields.sql') + add_rank_fields_script = os.path.join(migrations_dir, "add_lazer_rank_fields.sql") if not run_sql_script(add_rank_fields_script): print("添加字段失败") return - + print("\n🎉 数据同步完成!") print("\n现在您可以:") print("1. 启动 Lazer API 服务器") print("2. 使用现有用户账号登录") print("3. 查看同步后的用户数据") + if __name__ == "__main__": main() diff --git a/sync_data.py b/sync_data.py index 7408e99..f3257ce 100644 --- a/sync_data.py +++ b/sync_data.py @@ -4,25 +4,24 @@ Lazer API 数据同步脚本 用于将现有的 bancho.py 数据同步到新的 lazer 专用表中 """ +from __future__ import annotations + +import logging import os import sys + import pymysql -from typing import Optional -import logging -from datetime import datetime # 配置日志 logging.basicConfig( level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler('data_sync.log'), - logging.StreamHandler(sys.stdout) - ] + format="%(asctime)s - %(levelname)s - %(message)s", + handlers=[logging.FileHandler("data_sync.log"), logging.StreamHandler(sys.stdout)], ) logger = logging.getLogger(__name__) + class DatabaseSyncer: def __init__(self, host: str, port: int, user: str, password: str, database: str): """初始化数据库连接配置""" @@ -32,7 +31,7 @@ class DatabaseSyncer: self.password = password self.database = database self.connection = None - + def connect(self): """连接到数据库""" try: @@ -42,72 +41,74 @@ class DatabaseSyncer: user=self.user, password=self.password, database=self.database, - charset='utf8mb4', - autocommit=False + charset="utf8mb4", + autocommit=False, ) logger.info(f"成功连接到数据库 {self.database}") except Exception as e: logger.error(f"连接数据库失败: {e}") raise - + def disconnect(self): """断开数据库连接""" if self.connection: self.connection.close() logger.info("数据库连接已关闭") - + def execute_sql_file(self, file_path: str): """执行 SQL 文件""" if not os.path.exists(file_path): logger.error(f"SQL 文件不存在: {file_path}") return False - + try: - with open(file_path, 'r', encoding='utf-8') as f: + with open(file_path, encoding="utf-8") as f: sql_content = f.read() - + # 分割SQL语句(简单实现,按分号分割) - statements = [stmt.strip() for stmt in sql_content.split(';') if stmt.strip()] - + statements = [ + stmt.strip() for stmt in sql_content.split(";") if stmt.strip() + ] + cursor = self.connection.cursor() - + for i, statement in enumerate(statements): # 跳过注释和空语句 - if statement.startswith('--') or not statement: + if statement.startswith("--") or not statement: continue - + try: - logger.info(f"执行第 {i+1}/{len(statements)} 条SQL语句...") + logger.info(f"执行第 {i + 1}/{len(statements)} 条SQL语句...") cursor.execute(statement) - + # 如果是SELECT语句,显示结果 - if statement.strip().upper().startswith('SELECT'): + if statement.strip().upper().startswith("SELECT"): results = cursor.fetchall() if results: logger.info(f"查询结果: {results}") - + except Exception as e: logger.error(f"执行SQL语句失败: {statement[:100]}...") logger.error(f"错误信息: {e}") # 继续执行其他语句 continue - + self.connection.commit() cursor.close() logger.info(f"成功执行SQL文件: {file_path}") return True - + except Exception as e: logger.error(f"执行SQL文件失败: {e}") if self.connection: self.connection.rollback() return False - + def check_tables_exist(self, tables: list) -> dict: """检查表是否存在""" results = {} cursor = self.connection.cursor() - + for table in tables: try: cursor.execute(f"SHOW TABLES LIKE '{table}'") @@ -117,10 +118,10 @@ class DatabaseSyncer: except Exception as e: logger.error(f"检查表 '{table}' 时出错: {e}") results[table] = False - + cursor.close() return results - + def get_table_count(self, table: str) -> int: """获取表的记录数""" try: @@ -134,57 +135,58 @@ class DatabaseSyncer: logger.error(f"获取表 '{table}' 记录数失败: {e}") return -1 + def main(): """主函数""" print("Lazer API 数据同步工具") print("=" * 50) - + # 数据库配置 db_config = { - 'host': input("数据库主机 [localhost]: ").strip() or 'localhost', - 'port': int(input("数据库端口 [3306]: ").strip() or '3306'), - 'user': input("数据库用户名: ").strip(), - 'password': input("数据库密码: ").strip(), - 'database': input("数据库名称: ").strip() + "host": input("数据库主机 [localhost]: ").strip() or "localhost", + "port": int(input("数据库端口 [3306]: ").strip() or "3306"), + "user": input("数据库用户名: ").strip(), + "password": input("数据库密码: ").strip(), + "database": input("数据库名称: ").strip(), } - + syncer = DatabaseSyncer(**db_config) - + try: # 连接数据库 syncer.connect() - + # 检查必要的原始表是否存在 - required_tables = ['users', 'stats'] + required_tables = ["users", "stats"] table_status = syncer.check_tables_exist(required_tables) - + missing_tables = [table for table, exists in table_status.items() if not exists] if missing_tables: logger.error(f"缺少必要的原始表: {missing_tables}") return - + # 显示原始表的记录数 for table in required_tables: count = syncer.get_table_count(table) logger.info(f"表 '{table}' 当前有 {count} 条记录") - + # 确认是否执行同步 print("\n准备执行数据同步...") print("这将会:") print("1. 创建 lazer 专用表结构 (如果不存在)") print("2. 从现有表同步数据到新表") print("3. 不会修改或删除现有数据") - + confirm = input("\n是否继续? (y/N): ").strip().lower() - if confirm != 'y': + if confirm != "y": print("操作已取消") return - + # 执行表结构创建 - migrations_dir = os.path.join(os.path.dirname(__file__), 'migrations') - + migrations_dir = os.path.join(os.path.dirname(__file__), "migrations") + print("\n步骤 1: 创建表结构...") - add_fields_sql = os.path.join(migrations_dir, 'add_missing_fields.sql') + add_fields_sql = os.path.join(migrations_dir, "add_missing_fields.sql") if os.path.exists(add_fields_sql): success = syncer.execute_sql_file(add_fields_sql) if not success: @@ -192,10 +194,10 @@ def main(): return else: logger.warning(f"表结构文件不存在: {add_fields_sql}") - + # 执行数据同步 print("\n步骤 2: 同步数据...") - sync_sql = os.path.join(migrations_dir, 'sync_legacy_data.sql') + sync_sql = os.path.join(migrations_dir, "sync_legacy_data.sql") if os.path.exists(sync_sql): success = syncer.execute_sql_file(sync_sql) if not success: @@ -204,24 +206,24 @@ def main(): else: logger.error(f"同步脚本不存在: {sync_sql}") return - + # 显示同步后的统计信息 print("\n步骤 3: 同步完成统计...") lazer_tables = [ - 'lazer_user_profiles', - 'lazer_user_countries', - 'lazer_user_statistics', - 'lazer_user_kudosu', - 'lazer_user_counts' + "lazer_user_profiles", + "lazer_user_countries", + "lazer_user_statistics", + "lazer_user_kudosu", + "lazer_user_counts", ] - + for table in lazer_tables: count = syncer.get_table_count(table) if count >= 0: logger.info(f"表 '{table}' 现在有 {count} 条记录") - + print("\n数据同步完成!") - + except KeyboardInterrupt: print("\n\n操作被用户中断") except Exception as e: @@ -229,5 +231,6 @@ def main(): finally: syncer.disconnect() + if __name__ == "__main__": main() diff --git a/test_api.py b/test_api.py index 2249af9..a5f3484 100644 --- a/test_api.py +++ b/test_api.py @@ -3,17 +3,22 @@ 测试 osu! API 模拟服务器的脚本 """ -import requests +from __future__ import annotations + import os + from dotenv import load_dotenv -import json +import requests # 加载 .env 文件 load_dotenv() -CLIENT_ID = os.environ.get('OSU_CLIENT_ID', '5') -CLIENT_SECRET = os.environ.get('OSU_CLIENT_SECRET', 'FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk') -API_URL = os.environ.get('OSU_API_URL', 'http://localhost:8000') +CLIENT_ID = os.environ.get("OSU_CLIENT_ID", "5") +CLIENT_SECRET = os.environ.get( + "OSU_CLIENT_SECRET", "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" +) +API_URL = os.environ.get("OSU_API_URL", "http://localhost:8000") + def test_server_health(): """测试服务器健康状态""" @@ -29,6 +34,7 @@ def test_server_health(): print(f"❌ 无法连接到服务器: {e}") return False + def authenticate(username: str, password: str): """通过 OAuth 密码流进行身份验证并返回令牌字典""" url = f"{API_URL}/oauth/token" @@ -40,7 +46,7 @@ def authenticate(username: str, password: str): "client_secret": CLIENT_SECRET, "scope": "*", } - + try: response = requests.post(url, data=data) if response.status_code == 200: @@ -54,6 +60,7 @@ def authenticate(username: str, password: str): print(f"❌ 身份验证请求失败: {e}") return None + def refresh_token(refresh_token: str): """刷新 OAuth 令牌""" url = f"{API_URL}/oauth/token" @@ -64,7 +71,7 @@ def refresh_token(refresh_token: str): "client_secret": CLIENT_SECRET, "scope": "*", } - + try: response = requests.post(url, data=data) if response.status_code == 200: @@ -78,11 +85,12 @@ def refresh_token(refresh_token: str): print(f"❌ 令牌刷新请求失败: {e}") return None + def get_current_user(access_token: str, ruleset: str = "osu"): """获取认证用户的数据""" url = f"{API_URL}/api/v2/me/{ruleset}" headers = {"Authorization": f"Bearer {access_token}"} - + try: response = requests.get(url, headers=headers) if response.status_code == 200: @@ -96,38 +104,40 @@ def get_current_user(access_token: str, ruleset: str = "osu"): print(f"❌ 获取用户数据请求失败: {e}") return None + def main(): """主测试函数""" print("=== osu! API 模拟服务器测试 ===\n") - + # 1. 测试服务器健康状态 print("1. 检查服务器状态...") if not test_server_health(): print("请确保服务器正在运行: uvicorn main:app --reload") return - + print() - + # 2. 获取用户凭据 print("2. 用户身份验证...") username = input("请输入用户名 (默认: Googujiang): ").strip() or "Googujiang" - + import getpass + password = getpass.getpass("请输入密码 (默认: password123): ") or "password123" - + # 3. 身份验证 print(f"\n3. 正在验证用户 '{username}'...") token_data = authenticate(username, password) if not token_data: print("身份验证失败,请检查用户名和密码") return - + print(f"访问令牌: {token_data['access_token'][:50]}...") print(f"刷新令牌: {token_data['refresh_token'][:30]}...") print(f"令牌有效期: {token_data['expires_in']} 秒") - + # 4. 获取用户数据 - print(f"\n4. 获取用户数据...") + print("\n4. 获取用户数据...") for ruleset in ["osu", "taiko", "fruits", "mania"]: print(f"\n--- {ruleset.upper()} 模式 ---") user_data = get_current_user(token_data["access_token"], ruleset) @@ -138,20 +148,21 @@ def main(): print(f"PP: {user_data['statistics']['pp']}") print(f"游戏次数: {user_data['statistics']['play_count']}") print(f"命中精度: {user_data['statistics']['hit_accuracy']:.2f}%") - + # 5. 测试令牌刷新 - print(f"\n5. 测试令牌刷新...") + print("\n5. 测试令牌刷新...") new_token_data = refresh_token(token_data["refresh_token"]) if new_token_data: print(f"新访问令牌: {new_token_data['access_token'][:50]}...") - + # 使用新令牌获取用户数据 print("\n6. 使用新令牌获取用户数据...") user_data = get_current_user(new_token_data["access_token"]) if user_data: print(f"✅ 新令牌有效,用户: {user_data['username']}") - + print("\n=== 测试完成 ===") + if __name__ == "__main__": main() diff --git a/test_lazer.py b/test_lazer.py index 8053116..8bdae16 100644 --- a/test_lazer.py +++ b/test_lazer.py @@ -4,105 +4,113 @@ Lazer API 系统测试脚本 验证新的 lazer 表支持是否正常工作 """ -import sys +from __future__ import annotations + import os +import sys + sys.path.append(os.path.dirname(os.path.dirname(__file__))) -from sqlalchemy.orm import Session +from app.database import User from app.dependencies import get_db -from app.database import User, LazerUserProfile, LazerUserStatistics, LazerUserCountry -from app.auth import authenticate_user from app.utils import convert_db_user_to_api_user + def test_lazer_tables(): """测试 lazer 表的基本功能""" print("测试 Lazer API 表支持...") - + # 获取数据库会话 db_gen = get_db() db = next(db_gen) - + try: # 测试查询用户 user = db.query(User).first() if not user: print("❌ 没有找到用户,请先同步数据") return False - + print(f"✓ 找到用户: {user.name} (ID: {user.id})") - + # 测试 lazer 资料 if user.lazer_profile: print(f"✓ 用户有 lazer 资料: 支持者={user.lazer_profile.is_supporter}") else: print("⚠ 用户没有 lazer 资料,将使用默认值") - + # 测试 lazer 统计 osu_stats = None for stat in user.lazer_statistics: - if stat.mode == 'osu': + if stat.mode == "osu": osu_stats = stat break - + if osu_stats: - print(f"✓ 用户有 osu! 统计: PP={osu_stats.pp}, 游戏次数={osu_stats.play_count}") + print( + f"✓ 用户有 osu! 统计: PP={osu_stats.pp}, " + f"游戏次数={osu_stats.play_count}" + ) else: print("⚠ 用户没有 osu! 统计,将使用默认值") - + # 测试转换为 API 格式 api_user = convert_db_user_to_api_user(user, "osu", db) - print(f"✓ 成功转换为 API 用户格式") + print("✓ 成功转换为 API 用户格式") print(f" - 用户名: {api_user.username}") print(f" - 国家: {api_user.country_code}") print(f" - PP: {api_user.statistics.pp}") print(f" - 是否支持者: {api_user.is_supporter}") - + return True - + except Exception as e: print(f"❌ 测试失败: {e}") import traceback + traceback.print_exc() return False finally: db.close() + def test_authentication(): """测试认证功能""" print("\n测试认证功能...") - + db_gen = get_db() db = next(db_gen) - + try: # 尝试认证第一个用户 user = db.query(User).first() if not user: print("❌ 没有用户进行认证测试") return False - + print(f"✓ 测试用户: {user.name}") print("⚠ 注意: 实际密码认证需要正确的密码") - + return True - + except Exception as e: print(f"❌ 认证测试失败: {e}") return False finally: db.close() + def main(): """主测试函数""" print("Lazer API 系统测试") print("=" * 40) - + # 测试表连接 success1 = test_lazer_tables() - + # 测试认证 success2 = test_authentication() - + print("\n" + "=" * 40) if success1 and success2: print("🎉 所有测试通过!") @@ -116,5 +124,6 @@ def main(): print("2. 是否已运行数据同步脚本") print("3. lazer 表是否正确创建") + if __name__ == "__main__": main() diff --git a/test_password.py b/test_password.py index 20dcb7f..c0aa3cd 100644 --- a/test_password.py +++ b/test_password.py @@ -3,49 +3,53 @@ 测试密码哈希和验证逻辑 """ +from __future__ import annotations + import hashlib -import bcrypt -from app.auth import get_password_hash, verify_password_legacy, bcrypt_cache + +from app.auth import bcrypt_cache, get_password_hash, verify_password_legacy + def test_password_logic(): """测试密码逻辑""" print("=== 测试密码哈希和验证逻辑 ===\n") - + # 测试密码 password = "password123" print(f"原始密码: {password}") - + # 1. 生成哈希 print("\n1. 生成密码哈希...") hashed = get_password_hash(password) print(f"bcrypt 哈希: {hashed}") - + # 2. 验证密码 print("\n2. 验证密码...") is_valid = verify_password_legacy(password, hashed) print(f"验证结果: {'✅ 成功' if is_valid else '❌ 失败'}") - + # 3. 测试错误密码 print("\n3. 测试错误密码...") wrong_password = "wrongpassword" is_valid_wrong = verify_password_legacy(wrong_password, hashed) print(f"错误密码验证结果: {'❌ 不应该成功' if is_valid_wrong else '✅ 正确拒绝'}") - + # 4. 测试缓存 - print(f"\n4. 缓存状态:") + print("\n4. 缓存状态:") print(f"缓存中的条目数: {len(bcrypt_cache)}") if hashed in bcrypt_cache: print(f"缓存的 MD5: {bcrypt_cache[hashed]}") expected_md5 = hashlib.md5(password.encode()).hexdigest().encode() print(f"期望的 MD5: {expected_md5}") print(f"缓存匹配: {'✅' if bcrypt_cache[hashed] == expected_md5 else '❌'}") - + # 5. 再次验证(应该使用缓存) print("\n5. 再次验证(使用缓存)...") is_valid_cached = verify_password_legacy(password, hashed) print(f"缓存验证结果: {'✅ 成功' if is_valid_cached else '❌ 失败'}") - + print("\n=== 测试完成 ===") + if __name__ == "__main__": test_password_logic() diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..934e0b6 --- /dev/null +++ b/uv.lock @@ -0,0 +1,964 @@ +version = 1 +revision = 2 +requires-python = ">=3.11" + +[[package]] +name = "alembic" +version = "1.16.4" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "mako" }, + { name = "sqlalchemy" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/83/52/72e791b75c6b1efa803e491f7cbab78e963695e76d4ada05385252927e76/alembic-1.16.4.tar.gz", hash = "sha256:efab6ada0dd0fae2c92060800e0bf5c1dc26af15a10e02fb4babff164b4725e2", size = 1968161, upload-time = "2025-07-10T16:17:20.192Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c2/62/96b5217b742805236614f05904541000f55422a6060a90d7fd4ce26c172d/alembic-1.16.4-py3-none-any.whl", hash = "sha256:b05e51e8e82efc1abd14ba2af6392897e145930c3e0a2faf2b0da2f7f7fd660d", size = 247026, upload-time = "2025-07-10T16:17:21.845Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.9.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + +[[package]] +name = "bcrypt" +version = "4.3.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/bb/5d/6d7433e0f3cd46ce0b43cd65e1db465ea024dbb8216fb2404e919c2ad77b/bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18", size = 25697, upload-time = "2025-02-28T01:24:09.174Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/bf/2c/3d44e853d1fe969d229bd58d39ae6902b3d924af0e2b5a60d17d4b809ded/bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281", size = 483719, upload-time = "2025-02-28T01:22:34.539Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a1/e2/58ff6e2a22eca2e2cff5370ae56dba29d70b1ea6fc08ee9115c3ae367795/bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb", size = 272001, upload-time = "2025-02-28T01:22:38.078Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/37/1f/c55ed8dbe994b1d088309e366749633c9eb90d139af3c0a50c102ba68a1a/bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180", size = 277451, upload-time = "2025-02-28T01:22:40.787Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d7/1c/794feb2ecf22fe73dcfb697ea7057f632061faceb7dcf0f155f3443b4d79/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f", size = 272792, upload-time = "2025-02-28T01:22:43.144Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/13/b7/0b289506a3f3598c2ae2bdfa0ea66969812ed200264e3f61df77753eee6d/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09", size = 289752, upload-time = "2025-02-28T01:22:45.56Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/dc/24/d0fb023788afe9e83cc118895a9f6c57e1044e7e1672f045e46733421fe6/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d", size = 277762, upload-time = "2025-02-28T01:22:47.023Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e4/38/cde58089492e55ac4ef6c49fea7027600c84fd23f7520c62118c03b4625e/bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd", size = 272384, upload-time = "2025-02-28T01:22:49.221Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/de/6a/d5026520843490cfc8135d03012a413e4532a400e471e6188b01b2de853f/bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af", size = 277329, upload-time = "2025-02-28T01:22:51.603Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b3/a3/4fc5255e60486466c389e28c12579d2829b28a527360e9430b4041df4cf9/bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231", size = 305241, upload-time = "2025-02-28T01:22:53.283Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c7/15/2b37bc07d6ce27cc94e5b10fd5058900eb8fb11642300e932c8c82e25c4a/bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c", size = 309617, upload-time = "2025-02-28T01:22:55.461Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5f/1f/99f65edb09e6c935232ba0430c8c13bb98cb3194b6d636e61d93fe60ac59/bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f", size = 335751, upload-time = "2025-02-28T01:22:57.81Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/00/1b/b324030c706711c99769988fcb694b3cb23f247ad39a7823a78e361bdbb8/bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d", size = 355965, upload-time = "2025-02-28T01:22:59.181Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/aa/dd/20372a0579dd915dfc3b1cd4943b3bca431866fcb1dfdfd7518c3caddea6/bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4", size = 155316, upload-time = "2025-02-28T01:23:00.763Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6d/52/45d969fcff6b5577c2bf17098dc36269b4c02197d551371c023130c0f890/bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669", size = 147752, upload-time = "2025-02-28T01:23:02.908Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/11/22/5ada0b9af72b60cbc4c9a399fdde4af0feaa609d27eb0adc61607997a3fa/bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d", size = 498019, upload-time = "2025-02-28T01:23:05.838Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b8/8c/252a1edc598dc1ce57905be173328eda073083826955ee3c97c7ff5ba584/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b", size = 279174, upload-time = "2025-02-28T01:23:07.274Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/29/5b/4547d5c49b85f0337c13929f2ccbe08b7283069eea3550a457914fc078aa/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e", size = 283870, upload-time = "2025-02-28T01:23:09.151Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/be/21/7dbaf3fa1745cb63f776bb046e481fbababd7d344c5324eab47f5ca92dd2/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59", size = 279601, upload-time = "2025-02-28T01:23:11.461Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6d/64/e042fc8262e971347d9230d9abbe70d68b0a549acd8611c83cebd3eaec67/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753", size = 297660, upload-time = "2025-02-28T01:23:12.989Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/50/b8/6294eb84a3fef3b67c69b4470fcdd5326676806bf2519cda79331ab3c3a9/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761", size = 284083, upload-time = "2025-02-28T01:23:14.5Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/62/e6/baff635a4f2c42e8788fe1b1633911c38551ecca9a749d1052d296329da6/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb", size = 279237, upload-time = "2025-02-28T01:23:16.686Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/39/48/46f623f1b0c7dc2e5de0b8af5e6f5ac4cc26408ac33f3d424e5ad8da4a90/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d", size = 283737, upload-time = "2025-02-28T01:23:18.897Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/49/8b/70671c3ce9c0fca4a6cc3cc6ccbaa7e948875a2e62cbd146e04a4011899c/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f", size = 312741, upload-time = "2025-02-28T01:23:21.041Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/27/fb/910d3a1caa2d249b6040a5caf9f9866c52114d51523ac2fb47578a27faee/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732", size = 316472, upload-time = "2025-02-28T01:23:23.183Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/dc/cf/7cf3a05b66ce466cfb575dbbda39718d45a609daa78500f57fa9f36fa3c0/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef", size = 343606, upload-time = "2025-02-28T01:23:25.361Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e3/b8/e970ecc6d7e355c0d892b7f733480f4aa8509f99b33e71550242cf0b7e63/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304", size = 362867, upload-time = "2025-02-28T01:23:26.875Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a9/97/8d3118efd8354c555a3422d544163f40d9f236be5b96c714086463f11699/bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51", size = 160589, upload-time = "2025-02-28T01:23:28.381Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/29/07/416f0b99f7f3997c69815365babbc2e8754181a4b1899d921b3c7d5b6f12/bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62", size = 152794, upload-time = "2025-02-28T01:23:30.187Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6e/c1/3fa0e9e4e0bfd3fd77eb8b52ec198fd6e1fd7e9402052e43f23483f956dd/bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3", size = 498969, upload-time = "2025-02-28T01:23:31.945Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ce/d4/755ce19b6743394787fbd7dff6bf271b27ee9b5912a97242e3caf125885b/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24", size = 279158, upload-time = "2025-02-28T01:23:34.161Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9b/5d/805ef1a749c965c46b28285dfb5cd272a7ed9fa971f970435a5133250182/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef", size = 284285, upload-time = "2025-02-28T01:23:35.765Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ab/2b/698580547a4a4988e415721b71eb45e80c879f0fb04a62da131f45987b96/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b", size = 279583, upload-time = "2025-02-28T01:23:38.021Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f2/87/62e1e426418204db520f955ffd06f1efd389feca893dad7095bf35612eec/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676", size = 297896, upload-time = "2025-02-28T01:23:39.575Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cb/c6/8fedca4c2ada1b6e889c52d2943b2f968d3427e5d65f595620ec4c06fa2f/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1", size = 284492, upload-time = "2025-02-28T01:23:40.901Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/4d/4d/c43332dcaaddb7710a8ff5269fcccba97ed3c85987ddaa808db084267b9a/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe", size = 279213, upload-time = "2025-02-28T01:23:42.653Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/dc/7f/1e36379e169a7df3a14a1c160a49b7b918600a6008de43ff20d479e6f4b5/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0", size = 284162, upload-time = "2025-02-28T01:23:43.964Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1c/0a/644b2731194b0d7646f3210dc4d80c7fee3ecb3a1f791a6e0ae6bb8684e3/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f", size = 312856, upload-time = "2025-02-28T01:23:46.011Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/dc/62/2a871837c0bb6ab0c9a88bf54de0fc021a6a08832d4ea313ed92a669d437/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23", size = 316726, upload-time = "2025-02-28T01:23:47.575Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0c/a1/9898ea3faac0b156d457fd73a3cb9c2855c6fd063e44b8522925cdd8ce46/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe", size = 343664, upload-time = "2025-02-28T01:23:49.059Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/40/f2/71b4ed65ce38982ecdda0ff20c3ad1b15e71949c78b2c053df53629ce940/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505", size = 363128, upload-time = "2025-02-28T01:23:50.399Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/11/99/12f6a58eca6dea4be992d6c681b7ec9410a1d9f5cf368c61437e31daa879/bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a", size = 160598, upload-time = "2025-02-28T01:23:51.775Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a9/cf/45fb5261ece3e6b9817d3d82b2f343a505fd58674a92577923bc500bd1aa/bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b", size = 152799, upload-time = "2025-02-28T01:23:53.139Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/4c/b1/1289e21d710496b88340369137cc4c5f6ee036401190ea116a7b4ae6d32a/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a", size = 275103, upload-time = "2025-02-28T01:24:00.764Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/94/41/19be9fe17e4ffc5d10b7b67f10e459fc4eee6ffe9056a88de511920cfd8d/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce", size = 280513, upload-time = "2025-02-28T01:24:02.243Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/aa/73/05687a9ef89edebdd8ad7474c16d8af685eb4591c3c38300bb6aad4f0076/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8", size = 274685, upload-time = "2025-02-28T01:24:04.512Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/63/13/47bba97924ebe86a62ef83dc75b7c8a881d53c535f83e2c54c4bd701e05c/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938", size = 280110, upload-time = "2025-02-28T01:24:05.896Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, +] + +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "45.0.5" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/95/1e/49527ac611af559665f71cbb8f92b332b5ec9c6fbc4e88b0f8e92f5e85df/cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a", size = 744903, upload-time = "2025-07-02T13:06:25.941Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f0/fb/09e28bc0c46d2c547085e60897fea96310574c70fb21cd58a730a45f3403/cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8", size = 7043092, upload-time = "2025-07-02T13:05:01.514Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b1/05/2194432935e29b91fb649f6149c1a4f9e6d3d9fc880919f4ad1bcc22641e/cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d", size = 4205926, upload-time = "2025-07-02T13:05:04.741Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/07/8b/9ef5da82350175e32de245646b1884fc01124f53eb31164c77f95a08d682/cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5", size = 4429235, upload-time = "2025-07-02T13:05:07.084Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7c/e1/c809f398adde1994ee53438912192d92a1d0fc0f2d7582659d9ef4c28b0c/cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57", size = 4209785, upload-time = "2025-07-02T13:05:09.321Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d0/8b/07eb6bd5acff58406c5e806eff34a124936f41a4fb52909ffa4d00815f8c/cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0", size = 3893050, upload-time = "2025-07-02T13:05:11.069Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ec/ef/3333295ed58d900a13c92806b67e62f27876845a9a908c939f040887cca9/cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d", size = 4457379, upload-time = "2025-07-02T13:05:13.32Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d9/9d/44080674dee514dbb82b21d6fa5d1055368f208304e2ab1828d85c9de8f4/cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9", size = 4209355, upload-time = "2025-07-02T13:05:15.017Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c9/d8/0749f7d39f53f8258e5c18a93131919ac465ee1f9dccaf1b3f420235e0b5/cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27", size = 4456087, upload-time = "2025-07-02T13:05:16.945Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/09/d7/92acac187387bf08902b0bf0699816f08553927bdd6ba3654da0010289b4/cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e", size = 4332873, upload-time = "2025-07-02T13:05:18.743Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/03/c2/840e0710da5106a7c3d4153c7215b2736151bba60bf4491bdb421df5056d/cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174", size = 4564651, upload-time = "2025-07-02T13:05:21.382Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2e/92/cc723dd6d71e9747a887b94eb3827825c6c24b9e6ce2bb33b847d31d5eaa/cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9", size = 2929050, upload-time = "2025-07-02T13:05:23.39Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1f/10/197da38a5911a48dd5389c043de4aec4b3c94cb836299b01253940788d78/cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63", size = 3403224, upload-time = "2025-07-02T13:05:25.202Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/2b/160ce8c2765e7a481ce57d55eba1546148583e7b6f85514472b1d151711d/cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8", size = 7017143, upload-time = "2025-07-02T13:05:27.229Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c2/e7/2187be2f871c0221a81f55ee3105d3cf3e273c0a0853651d7011eada0d7e/cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd", size = 4197780, upload-time = "2025-07-02T13:05:29.299Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b9/cf/84210c447c06104e6be9122661159ad4ce7a8190011669afceeaea150524/cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e", size = 4420091, upload-time = "2025-07-02T13:05:31.221Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3e/6a/cb8b5c8bb82fafffa23aeff8d3a39822593cee6e2f16c5ca5c2ecca344f7/cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0", size = 4198711, upload-time = "2025-07-02T13:05:33.062Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/04/f7/36d2d69df69c94cbb2473871926daf0f01ad8e00fe3986ac3c1e8c4ca4b3/cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135", size = 3883299, upload-time = "2025-07-02T13:05:34.94Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/82/c7/f0ea40f016de72f81288e9fe8d1f6748036cb5ba6118774317a3ffc6022d/cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7", size = 4450558, upload-time = "2025-07-02T13:05:37.288Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/06/ae/94b504dc1a3cdf642d710407c62e86296f7da9e66f27ab12a1ee6fdf005b/cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42", size = 4198020, upload-time = "2025-07-02T13:05:39.102Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/05/2b/aaf0adb845d5dabb43480f18f7ca72e94f92c280aa983ddbd0bcd6ecd037/cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492", size = 4449759, upload-time = "2025-07-02T13:05:41.398Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/91/e4/f17e02066de63e0100a3a01b56f8f1016973a1d67551beaf585157a86b3f/cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0", size = 4319991, upload-time = "2025-07-02T13:05:43.64Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f2/2e/e2dbd629481b499b14516eed933f3276eb3239f7cee2dcfa4ee6b44d4711/cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a", size = 4554189, upload-time = "2025-07-02T13:05:46.045Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f8/ea/a78a0c38f4c8736287b71c2ea3799d173d5ce778c7d6e3c163a95a05ad2a/cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f", size = 2911769, upload-time = "2025-07-02T13:05:48.329Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/79/b3/28ac139109d9005ad3f6b6f8976ffede6706a6478e21c889ce36c840918e/cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97", size = 3390016, upload-time = "2025-07-02T13:05:50.811Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c0/71/9bdbcfd58d6ff5084687fe722c58ac718ebedbc98b9f8f93781354e6d286/cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e", size = 3587878, upload-time = "2025-07-02T13:06:06.339Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f0/63/83516cfb87f4a8756eaa4203f93b283fda23d210fc14e1e594bd5f20edb6/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6", size = 4152447, upload-time = "2025-07-02T13:06:08.345Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/22/11/d2823d2a5a0bd5802b3565437add16f5c8ce1f0778bf3822f89ad2740a38/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18", size = 4386778, upload-time = "2025-07-02T13:06:10.263Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5f/38/6bf177ca6bce4fe14704ab3e93627c5b0ca05242261a2e43ef3168472540/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463", size = 4151627, upload-time = "2025-07-02T13:06:13.097Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/38/6a/69fc67e5266bff68a91bcb81dff8fb0aba4d79a78521a08812048913e16f/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1", size = 4385593, upload-time = "2025-07-02T13:06:15.689Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f6/34/31a1604c9a9ade0fdab61eb48570e09a796f4d9836121266447b0eaf7feb/cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f", size = 3331106, upload-time = "2025-07-02T13:06:18.058Z" }, +] + +[[package]] +name = "dnspython" +version = "2.7.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, +] + +[[package]] +name = "ecdsa" +version = "0.19.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/c0/1f/924e3caae75f471eae4b26bd13b698f6af2c44279f67af317439c2f4c46a/ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61", size = 201793, upload-time = "2025-03-13T11:52:43.25Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cb/a3/460c57f094a4a165c84a1341c373b0a4f5ec6ac244b998d5021aade89b77/ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3", size = 150607, upload-time = "2025-03-13T11:52:41.757Z" }, +] + +[[package]] +name = "email-validator" +version = "2.2.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, +] + +[[package]] +name = "fastapi" +version = "0.116.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, +] + +[[package]] +name = "greenlet" +version = "3.2.3" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fc/2e/d4fcb2978f826358b673f779f78fa8a32ee37df11920dc2bb5589cbeecef/greenlet-3.2.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822", size = 270219, upload-time = "2025-06-05T16:10:10.414Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/16/24/929f853e0202130e4fe163bc1d05a671ce8dcd604f790e14896adac43a52/greenlet-3.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83", size = 630383, upload-time = "2025-06-05T16:38:51.785Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d1/b2/0320715eb61ae70c25ceca2f1d5ae620477d246692d9cc284c13242ec31c/greenlet-3.2.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf", size = 642422, upload-time = "2025-06-05T16:41:35.259Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/bd/49/445fd1a210f4747fedf77615d941444349c6a3a4a1135bba9701337cd966/greenlet-3.2.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b", size = 638375, upload-time = "2025-06-05T16:48:18.235Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7e/c8/ca19760cf6eae75fa8dc32b487e963d863b3ee04a7637da77b616703bc37/greenlet-3.2.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147", size = 637627, upload-time = "2025-06-05T16:13:02.858Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/65/89/77acf9e3da38e9bcfca881e43b02ed467c1dedc387021fc4d9bd9928afb8/greenlet-3.2.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5", size = 585502, upload-time = "2025-06-05T16:12:49.642Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/97/c6/ae244d7c95b23b7130136e07a9cc5aadd60d59b5951180dc7dc7e8edaba7/greenlet-3.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc", size = 1114498, upload-time = "2025-06-05T16:36:46.598Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/89/5f/b16dec0cbfd3070658e0d744487919740c6d45eb90946f6787689a7efbce/greenlet-3.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:751261fc5ad7b6705f5f76726567375bb2104a059454e0226e1eef6c756748ba", size = 1139977, upload-time = "2025-06-05T16:12:38.262Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/66/77/d48fb441b5a71125bcac042fc5b1494c806ccb9a1432ecaa421e72157f77/greenlet-3.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:83a8761c75312361aa2b5b903b79da97f13f556164a7dd2d5448655425bd4c34", size = 297017, upload-time = "2025-06-05T16:25:05.225Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f3/94/ad0d435f7c48debe960c53b8f60fb41c2026b1d0fa4a99a1cb17c3461e09/greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d", size = 271992, upload-time = "2025-06-05T16:11:23.467Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/93/5d/7c27cf4d003d6e77749d299c7c8f5fd50b4f251647b5c2e97e1f20da0ab5/greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b", size = 638820, upload-time = "2025-06-05T16:38:52.882Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c6/7e/807e1e9be07a125bb4c169144937910bf59b9d2f6d931578e57f0bce0ae2/greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d", size = 653046, upload-time = "2025-06-05T16:41:36.343Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9d/ab/158c1a4ea1068bdbc78dba5a3de57e4c7aeb4e7fa034320ea94c688bfb61/greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264", size = 647701, upload-time = "2025-06-05T16:48:19.604Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cc/0d/93729068259b550d6a0288da4ff72b86ed05626eaf1eb7c0d3466a2571de/greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688", size = 649747, upload-time = "2025-06-05T16:13:04.628Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f6/f6/c82ac1851c60851302d8581680573245c8fc300253fc1ff741ae74a6c24d/greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb", size = 605461, upload-time = "2025-06-05T16:12:50.792Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/98/82/d022cf25ca39cf1200650fc58c52af32c90f80479c25d1cbf57980ec3065/greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c", size = 1121190, upload-time = "2025-06-05T16:36:48.59Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f5/e1/25297f70717abe8104c20ecf7af0a5b82d2f5a980eb1ac79f65654799f9f/greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163", size = 1149055, upload-time = "2025-06-05T16:12:40.457Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1f/8f/8f9e56c5e82eb2c26e8cde787962e66494312dc8cb261c460e1f3a9c88bc/greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849", size = 297817, upload-time = "2025-06-05T16:29:49.244Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b1/cf/f5c0b23309070ae93de75c90d29300751a5aacefc0a3ed1b1d8edb28f08b/greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad", size = 270732, upload-time = "2025-06-05T16:10:08.26Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/48/ae/91a957ba60482d3fecf9be49bc3948f341d706b52ddb9d83a70d42abd498/greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef", size = 639033, upload-time = "2025-06-05T16:38:53.983Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6f/df/20ffa66dd5a7a7beffa6451bdb7400d66251374ab40b99981478c69a67a8/greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3", size = 652999, upload-time = "2025-06-05T16:41:37.89Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/51/b4/ebb2c8cb41e521f1d72bf0465f2f9a2fd803f674a88db228887e6847077e/greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95", size = 647368, upload-time = "2025-06-05T16:48:21.467Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8e/6a/1e1b5aa10dced4ae876a322155705257748108b7fd2e4fae3f2a091fe81a/greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb", size = 650037, upload-time = "2025-06-05T16:13:06.402Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/26/f2/ad51331a157c7015c675702e2d5230c243695c788f8f75feba1af32b3617/greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b", size = 608402, upload-time = "2025-06-05T16:12:51.91Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/26/bc/862bd2083e6b3aff23300900a956f4ea9a4059de337f5c8734346b9b34fc/greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0", size = 1119577, upload-time = "2025-06-05T16:36:49.787Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/86/94/1fc0cc068cfde885170e01de40a619b00eaa8f2916bf3541744730ffb4c3/greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36", size = 1147121, upload-time = "2025-06-05T16:12:42.527Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/27/1a/199f9587e8cb08a0658f9c30f3799244307614148ffe8b1e3aa22f324dea/greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3", size = 297603, upload-time = "2025-06-05T16:20:12.651Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d8/ca/accd7aa5280eb92b70ed9e8f7fd79dc50a2c21d8c73b9a0856f5b564e222/greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86", size = 271479, upload-time = "2025-06-05T16:10:47.525Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/55/71/01ed9895d9eb49223280ecc98a557585edfa56b3d0e965b9fa9f7f06b6d9/greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97", size = 683952, upload-time = "2025-06-05T16:38:55.125Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ea/61/638c4bdf460c3c678a0a1ef4c200f347dff80719597e53b5edb2fb27ab54/greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728", size = 696917, upload-time = "2025-06-05T16:41:38.959Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/22/cc/0bd1a7eb759d1f3e3cc2d1bc0f0b487ad3cc9f34d74da4b80f226fde4ec3/greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a", size = 692443, upload-time = "2025-06-05T16:48:23.113Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/67/10/b2a4b63d3f08362662e89c103f7fe28894a51ae0bc890fabf37d1d780e52/greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892", size = 692995, upload-time = "2025-06-05T16:13:07.972Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5a/c6/ad82f148a4e3ce9564056453a71529732baf5448ad53fc323e37efe34f66/greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141", size = 655320, upload-time = "2025-06-05T16:12:53.453Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5c/4f/aab73ecaa6b3086a4c89863d94cf26fa84cbff63f52ce9bc4342b3087a06/greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a", size = 301236, upload-time = "2025-06-05T16:15:20.111Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httptools" +version = "0.6.4" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "mako" +version = "1.3.10" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "osu-lazer-api" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "alembic" }, + { name = "bcrypt" }, + { name = "cryptography" }, + { name = "fastapi" }, + { name = "passlib", extra = ["bcrypt"] }, + { name = "pydantic", extra = ["email"] }, + { name = "pymysql" }, + { name = "python-dotenv" }, + { name = "python-jose", extra = ["cryptography"] }, + { name = "python-multipart" }, + { name = "redis" }, + { name = "sqlalchemy" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[package.dev-dependencies] +dev = [ + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "alembic", specifier = ">=1.12.1" }, + { name = "bcrypt", specifier = ">=4.1.2" }, + { name = "cryptography", specifier = ">=41.0.7" }, + { name = "fastapi", specifier = ">=0.104.1" }, + { name = "passlib", extras = ["bcrypt"], specifier = ">=1.7.4" }, + { name = "pydantic", extras = ["email"], specifier = ">=2.5.0" }, + { name = "pymysql", specifier = ">=1.1.0" }, + { name = "python-dotenv", specifier = ">=1.0.0" }, + { name = "python-jose", extras = ["cryptography"], specifier = ">=3.3.0" }, + { name = "python-multipart", specifier = ">=0.0.6" }, + { name = "redis", specifier = ">=5.0.1" }, + { name = "sqlalchemy", specifier = ">=2.0.23" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.24.0" }, +] + +[package.metadata.requires-dev] +dev = [{ name = "ruff", specifier = ">=0.12.4" }] + +[[package]] +name = "passlib" +version = "1.7.4" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/b6/06/9da9ee59a67fae7761aab3ccc84fa4f3f33f125b370f1ccdb915bf967c11/passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04", size = 689844, upload-time = "2020-10-08T19:00:52.121Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", size = 525554, upload-time = "2020-10-08T19:00:49.856Z" }, +] + +[package.optional-dependencies] +bcrypt = [ + { name = "bcrypt" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, +] + +[[package]] +name = "pymysql" +version = "1.1.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/b3/8f/ce59b5e5ed4ce8512f879ff1fa5ab699d211ae2495f1adaa5fbba2a1eada/pymysql-1.1.1.tar.gz", hash = "sha256:e127611aaf2b417403c60bf4dc570124aeb4a57f5f37b8e95ae399a42f904cd0", size = 47678, upload-time = "2024-05-21T11:03:43.722Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0c/94/e4181a1f6286f545507528c78016e00065ea913276888db2262507693ce5/PyMySQL-1.1.1-py3-none-any.whl", hash = "sha256:4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c", size = 44972, upload-time = "2024-05-21T11:03:41.216Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-jose" +version = "3.5.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "ecdsa" }, + { name = "pyasn1" }, + { name = "rsa" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" }, +] + +[package.optional-dependencies] +cryptography = [ + { name = "cryptography" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "redis" +version = "6.2.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/ea/9a/0551e01ba52b944f97480721656578c8a7c46b51b99d66814f85fe3a4f3e/redis-6.2.0.tar.gz", hash = "sha256:e821f129b75dde6cb99dd35e5c76e8c49512a5a0d8dfdc560b2fbd44b85ca977", size = 4639129, upload-time = "2025-05-28T05:01:18.91Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/13/67/e60968d3b0e077495a8fee89cf3f2373db98e528288a48f1ee44967f6e8c/redis-6.2.0-py3-none-any.whl", hash = "sha256:c8ddf316ee0aab65f04a11229e94a64b2618451dab7a67cb2f77eb799d872d5e", size = 278659, upload-time = "2025-05-28T05:01:16.955Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "ruff" +version = "0.12.4" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/9b/ce/8d7dbedede481245b489b769d27e2934730791a9a82765cb94566c6e6abd/ruff-0.12.4.tar.gz", hash = "sha256:13efa16df6c6eeb7d0f091abae50f58e9522f3843edb40d56ad52a5a4a4b6873", size = 5131435, upload-time = "2025-07-17T17:27:19.138Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ae/9f/517bc5f61bad205b7f36684ffa5415c013862dee02f55f38a217bdbe7aa4/ruff-0.12.4-py3-none-linux_armv6l.whl", hash = "sha256:cb0d261dac457ab939aeb247e804125a5d521b21adf27e721895b0d3f83a0d0a", size = 10188824, upload-time = "2025-07-17T17:26:31.412Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/28/83/691baae5a11fbbde91df01c565c650fd17b0eabed259e8b7563de17c6529/ruff-0.12.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:55c0f4ca9769408d9b9bac530c30d3e66490bd2beb2d3dae3e4128a1f05c7442", size = 10884521, upload-time = "2025-07-17T17:26:35.084Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d6/8d/756d780ff4076e6dd035d058fa220345f8c458391f7edfb1c10731eedc75/ruff-0.12.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a8224cc3722c9ad9044da7f89c4c1ec452aef2cfe3904365025dd2f51daeae0e", size = 10277653, upload-time = "2025-07-17T17:26:37.897Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8d/97/8eeee0f48ece153206dce730fc9e0e0ca54fd7f261bb3d99c0a4343a1892/ruff-0.12.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9949d01d64fa3672449a51ddb5d7548b33e130240ad418884ee6efa7a229586", size = 10485993, upload-time = "2025-07-17T17:26:40.68Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/49/b8/22a43d23a1f68df9b88f952616c8508ea6ce4ed4f15353b8168c48b2d7e7/ruff-0.12.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:be0593c69df9ad1465e8a2d10e3defd111fdb62dcd5be23ae2c06da77e8fcffb", size = 10022824, upload-time = "2025-07-17T17:26:43.564Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cd/70/37c234c220366993e8cffcbd6cadbf332bfc848cbd6f45b02bade17e0149/ruff-0.12.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7dea966bcb55d4ecc4cc3270bccb6f87a337326c9dcd3c07d5b97000dbff41c", size = 11524414, upload-time = "2025-07-17T17:26:46.219Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/14/77/c30f9964f481b5e0e29dd6a1fae1f769ac3fd468eb76fdd5661936edd262/ruff-0.12.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afcfa3ab5ab5dd0e1c39bf286d829e042a15e966b3726eea79528e2e24d8371a", size = 12419216, upload-time = "2025-07-17T17:26:48.883Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6e/79/af7fe0a4202dce4ef62c5e33fecbed07f0178f5b4dd9c0d2fcff5ab4a47c/ruff-0.12.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c057ce464b1413c926cdb203a0f858cd52f3e73dcb3270a3318d1630f6395bb3", size = 11976756, upload-time = "2025-07-17T17:26:51.754Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/09/d1/33fb1fc00e20a939c305dbe2f80df7c28ba9193f7a85470b982815a2dc6a/ruff-0.12.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e64b90d1122dc2713330350626b10d60818930819623abbb56535c6466cce045", size = 11020019, upload-time = "2025-07-17T17:26:54.265Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/64/f4/e3cd7f7bda646526f09693e2e02bd83d85fff8a8222c52cf9681c0d30843/ruff-0.12.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2abc48f3d9667fdc74022380b5c745873499ff827393a636f7a59da1515e7c57", size = 11277890, upload-time = "2025-07-17T17:26:56.914Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5e/d0/69a85fb8b94501ff1a4f95b7591505e8983f38823da6941eb5b6badb1e3a/ruff-0.12.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2b2449dc0c138d877d629bea151bee8c0ae3b8e9c43f5fcaafcd0c0d0726b184", size = 10348539, upload-time = "2025-07-17T17:26:59.381Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/16/a0/91372d1cb1678f7d42d4893b88c252b01ff1dffcad09ae0c51aa2542275f/ruff-0.12.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:56e45bb11f625db55f9b70477062e6a1a04d53628eda7784dce6e0f55fd549eb", size = 10009579, upload-time = "2025-07-17T17:27:02.462Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/23/1b/c4a833e3114d2cc0f677e58f1df6c3b20f62328dbfa710b87a1636a5e8eb/ruff-0.12.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:478fccdb82ca148a98a9ff43658944f7ab5ec41c3c49d77cd99d44da019371a1", size = 10942982, upload-time = "2025-07-17T17:27:05.343Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/ce/ce85e445cf0a5dd8842f2f0c6f0018eedb164a92bdf3eda51984ffd4d989/ruff-0.12.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0fc426bec2e4e5f4c4f182b9d2ce6a75c85ba9bcdbe5c6f2a74fcb8df437df4b", size = 11343331, upload-time = "2025-07-17T17:27:08.652Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/35/cf/441b7fc58368455233cfb5b77206c849b6dfb48b23de532adcc2e50ccc06/ruff-0.12.4-py3-none-win32.whl", hash = "sha256:4de27977827893cdfb1211d42d84bc180fceb7b72471104671c59be37041cf93", size = 10267904, upload-time = "2025-07-17T17:27:11.814Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ce/7e/20af4a0df5e1299e7368d5ea4350412226afb03d95507faae94c80f00afd/ruff-0.12.4-py3-none-win_amd64.whl", hash = "sha256:fe0b9e9eb23736b453143d72d2ceca5db323963330d5b7859d60d101147d461a", size = 11209038, upload-time = "2025-07-17T17:27:14.417Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/11/02/8857d0dfb8f44ef299a5dfd898f673edefb71e3b533b3b9d2db4c832dd13/ruff-0.12.4-py3-none-win_arm64.whl", hash = "sha256:0618ec4442a83ab545e5b71202a5c0ed7791e8471435b94e655b570a5031a98e", size = 10469336, upload-time = "2025-07-17T17:27:16.913Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.41" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/37/4e/b00e3ffae32b74b5180e15d2ab4040531ee1bef4c19755fe7926622dc958/sqlalchemy-2.0.41-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f", size = 2121232, upload-time = "2025-05-14T17:48:20.444Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ef/30/6547ebb10875302074a37e1970a5dce7985240665778cfdee2323709f749/sqlalchemy-2.0.41-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560", size = 2110897, upload-time = "2025-05-14T17:48:21.634Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9e/21/59df2b41b0f6c62da55cd64798232d7349a9378befa7f1bb18cf1dfd510a/sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f", size = 3273313, upload-time = "2025-05-14T17:51:56.205Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/62/e4/b9a7a0e5c6f79d49bcd6efb6e90d7536dc604dab64582a9dec220dab54b6/sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6", size = 3273807, upload-time = "2025-05-14T17:55:26.928Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/39/d8/79f2427251b44ddee18676c04eab038d043cff0e764d2d8bb08261d6135d/sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04", size = 3209632, upload-time = "2025-05-14T17:51:59.384Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d4/16/730a82dda30765f63e0454918c982fb7193f6b398b31d63c7c3bd3652ae5/sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582", size = 3233642, upload-time = "2025-05-14T17:55:29.901Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/04/61/c0d4607f7799efa8b8ea3c49b4621e861c8f5c41fd4b5b636c534fcb7d73/sqlalchemy-2.0.41-cp311-cp311-win32.whl", hash = "sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8", size = 2086475, upload-time = "2025-05-14T17:56:02.095Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9d/8e/8344f8ae1cb6a479d0741c02cd4f666925b2bf02e2468ddaf5ce44111f30/sqlalchemy-2.0.41-cp311-cp311-win_amd64.whl", hash = "sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504", size = 2110903, upload-time = "2025-05-14T17:56:03.499Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3e/2a/f1f4e068b371154740dd10fb81afb5240d5af4aa0087b88d8b308b5429c2/sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9", size = 2119645, upload-time = "2025-05-14T17:55:24.854Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9b/e8/c664a7e73d36fbfc4730f8cf2bf930444ea87270f2825efbe17bf808b998/sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1", size = 2107399, upload-time = "2025-05-14T17:55:28.097Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5c/78/8a9cf6c5e7135540cb682128d091d6afa1b9e48bd049b0d691bf54114f70/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70", size = 3293269, upload-time = "2025-05-14T17:50:38.227Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3c/35/f74add3978c20de6323fb11cb5162702670cc7a9420033befb43d8d5b7a4/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e", size = 3303364, upload-time = "2025-05-14T17:51:49.829Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6a/d4/c990f37f52c3f7748ebe98883e2a0f7d038108c2c5a82468d1ff3eec50b7/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078", size = 3229072, upload-time = "2025-05-14T17:50:39.774Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/15/69/cab11fecc7eb64bc561011be2bd03d065b762d87add52a4ca0aca2e12904/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae", size = 3268074, upload-time = "2025-05-14T17:51:51.736Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5c/ca/0c19ec16858585d37767b167fc9602593f98998a68a798450558239fb04a/sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6", size = 2084514, upload-time = "2025-05-14T17:55:49.915Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7f/23/4c2833d78ff3010a4e17f984c734f52b531a8c9060a50429c9d4b0211be6/sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0", size = 2111557, upload-time = "2025-05-14T17:55:51.349Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, +] + +[[package]] +name = "starlette" +version = "0.47.2" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/04/57/d062573f391d062710d4088fa1369428c38d51460ab6fedff920efef932e/starlette-0.47.2.tar.gz", hash = "sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8", size = 2583948, upload-time = "2025-07-20T17:31:58.522Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f7/1f/b876b1f83aef204198a42dc101613fefccb32258e5428b5f9259677864b4/starlette-0.47.2-py3-none-any.whl", hash = "sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b", size = 72984, upload-time = "2025-07-20T17:31:56.738Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.35.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.21.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.0" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8b/78/7401154b78ab484ccaaeef970dc2af0cb88b5ba8a1b415383da444cdd8d3/watchfiles-1.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c9649dfc57cc1f9835551deb17689e8d44666315f2e82d337b9f07bd76ae3aa2", size = 405751, upload-time = "2025-06-15T19:05:07.679Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/76/63/e6c3dbc1f78d001589b75e56a288c47723de28c580ad715eb116639152b5/watchfiles-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:406520216186b99374cdb58bc48e34bb74535adec160c8459894884c983a149c", size = 397313, upload-time = "2025-06-15T19:05:08.764Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6c/a2/8afa359ff52e99af1632f90cbf359da46184207e893a5f179301b0c8d6df/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45350fd1dc75cd68d3d72c47f5b513cb0578da716df5fba02fff31c69d5f2d", size = 450792, upload-time = "2025-06-15T19:05:09.869Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1d/bf/7446b401667f5c64972a57a0233be1104157fc3abf72c4ef2666c1bd09b2/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11ee4444250fcbeb47459a877e5e80ed994ce8e8d20283857fc128be1715dac7", size = 458196, upload-time = "2025-06-15T19:05:11.91Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/58/2f/501ddbdfa3fa874ea5597c77eeea3d413579c29af26c1091b08d0c792280/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bda8136e6a80bdea23e5e74e09df0362744d24ffb8cd59c4a95a6ce3d142f79c", size = 484788, upload-time = "2025-06-15T19:05:13.373Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/61/1e/9c18eb2eb5c953c96bc0e5f626f0e53cfef4bd19bd50d71d1a049c63a575/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b915daeb2d8c1f5cee4b970f2e2c988ce6514aace3c9296e58dd64dc9aa5d575", size = 597879, upload-time = "2025-06-15T19:05:14.725Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8b/6c/1467402e5185d89388b4486745af1e0325007af0017c3384cc786fff0542/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed8fc66786de8d0376f9f913c09e963c66e90ced9aa11997f93bdb30f7c872a8", size = 477447, upload-time = "2025-06-15T19:05:15.775Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2b/a1/ec0a606bde4853d6c4a578f9391eeb3684a9aea736a8eb217e3e00aa89a1/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe4371595edf78c41ef8ac8df20df3943e13defd0efcb732b2e393b5a8a7a71f", size = 453145, upload-time = "2025-06-15T19:05:17.17Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/90/b9/ef6f0c247a6a35d689fc970dc7f6734f9257451aefb30def5d100d6246a5/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b7c5f6fe273291f4d414d55b2c80d33c457b8a42677ad14b4b47ff025d0893e4", size = 626539, upload-time = "2025-06-15T19:05:18.557Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/34/44/6ffda5537085106ff5aaa762b0d130ac6c75a08015dd1621376f708c94de/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7738027989881e70e3723c75921f1efa45225084228788fc59ea8c6d732eb30d", size = 624472, upload-time = "2025-06-15T19:05:19.588Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c3/e3/71170985c48028fa3f0a50946916a14055e741db11c2e7bc2f3b61f4d0e3/watchfiles-1.1.0-cp311-cp311-win32.whl", hash = "sha256:622d6b2c06be19f6e89b1d951485a232e3b59618def88dbeda575ed8f0d8dbf2", size = 279348, upload-time = "2025-06-15T19:05:20.856Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/89/1b/3e39c68b68a7a171070f81fc2561d23ce8d6859659406842a0e4bebf3bba/watchfiles-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:48aa25e5992b61debc908a61ab4d3f216b64f44fdaa71eb082d8b2de846b7d12", size = 292607, upload-time = "2025-06-15T19:05:21.937Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/61/9f/2973b7539f2bdb6ea86d2c87f70f615a71a1fc2dba2911795cea25968aea/watchfiles-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:00645eb79a3faa70d9cb15c8d4187bb72970b2470e938670240c7998dad9f13a", size = 285056, upload-time = "2025-06-15T19:05:23.12Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f6/b8/858957045a38a4079203a33aaa7d23ea9269ca7761c8a074af3524fbb240/watchfiles-1.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9dc001c3e10de4725c749d4c2f2bdc6ae24de5a88a339c4bce32300a31ede179", size = 402339, upload-time = "2025-06-15T19:05:24.516Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/80/28/98b222cca751ba68e88521fabd79a4fab64005fc5976ea49b53fa205d1fa/watchfiles-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d9ba68ec283153dead62cbe81872d28e053745f12335d037de9cbd14bd1877f5", size = 394409, upload-time = "2025-06-15T19:05:25.469Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/86/50/dee79968566c03190677c26f7f47960aff738d32087087bdf63a5473e7df/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130fc497b8ee68dce163e4254d9b0356411d1490e868bd8790028bc46c5cc297", size = 450939, upload-time = "2025-06-15T19:05:26.494Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/40/45/a7b56fb129700f3cfe2594a01aa38d033b92a33dddce86c8dfdfc1247b72/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50a51a90610d0845a5931a780d8e51d7bd7f309ebc25132ba975aca016b576a0", size = 457270, upload-time = "2025-06-15T19:05:27.466Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b5/c8/fa5ef9476b1d02dc6b5e258f515fcaaecf559037edf8b6feffcbc097c4b8/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc44678a72ac0910bac46fa6a0de6af9ba1355669b3dfaf1ce5f05ca7a74364e", size = 483370, upload-time = "2025-06-15T19:05:28.548Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/98/68/42cfcdd6533ec94f0a7aab83f759ec11280f70b11bfba0b0f885e298f9bd/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a543492513a93b001975ae283a51f4b67973662a375a403ae82f420d2c7205ee", size = 598654, upload-time = "2025-06-15T19:05:29.997Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d3/74/b2a1544224118cc28df7e59008a929e711f9c68ce7d554e171b2dc531352/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ac164e20d17cc285f2b94dc31c384bc3aa3dd5e7490473b3db043dd70fbccfd", size = 478667, upload-time = "2025-06-15T19:05:31.172Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/77/e3362fe308358dc9f8588102481e599c83e1b91c2ae843780a7ded939a35/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7590d5a455321e53857892ab8879dce62d1f4b04748769f5adf2e707afb9d4f", size = 452213, upload-time = "2025-06-15T19:05:32.299Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/6e/17/c8f1a36540c9a1558d4faf08e909399e8133599fa359bf52ec8fcee5be6f/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:37d3d3f7defb13f62ece99e9be912afe9dd8a0077b7c45ee5a57c74811d581a4", size = 626718, upload-time = "2025-06-15T19:05:33.415Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/26/45/fb599be38b4bd38032643783d7496a26a6f9ae05dea1a42e58229a20ac13/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7080c4bb3efd70a07b1cc2df99a7aa51d98685be56be6038c3169199d0a1c69f", size = 623098, upload-time = "2025-06-15T19:05:34.534Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a1/e7/fdf40e038475498e160cd167333c946e45d8563ae4dd65caf757e9ffe6b4/watchfiles-1.1.0-cp312-cp312-win32.whl", hash = "sha256:cbcf8630ef4afb05dc30107bfa17f16c0896bb30ee48fc24bf64c1f970f3b1fd", size = 279209, upload-time = "2025-06-15T19:05:35.577Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3f/d3/3ae9d5124ec75143bdf088d436cba39812122edc47709cd2caafeac3266f/watchfiles-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:cbd949bdd87567b0ad183d7676feb98136cde5bb9025403794a4c0db28ed3a47", size = 292786, upload-time = "2025-06-15T19:05:36.559Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/26/2f/7dd4fc8b5f2b34b545e19629b4a018bfb1de23b3a496766a2c1165ca890d/watchfiles-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:0a7d40b77f07be87c6faa93d0951a0fcd8cbca1ddff60a1b65d741bac6f3a9f6", size = 284343, upload-time = "2025-06-15T19:05:37.5Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/6b/686dcf5d3525ad17b384fd94708e95193529b460a1b7bf40851f1328ec6e/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0ece16b563b17ab26eaa2d52230c9a7ae46cf01759621f4fbbca280e438267b3", size = 406910, upload-time = "2025-06-15T19:06:49.335Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f3/d3/71c2dcf81dc1edcf8af9f4d8d63b1316fb0a2dd90cbfd427e8d9dd584a90/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:51b81e55d40c4b4aa8658427a3ee7ea847c591ae9e8b81ef94a90b668999353c", size = 398816, upload-time = "2025-06-15T19:06:50.433Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/b8/fa/12269467b2fc006f8fce4cd6c3acfa77491dd0777d2a747415f28ccc8c60/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2bcdc54ea267fe72bfc7d83c041e4eb58d7d8dc6f578dfddb52f037ce62f432", size = 451584, upload-time = "2025-06-15T19:06:51.834Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/bd/d3/254cea30f918f489db09d6a8435a7de7047f8cb68584477a515f160541d6/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923fec6e5461c42bd7e3fd5ec37492c6f3468be0499bc0707b4bbbc16ac21792", size = 454009, upload-time = "2025-06-15T19:06:52.896Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } +sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://mirrors.ustc.edu.cn/pypi/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://mirrors.ustc.edu.cn/pypi/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +]