diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 213e7609..cf4fd4ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,4 +10,16 @@ repos: rev: v0.0.262 hooks: - id: ruff - args: [ '--config', '.ruff.toml' ] + args: + - '--config' + - '.ruff.toml' + - '--fix' + - repo: https://github.com/psf/black + rev: 23.3.0 + hooks: + - id: black + language_version: python3.8 + args: + - '--skip-string-normalization' + - '--line-length' + - '120' diff --git a/backend/app/api/service/user_service.py b/backend/app/api/service/user_service.py index 5a195225..acf7c590 100644 --- a/backend/app/api/service/user_service.py +++ b/backend/app/api/service/user_service.py @@ -14,7 +14,6 @@ from backend.app.utils import re_verify class UserService: - @staticmethod async def login(form_data: OAuth2PasswordRequestForm): async with async_db_session() as db: diff --git a/backend/app/api/v1/task_demo.py b/backend/app/api/v1/task_demo.py index d2c6f95d..e8046ebb 100644 --- a/backend/app/api/v1/task_demo.py +++ b/backend/app/api/v1/task_demo.py @@ -22,31 +22,28 @@ async def task_demo_async(): async def task_demo_get(): tasks = [] for job in scheduler.get_jobs(): - tasks.append({ - "id": job.id, - "func_name": job.func_ref, - "trigger": str(job.trigger), - "executor": job.executor, - # "args": str(job.args), - # "kwargs": job.kwargs, - "name": job.name, - "misfire_grace_time": job.misfire_grace_time, - "coalesce": job.coalesce, - "max_instances": job.max_instances, - "next_run_time": job.next_run_time, - }) + tasks.append( + { + "id": job.id, + "func_name": job.func_ref, + "trigger": str(job.trigger), + "executor": job.executor, + # "args": str(job.args), + # "kwargs": job.kwargs, + "name": job.name, + "misfire_grace_time": job.misfire_grace_time, + "coalesce": job.coalesce, + "max_instances": job.max_instances, + "next_run_time": job.next_run_time, + } + ) return {'msg': 'success', 'data': tasks} @router.post('', summary='添加同步任务') async def task_demo_add(): scheduler.add_job( - task_demo, - 'interval', - seconds=1, - id='task_demo', - replace_existing=True, - start_date=datetime.datetime.now() + task_demo, 'interval', seconds=1, id='task_demo', replace_existing=True, start_date=datetime.datetime.now() ) return {'msg': 'success'} @@ -60,7 +57,7 @@ async def task_demo_add_async(): seconds=1, id='task_demo_async', replace_existing=True, - start_date=datetime.datetime.now() + start_date=datetime.datetime.now(), ) return {'msg': 'success'} diff --git a/backend/app/common/enums.py b/backend/app/common/enums.py index b8dfaeb3..cc1d145c 100644 --- a/backend/app/common/enums.py +++ b/backend/app/common/enums.py @@ -4,7 +4,6 @@ from enum import Enum class EnumBase(Enum): - @classmethod def get_member_values(cls): return [item.value for item in cls._member_map_.values()] @@ -16,9 +15,11 @@ class EnumBase(Enum): class IntEnum(int, EnumBase): """整型枚举""" + pass class StrEnum(str, EnumBase): """字符串枚举""" + pass diff --git a/backend/app/common/exception/errors.py b/backend/app/common/exception/errors.py index 524e506e..a5f5ed8f 100644 --- a/backend/app/common/exception/errors.py +++ b/backend/app/common/exception/errors.py @@ -55,7 +55,6 @@ class GatewayError(BaseExceptionMixin): class CodeError(BaseExceptionMixin): - def __init__(self, *, error: CodeEnum, data: Any = None): self.code = error.code super().__init__(msg=error.msg, data=data) diff --git a/backend/app/common/exception/exception_handler.py b/backend/app/common/exception/exception_handler.py index 9abf318d..30aca75e 100644 --- a/backend/app/common/exception/exception_handler.py +++ b/backend/app/common/exception/exception_handler.py @@ -47,7 +47,7 @@ def register_exception(app: FastAPI): return JSONResponse( status_code=_get_exception_code(exc.status_code), content=response_base.fail(code=exc.status_code, msg=exc.detail), - headers=exc.headers + headers=exc.headers, ) @app.exception_handler(Exception) @@ -81,24 +81,21 @@ def register_exception(app: FastAPI): status_code=422, content=response_base.fail( msg='请求参数非法' if len(message) == 0 else f'请求参数非法:{message[:-1]}', - data={'errors': exc.errors()} if message == '' and settings.UVICORN_RELOAD is True else None - ) + data={'errors': exc.errors()} if message == '' and settings.UVICORN_RELOAD is True else None, + ), ) # 自定义 if isinstance(exc, BaseExceptionMixin): return JSONResponse( status_code=_get_exception_code(exc.code), - content=response_base.fail( - code=exc.code, - msg=str(exc.msg), - data=exc.data if exc.data else None - ) + content=response_base.fail(code=exc.code, msg=str(exc.msg), data=exc.data if exc.data else None), ) else: return JSONResponse( status_code=500, - content=response_base.fail(code=500, msg=str(exc)) if settings.UVICORN_RELOAD else - response_base.fail(code=500, msg='Internal Server Error') + content=response_base.fail(code=500, msg=str(exc)) + if settings.UVICORN_RELOAD + else response_base.fail(code=500, msg='Internal Server Error'), ) diff --git a/backend/app/common/log.py b/backend/app/common/log.py index 8b2963a3..a350dfee 100644 --- a/backend/app/common/log.py +++ b/backend/app/common/log.py @@ -11,7 +11,6 @@ from backend.app.core import path_conf class Logger: - @staticmethod def log() -> loguru.Logger: if not os.path.exists(path_conf.LogPath): diff --git a/backend/app/common/pagination.py b/backend/app/common/pagination.py index d251bddd..8e5d340e 100644 --- a/backend/app/common/pagination.py +++ b/backend/app/common/pagination.py @@ -41,10 +41,10 @@ class Page(AbstractPage[T], Generic[T]): @classmethod def create( - cls, - data: Sequence[T], - total: int, - params: Params, + cls, + data: Sequence[T], + total: int, + params: Params, ) -> Page[T]: page = params.page size = params.size @@ -54,15 +54,8 @@ class Page(AbstractPage[T], Generic[T]): "first": {"page": 1, "size": f"{size}"}, "last": {"page": f"{math.ceil(total / params.size)}", "size": f"{size}"} if total > 0 else None, "next": {"page": f"{page + 1}", "size": f"{size}"} if (page + 1) <= total_pages else None, - "prev": {"page": f"{page - 1}", "size": f"{size}"} if (page - 1) >= 1 else None + "prev": {"page": f"{page - 1}", "size": f"{size}"} if (page - 1) >= 1 else None, } ).dict() - return cls( - data=data, - total=total, - page=params.page, - size=params.size, - total_pages=total_pages, - links=links - ) + return cls(data=data, total=total, page=params.page, size=params.size, total_pages=total_pages, links=links) diff --git a/backend/app/common/redis.py b/backend/app/common/redis.py index cfc667f9..e8768273 100644 --- a/backend/app/common/redis.py +++ b/backend/app/common/redis.py @@ -9,7 +9,6 @@ from backend.app.core.conf import settings class RedisCli(Redis): - def __init__(self): super(RedisCli, self).__init__( host=settings.REDIS_HOST, @@ -17,7 +16,7 @@ class RedisCli(Redis): password=settings.REDIS_PASSWORD, db=settings.REDIS_DATABASE, socket_timeout=settings.REDIS_TIMEOUT, - decode_responses=True # 转码 utf-8 + decode_responses=True, # 转码 utf-8 ) async def open(self): diff --git a/backend/app/common/response/response_code.py b/backend/app/common/response/response_code.py index 04e256a9..a55dc15a 100644 --- a/backend/app/common/response/response_code.py +++ b/backend/app/common/response/response_code.py @@ -7,6 +7,7 @@ class CodeEnum(Enum): """ 错误码 """ + CAPTCHA_ERROR = (40001, '图形验证码错误') @property diff --git a/backend/app/common/response/response_schema.py b/backend/app/common/response/response_schema.py index b9da7430..34f4d2b6 100644 --- a/backend/app/common/response/response_schema.py +++ b/backend/app/common/response/response_schema.py @@ -8,41 +8,32 @@ from pydantic import validate_arguments, BaseModel _JsonEncoder = Union[Set[Union[int, str]], Dict[Union[int, str], Any]] -__all__ = [ - 'ResponseModel', - 'response_base' -] +__all__ = ['ResponseModel', 'response_base'] class ResponseModel(BaseModel): """ 统一返回模型, 可在 FastAPI 接口请求中指定 response_model 及更多操作 """ + code: int = 200 msg: str = 'Success' data: Optional[Any] = None class Config: - json_encoders = { - datetime: lambda x: x.strftime("%Y-%m-%d %H:%M:%S") - } + json_encoders = {datetime: lambda x: x.strftime("%Y-%m-%d %H:%M:%S")} class ResponseBase: - @staticmethod def __encode_json(data: Any): - return jsonable_encoder( - data, - custom_encoder={ - datetime: lambda x: x.strftime("%Y-%m-%d %H:%M:%S") - } - ) + return jsonable_encoder(data, custom_encoder={datetime: lambda x: x.strftime("%Y-%m-%d %H:%M:%S")}) @staticmethod @validate_arguments - def success(*, code: int = 200, msg: str = 'Success', data: Optional[Any] = None, - exclude: Optional[_JsonEncoder] = None): + def success( + *, code: int = 200, msg: str = 'Success', data: Optional[Any] = None, exclude: Optional[_JsonEncoder] = None + ): """ 请求成功返回通用方法 diff --git a/backend/app/common/task.py b/backend/app/common/task.py index 72e7cfb0..0516d32c 100644 --- a/backend/app/common/task.py +++ b/backend/app/common/task.py @@ -20,14 +20,12 @@ def _scheduler_conf() -> dict: 'port': settings.APS_REDIS_PORT, 'password': settings.APS_REDIS_PASSWORD, 'db': settings.APS_REDIS_DATABASE, - 'socket_timeout': settings.APS_REDIS_TIMEOUT + 'socket_timeout': settings.APS_REDIS_TIMEOUT, } end_conf = { # 配置存储器 - "jobstores": { - 'default': RedisJobStore(**redis_conf) - }, + "jobstores": {'default': RedisJobStore(**redis_conf)}, # 配置执行器 "executors": { 'default': AsyncIOExecutor(), @@ -39,14 +37,13 @@ def _scheduler_conf() -> dict: "misfire_grace_time": settings.APS_MISFIRE_GRACE_TIME, }, # 时区 - "timezone": str(tzlocal.get_localzone()) + "timezone": str(tzlocal.get_localzone()), } return end_conf class Scheduler(AsyncIOScheduler): - def start(self, paused: bool = False): try: super().start(paused) diff --git a/backend/app/core/conf.py b/backend/app/core/conf.py index a246a7d8..d5780fdb 100644 --- a/backend/app/core/conf.py +++ b/backend/app/core/conf.py @@ -100,7 +100,7 @@ class Settings(BaseSettings): @lru_cache def get_settings(): - """ 读取配置优化写法 """ + """读取配置优化写法""" return Settings() diff --git a/backend/app/core/registrar.py b/backend/app/core/registrar.py index cb6ea75e..55a9438b 100644 --- a/backend/app/core/registrar.py +++ b/backend/app/core/registrar.py @@ -47,7 +47,7 @@ def register_app(): docs_url=settings.DOCS_URL, redoc_url=settings.REDOCS_URL, openapi_url=settings.OPENAPI_URL, - lifespan=register_init + lifespan=register_init, ) if settings.STATIC_FILES: @@ -78,6 +78,7 @@ def register_static_file(app: FastAPI): """ import os from fastapi.staticfiles import StaticFiles + if not os.path.exists("./static"): os.mkdir("./static") app.mount("/static", StaticFiles(directory="static"), name="static") diff --git a/backend/app/crud/base.py b/backend/app/crud/base.py index b4602617..f6612b0d 100644 --- a/backend/app/crud/base.py +++ b/backend/app/crud/base.py @@ -44,8 +44,7 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]): db.add(db_obj) async def update( - self, db: AsyncSession, pk: int, obj_in: Union[UpdateSchemaType, Dict[str, Any]], - user_id: Optional[int] = None + self, db: AsyncSession, pk: int, obj_in: Union[UpdateSchemaType, Dict[str, Any]], user_id: Optional[int] = None ) -> int: """ 通过主键 id 更新一条数据 @@ -62,11 +61,7 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]): update_data = obj_in.dict(exclude_unset=True) if user_id: update_data.update({'update_user': user_id}) - model = await db.execute( - update(self.model) - .where(self.model.id == pk) - .values(**update_data) - ) + model = await db.execute(update(self.model).where(self.model.id == pk).values(**update_data)) return model.rowcount async def delete(self, db: AsyncSession, pk: int) -> int: diff --git a/backend/app/crud/crud_user.py b/backend/app/crud/crud_user.py index 41b8d1f2..7138fab4 100644 --- a/backend/app/crud/crud_user.py +++ b/backend/app/crud/crud_user.py @@ -21,11 +21,7 @@ class CRUDUser(CRUDBase[User, CreateUser, UpdateUser]): return user.scalars().first() async def update_user_login_time(self, db: AsyncSession, username: str) -> int: - user = await db.execute( - update(self.model) - .where(self.model.username == username) - .values(last_login=func.now()) - ) + user = await db.execute(update(self.model).where(self.model.username == username).values(last_login=func.now())) return user.rowcount async def create_user(self, db: AsyncSession, create: CreateUser) -> NoReturn: @@ -34,19 +30,11 @@ class CRUDUser(CRUDBase[User, CreateUser, UpdateUser]): db.add(new_user) async def update_userinfo(self, db: AsyncSession, current_user: User, obj: UpdateUser) -> int: - user = await db.execute( - update(self.model) - .where(self.model.id == current_user.id) - .values(**obj.dict()) - ) + user = await db.execute(update(self.model).where(self.model.id == current_user.id).values(**obj.dict())) return user.rowcount async def update_avatar(self, db: AsyncSession, current_user: User, avatar: Avatar) -> int: - user = await db.execute( - update(self.model) - .where(self.model.id == current_user.id) - .values(avatar=avatar) - ) + user = await db.execute(update(self.model).where(self.model.id == current_user.id).values(avatar=avatar)) return user.rowcount async def delete_user(self, db: AsyncSession, user_id: int) -> int: @@ -58,9 +46,7 @@ class CRUDUser(CRUDBase[User, CreateUser, UpdateUser]): async def reset_password(self, db: AsyncSession, pk: int, password: str) -> int: user = await db.execute( - update(self.model) - .where(self.model.id == pk) - .values(password=jwt.get_hash_password(password)) + update(self.model).where(self.model.id == pk).values(password=jwt.get_hash_password(password)) ) return user.rowcount @@ -78,18 +64,14 @@ class CRUDUser(CRUDBase[User, CreateUser, UpdateUser]): async def super_set(self, db: AsyncSession, user_id: int) -> int: super_status = await self.get_user_is_super(db, user_id) user = await db.execute( - update(self.model) - .where(self.model.id == user_id) - .values(is_superuser=False if super_status else True) + update(self.model).where(self.model.id == user_id).values(is_superuser=False if super_status else True) ) return user.rowcount async def active_set(self, db: AsyncSession, user_id: int) -> int: active_status = await self.get_user_is_active(db, user_id) user = await db.execute( - update(self.model) - .where(self.model.id == user_id) - .values(is_active=False if active_status else True) + update(self.model).where(self.model.id == user_id).values(is_active=False if active_status else True) ) return user.rowcount diff --git a/backend/app/database/base_class.py b/backend/app/database/base_class.py index a7ec1099..325f6e15 100644 --- a/backend/app/database/base_class.py +++ b/backend/app/database/base_class.py @@ -26,8 +26,9 @@ class _BaseMixin(MappedAsDataclass): create_user: Mapped[int] = mapped_column(sort_order=9999, comment='创建者') update_user: Mapped[Optional[int]] = mapped_column(init=False, default=None, sort_order=9999, comment='修改者') created_time: Mapped[datetime] = mapped_column(init=False, default=func.now(), sort_order=9999, comment='创建时间') - updated_time: Mapped[Optional[datetime]] = mapped_column(init=False, onupdate=func.now(), sort_order=9999, - comment='更新时间') + updated_time: Mapped[Optional[datetime]] = mapped_column( + init=False, onupdate=func.now(), sort_order=9999, comment='更新时间' + ) class MappedBase(DeclarativeBase): diff --git a/backend/app/database/db_mysql.py b/backend/app/database/db_mysql.py index bc1e2b48..31bfefba 100644 --- a/backend/app/database/db_mysql.py +++ b/backend/app/database/db_mysql.py @@ -14,8 +14,10 @@ from backend.app.database.base_class import MappedBase 说明:SqlAlchemy """ -SQLALCHEMY_DATABASE_URL = f'mysql+asyncmy://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:' \ - f'{settings.DB_PORT}/{settings.DB_DATABASE}?charset={settings.DB_CHARSET}' +SQLALCHEMY_DATABASE_URL = ( + f'mysql+asyncmy://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:' + f'{settings.DB_PORT}/{settings.DB_DATABASE}?charset={settings.DB_CHARSET}' +) try: # 数据库引擎 diff --git a/backend/app/init_test_data.py b/backend/app/init_test_data.py index f1870c8d..cf74cd85 100644 --- a/backend/app/init_test_data.py +++ b/backend/app/init_test_data.py @@ -12,14 +12,14 @@ from backend.app.models import User class InitData: - """ 初始化数据 """ + """初始化数据""" def __init__(self): self.fake = Faker('zh_CN') @staticmethod async def create_superuser_by_yourself(): - """ 手动创建管理员账户 """ + """手动创建管理员账户""" print('请输入用户名:') username = input() print('请输入密码:') @@ -44,7 +44,7 @@ class InitData: log.info(f'管理员用户创建成功,账号:{username},密码:{password}') async def fake_user(self): - """ 自动创建普通用户 """ + """自动创建普通用户""" username = self.fake.user_name() password = self.fake.password() email = self.fake.email() @@ -59,7 +59,7 @@ class InitData: log.info(f"普通用户创建成功,账号:{username},密码:{password}") async def fake_no_active_user(self): - """ 自动创建锁定普通用户 """ + """自动创建锁定普通用户""" username = self.fake.user_name() password = self.fake.password() email = self.fake.email() @@ -75,7 +75,7 @@ class InitData: log.info(f"普通锁定用户创建成功,账号:{username},密码:{password}") async def fake_superuser(self): - """ 自动创建管理员用户 """ + """自动创建管理员用户""" username = self.fake.user_name() password = self.fake.password() email = self.fake.email() @@ -90,7 +90,7 @@ class InitData: log.info(f"管理员用户创建成功,账号:{username},密码:{password}") async def fake_no_active_superuser(self): - """ 自动创建锁定管理员用户 """ + """自动创建锁定管理员用户""" username = self.fake.user_name() password = self.fake.password() email = self.fake.email() @@ -106,7 +106,7 @@ class InitData: log.info(f"管理员锁定用户创建成功,账号:{username},密码:{password}") async def init_data(self): - """ 自动创建数据 """ + """自动创建数据""" log.info('⏳ 开始初始化数据') await self.create_superuser_by_yourself() await self.fake_user() diff --git a/backend/app/main.py b/backend/app/main.py index 6ea88d8a..bb831790 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -24,7 +24,11 @@ if __name__ == '__main__': """ ) - uvicorn.run(app=f'{Path(__file__).stem}:app', host=settings.UVICORN_HOST, port=settings.UVICORN_PORT, - reload=settings.UVICORN_RELOAD) + uvicorn.run( + app=f'{Path(__file__).stem}:app', + host=settings.UVICORN_HOST, + port=settings.UVICORN_PORT, + reload=settings.UVICORN_RELOAD, + ) except Exception as e: log.error(f'❌ FastAPI start filed: {e}') diff --git a/backend/app/models/user.py b/backend/app/models/user.py index 72b64742..f2ceca7d 100644 --- a/backend/app/models/user.py +++ b/backend/app/models/user.py @@ -10,7 +10,8 @@ from backend.app.database.base_class import use_uuid, id_key, DataClassBase class User(DataClassBase): - """ 用户表 """ + """用户表""" + __tablename__ = 'sys_user' id: Mapped[id_key] = mapped_column(init=False) diff --git a/docker_conf.py b/docker_conf.py index 59739d57..1665abef 100644 --- a/docker_conf.py +++ b/docker_conf.py @@ -73,7 +73,7 @@ class Settings(BaseSettings): @lru_cache def get_settings(): - """ 读取配置优化写法 """ + """读取配置优化写法""" return Settings()