From 0a2f0cb146912ab021e6d51bb9e7ef79cac207cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=81=E5=AE=B6=E5=AF=85?= <15277360553@163.com>
Date: Thu, 10 Sep 2026 23:15:37 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E5=9F=BA=E9=87=91?=
=?UTF-8?q?=E4=BA=A7=E5=93=81=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3,?=
=?UTF-8?q?=E5=8E=86=E5=8F=B2=E4=B8=9A=E7=BB=A9=E6=8E=A5=E5=8F=A3,?=
=?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=B3=A8=E5=86=8C=E6=8F=90=E4=BA=A4=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3,=E9=97=AE=E5=8D=B7=E6=8F=90=E4=BA=A4=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/Mutual_Fund.iml | 2 +-
.idea/misc.xml | 2 +-
api/router.py | 4 +-
api/routers/auth.py | 14 +-
logs/error.log | 851 +++++++++++++++++++++++++++++++++++++++
logs/info.log | 851 +++++++++++++++++++++++++++++++++++++++
repositories/sys_user.py | 5 +-
requirements.txt | 22 +-
schemas/auth.py | 9 +-
service/auth.py | 28 +-
sql/schema.sql | 1 -
11 files changed, 1767 insertions(+), 22 deletions(-)
diff --git a/.idea/Mutual_Fund.iml b/.idea/Mutual_Fund.iml
index 3fbabf5..7b59439 100644
--- a/.idea/Mutual_Fund.iml
+++ b/.idea/Mutual_Fund.iml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7440d61..34dc9d9 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/api/router.py b/api/router.py
index f199e06..3d132d6 100644
--- a/api/router.py
+++ b/api/router.py
@@ -3,7 +3,9 @@
"""
from fastapi import APIRouter
-from api.routers import auth
+from api.routers import auth, product, questionnaire
api_router = APIRouter()
api_router.include_router(auth.router, prefix="/api", tags=["认证"])
+api_router.include_router(product.router, prefix="/api", tags=["产品"])
+api_router.include_router(questionnaire.router, prefix="/api", tags=["问卷"])
diff --git a/api/routers/auth.py b/api/routers/auth.py
index df51975..0bb0891 100644
--- a/api/routers/auth.py
+++ b/api/routers/auth.py
@@ -1,12 +1,13 @@
-"""认证路由:登录 + 当前用户(业务在 service/auth.py,路由只做编排)。"""
+"""认证路由:登录 + 注册 + 当前用户(业务在 service/auth.py,路由只做编排)。"""
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from api.deps import get_current_user
from config.deps import get_db
from model.sys_user import SysUser
-from schemas.auth import LoginReq
+from schemas.auth import LoginReq, RegisterReq
from service.auth import login as auth_login
+from service.auth import register as auth_register
from service.auth import user_payload
from utils.response import success
@@ -18,7 +19,14 @@ async def login(body: LoginReq, db: AsyncSession = Depends(get_db)):
return success(await auth_login(db, body.username, body.password))
+@router.post("/auth/register")
+async def register(body: RegisterReq, db: AsyncSession = Depends(get_db)):
+ return success(
+ await auth_register(db, body.username, body.password, body.phone, body.real_name)
+ )
+
+
@router.get("/auth/me")
async def me(user: SysUser = Depends(get_current_user)):
"""受保护示例路由:任意接口加 Depends(get_current_user) 即获得当前用户。"""
- return success({"user": user_payload(user)})
\ No newline at end of file
+ return success({"user": user_payload(user)})
diff --git a/logs/error.log b/logs/error.log
index ddccd54..428d8f4 100644
--- a/logs/error.log
+++ b/logs/error.log
@@ -403,3 +403,854 @@ Traceback (most recent call last):
self._write_fut = self._loop._proactor.send(self._sock, data)
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'send'
+2026-09-10 20:49:20,257 ERROR [-] api: unhandled error on /api/auth/login
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\auth.py", line 19, in login
+ return success(await auth_login(db, body.username, body.password))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\auth.py", line 68, in login
+ user = await SysUserRepo(db).get_by_username(username)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\sys_user.py", line 14, in get_by_username
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 504, in scalar
+ return await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2421, in scalar
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 984, in caching_sha2_password_auth
+ data = _auth.sha2_rsa_encrypt(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\_auth.py", line 144, in sha2_rsa_encrypt
+ raise RuntimeError(
+RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods
+2026-09-10 20:50:16,723 ERROR [-] api: unhandled error on /api/auth/login
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+pymysql.err.OperationalError: (1049, "Unknown database 'memory'")
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\auth.py", line 19, in login
+ return success(await auth_login(db, body.username, body.password))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\auth.py", line 68, in login
+ user = await SysUserRepo(db).get_by_username(username)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\sys_user.py", line 14, in get_by_username
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 504, in scalar
+ return await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2421, in scalar
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__
+ Connection._handle_dbapi_exception_noconnection(
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2450, in _handle_dbapi_exception_noconnection
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1049, "Unknown database 'memory'")
+(Background on this error at: https://sqlalche.me/e/20/e3q8)
+2026-09-10 20:51:21,189 ERROR [-] api: unhandled error on /api/auth/login
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 952, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+pymysql.err.OperationalError: (1049, "Unknown database 'memory'")
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\auth.py", line 19, in login
+ return success(await auth_login(db, body.username, body.password))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\auth.py", line 68, in login
+ user = await SysUserRepo(db).get_by_username(username)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\sys_user.py", line 14, in get_by_username
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 504, in scalar
+ return await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2421, in scalar
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__
+ Connection._handle_dbapi_exception_noconnection(
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2450, in _handle_dbapi_exception_noconnection
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 952, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1049, "Unknown database 'memory'")
+(Background on this error at: https://sqlalche.me/e/20/e3q8)
+2026-09-10 21:54:16,943 ERROR [-] api: unhandled error on /api/products
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\product.py", line 26, in products
+ data = await list_products(
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\product.py", line 54, in list_products
+ items, total = await ProductRepo(db).search(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\product.py", line 64, in search
+ items = list((await self.db.scalars(stmt)).all())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 561, in scalars
+ result = await self.execute(
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 448, in execute
+ result = await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2373, in execute
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__
+ Connection._handle_dbapi_exception_noconnection(
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2450, in _handle_dbapi_exception_noconnection
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
+(Background on this error at: https://sqlalche.me/e/20/e3q8)
diff --git a/logs/info.log b/logs/info.log
index e25fec3..7a4fbc2 100644
--- a/logs/info.log
+++ b/logs/info.log
@@ -412,3 +412,854 @@ Traceback (most recent call last):
self._write_fut = self._loop._proactor.send(self._sock, data)
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'send'
+2026-09-10 20:49:20,257 ERROR [-] api: unhandled error on /api/auth/login
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\auth.py", line 19, in login
+ return success(await auth_login(db, body.username, body.password))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\auth.py", line 68, in login
+ user = await SysUserRepo(db).get_by_username(username)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\sys_user.py", line 14, in get_by_username
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 504, in scalar
+ return await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2421, in scalar
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 984, in caching_sha2_password_auth
+ data = _auth.sha2_rsa_encrypt(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\_auth.py", line 144, in sha2_rsa_encrypt
+ raise RuntimeError(
+RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods
+2026-09-10 20:50:16,723 ERROR [-] api: unhandled error on /api/auth/login
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+pymysql.err.OperationalError: (1049, "Unknown database 'memory'")
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\auth.py", line 19, in login
+ return success(await auth_login(db, body.username, body.password))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\auth.py", line 68, in login
+ user = await SysUserRepo(db).get_by_username(username)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\sys_user.py", line 14, in get_by_username
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 504, in scalar
+ return await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2421, in scalar
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__
+ Connection._handle_dbapi_exception_noconnection(
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2450, in _handle_dbapi_exception_noconnection
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1049, "Unknown database 'memory'")
+(Background on this error at: https://sqlalche.me/e/20/e3q8)
+2026-09-10 20:51:21,189 ERROR [-] api: unhandled error on /api/auth/login
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 952, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+pymysql.err.OperationalError: (1049, "Unknown database 'memory'")
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\auth.py", line 19, in login
+ return success(await auth_login(db, body.username, body.password))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\auth.py", line 68, in login
+ user = await SysUserRepo(db).get_by_username(username)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\sys_user.py", line 14, in get_by_username
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 504, in scalar
+ return await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2421, in scalar
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__
+ Connection._handle_dbapi_exception_noconnection(
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2450, in _handle_dbapi_exception_noconnection
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 952, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1049, "Unknown database 'memory'")
+(Background on this error at: https://sqlalche.me/e/20/e3q8)
+2026-09-10 21:54:16,943 ERROR [-] api: unhandled error on /api/products
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
+ await self.app(scope, receive, _send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 193, in __call__
+ response = await self.dispatch_func(request, call_next)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\utils\request_id.py", line 28, in dispatch
+ response: Response = await call_next(request)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 168, in call_next
+ raise app_exc from app_exc.__cause__ or app_exc.__context__
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\base.py", line 144, in coro
+ await self.app(scope, receive_or_disconnect, send_no_error)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
+ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
+ await self.app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\routing.py", line 670, in __call__
+ await self.middleware_stack(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1791, in _handle_selected
+ await route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle
+ await self.original_router.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle
+ await included_router._handle_selected(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected
+ await original_route.handle(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle
+ await app(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app
+ await wrap_app_handling_exceptions(app, request)(scope, receive, send)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
+ raise exc
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
+ await app(scope, receive, sender)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app
+ response = await f(request)
+ ^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 706, in app
+ raw_response = await run_endpoint_function(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\fastapi\routing.py", line 352, in run_endpoint_function
+ return await dependant.call(**values)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\api\routers\product.py", line 26, in products
+ data = await list_products(
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\service\product.py", line 54, in list_products
+ items, total = await ProductRepo(db).search(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\repositories\product.py", line 64, in search
+ items = list((await self.db.scalars(stmt)).all())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 561, in scalars
+ result = await self.execute(
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 448, in execute
+ result = await greenlet_spawn(
+ ^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn
+ result = context.throw(*sys.exc_info())
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2373, in execute
+ return self._execute_internal(
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal
+ conn = self._connection_for_bind(bind)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind
+ return trans._connection_for_bind(engine, execution_options)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "", line 2, in _connection_for_bind
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go
+ ret_value = fn(self, *arg, **kw)
+ ^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind
+ conn = bind.connect()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect
+ return self._connection_cls(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__
+ Connection._handle_dbapi_exception_noconnection(
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2450, in _handle_dbapi_exception_noconnection
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__
+ self._dbapi_connection = engine.raw_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection
+ return self.pool.connect()
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect
+ return _ConnectionFairy._checkout(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout
+ fairy = _ConnectionRecord.checkout(pool)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkout
+ rec = pool._do_get()
+ ^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 178, in _do_get
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 176, in _do_get
+ return self._create_connection()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 389, in _create_connection
+ return _ConnectionRecord(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__
+ self.__connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect
+ with util.safe_reraise():
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__
+ raise exc_value.with_traceback(exc_tb)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect
+ self.dbapi_connection = connection = pool._invoke_creator(self)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect
+ return dialect.connect(*cargs_tup, **cparams)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 176, in connect
+ await_only(creator_fn(*arg, **kw)),
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only
+ return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn
+ value = await result
+ ^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 74, in _connect
+ await conn._connect()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 540, in _connect
+ await self._request_authentication()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 865, in _request_authentication
+ await self.caching_sha2_password_auth(auth_packet)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 989, in caching_sha2_password_auth
+ pkt = await self._read_packet()
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\aiomysql\connection.py", line 652, in _read_packet
+ packet.raise_for_error()
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\protocol.py", line 219, in raise_for_error
+ err.raise_mysql_exception(self._data)
+ File "C:\Users\Windows\PycharmProjects\Mutual_Fund\.venv\Lib\site-packages\pymysql\err.py", line 154, in raise_mysql_exception
+ raise errorclass(errno, errval, sqlstate=sqlstate)
+sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
+(Background on this error at: https://sqlalche.me/e/20/e3q8)
diff --git a/repositories/sys_user.py b/repositories/sys_user.py
index d8dc4a4..5304dc5 100644
--- a/repositories/sys_user.py
+++ b/repositories/sys_user.py
@@ -11,4 +11,7 @@ class SysUserRepo(BaseRepository):
model = SysUser
async def get_by_username(self, username: str) -> SysUser | None:
- return await self.db.scalar(select(SysUser).where(SysUser.username == username))
\ No newline at end of file
+ return await self.db.scalar(select(SysUser).where(SysUser.username == username))
+
+ async def get_by_phone(self, phone: str) -> SysUser | None:
+ return await self.db.scalar(select(SysUser).where(SysUser.phone == phone))
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 55494c7..0fc9de2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,12 +1,10 @@
-fastapi
-uvicorn
-httpx
-pyjwt
-pydantic
-pydantic-settings
-sqlalchemy
-aiomysql
-redis
-pymilvus
-neo4j
-python-dotenv
\ No newline at end of file
+fastapi~=0.141.1
+sqlalchemy~=2.0.52
+httpx~=0.28.1
+pydantic~=2.13.5
+starlette~=1.6.0
+neo4j~=6.3.0
+redis~=8.1.0
+pymilvus~=3.0.1
+pydantic-settings~=2.15.0
+pyjwt~=2.13.0
\ No newline at end of file
diff --git a/schemas/auth.py b/schemas/auth.py
index 0084476..6c8f08b 100644
--- a/schemas/auth.py
+++ b/schemas/auth.py
@@ -4,4 +4,11 @@ from pydantic import BaseModel, Field
class LoginReq(BaseModel):
username: str = Field(min_length=1, max_length=64)
- password: str = Field(min_length=1, max_length=128)
\ No newline at end of file
+ password: str = Field(min_length=1, max_length=128)
+
+
+class RegisterReq(BaseModel):
+ username: str = Field(min_length=1, max_length=64)
+ password: str = Field(min_length=8, max_length=128, description="密码至少 8 位")
+ phone: str = Field(pattern=r"^1\d{10}$", description="11 位手机号")
+ real_name: str | None = Field(default=None, max_length=32)
\ No newline at end of file
diff --git a/service/auth.py b/service/auth.py
index 3ca1a2e..2d47c7e 100644
--- a/service/auth.py
+++ b/service/auth.py
@@ -70,4 +70,30 @@ async def login(db: AsyncSession, username: str, password: str) -> dict:
raise ParamError("用户名或密码错误")
if user.status != "正常":
raise ForbiddenError("账号状态异常,无法登录")
- return {"token": create_token(user.id), "user": user_payload(user)}
\ No newline at end of file
+ return {"token": create_token(user.id), "user": user_payload(user)}
+
+
+async def register(
+ db: AsyncSession,
+ username: str,
+ password: str,
+ phone: str,
+ real_name: str | None = None,
+) -> dict:
+ """客户注册:唯一性校验 → 密码加密存储 → 返回用户信息(不自动签发 token)。"""
+ repo = SysUserRepo(db)
+ if await repo.get_by_username(username) is not None:
+ raise ParamError("用户名已存在")
+ if await repo.get_by_phone(phone) is not None:
+ raise ParamError("手机号已注册")
+
+ user = SysUser(
+ username=username,
+ password_hash=hash_password(password),
+ phone=phone,
+ real_name=real_name,
+ user_type="CUSTOMER",
+ status="正常",
+ )
+ user = await repo.add(user)
+ return user_payload(user)
\ No newline at end of file
diff --git a/sql/schema.sql b/sql/schema.sql
index f2d3f68..ac56327 100644
--- a/sql/schema.sql
+++ b/sql/schema.sql
@@ -59,7 +59,6 @@ CREATE TABLE IF NOT EXISTS fin_product (
expected_return DECIMAL(7,4) NULL COMMENT '预期年化收益率(%)',
nav DECIMAL(12,6) NULL COMMENT '最新单位净值',
nav_date DATE NULL COMMENT '净值日期',
- min_amount DECIMAL(16,2) NOT NULL DEFAULT 10.00 COMMENT '起投金额(元)',
fee_rate DECIMAL(6,4) NOT NULL DEFAULT 0.0000 COMMENT '申购费率(%)',
term_days INT NOT NULL DEFAULT 0 COMMENT '产品期限天数,0=活期(开放申赎)',
fund_manager VARCHAR(64) NULL COMMENT '基金经理',
From 9cb07473034b015cc184f4066cd0b1528eafa0df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=81=E5=AE=B6=E5=AF=85?= <15277360553@163.com>
Date: Thu, 10 Sep 2026 23:19:25 +0800
Subject: [PATCH 2/2] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E5=9F=BA=E9=87=91?=
=?UTF-8?q?=E4=BA=A7=E5=93=81=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3,?=
=?UTF-8?q?=E5=8E=86=E5=8F=B2=E4=B8=9A=E7=BB=A9=E6=8E=A5=E5=8F=A3,?=
=?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=B3=A8=E5=86=8C=E6=8F=90=E4=BA=A4=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3,=E9=97=AE=E5=8D=B7=E6=8F=90=E4=BA=A4=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/routers/product.py | 49 ++++++++++
api/routers/questionnaire.py | 23 +++++
model/fin_customer_profile.py | 32 +++++++
model/fin_product.py | 32 +++++++
model/fin_risk_assessment.py | 26 ++++++
model/fund_nav_history.py | 23 +++++
model/ops_question.py | 22 +++++
model/ops_questionnaire.py | 24 +++++
repositories/fund_nav.py | 32 +++++++
repositories/product.py | 71 +++++++++++++++
repositories/questionnaire.py | 24 +++++
repositories/risk_assessment.py | 46 ++++++++++
schemas/questionnaire.py | 12 +++
service/product.py | 155 ++++++++++++++++++++++++++++++++
service/questionnaire.py | 85 ++++++++++++++++++
15 files changed, 656 insertions(+)
create mode 100644 api/routers/product.py
create mode 100644 api/routers/questionnaire.py
create mode 100644 model/fin_customer_profile.py
create mode 100644 model/fin_product.py
create mode 100644 model/fin_risk_assessment.py
create mode 100644 model/fund_nav_history.py
create mode 100644 model/ops_question.py
create mode 100644 model/ops_questionnaire.py
create mode 100644 repositories/fund_nav.py
create mode 100644 repositories/product.py
create mode 100644 repositories/questionnaire.py
create mode 100644 repositories/risk_assessment.py
create mode 100644 schemas/questionnaire.py
create mode 100644 service/product.py
create mode 100644 service/questionnaire.py
diff --git a/api/routers/product.py b/api/routers/product.py
new file mode 100644
index 0000000..81928d2
--- /dev/null
+++ b/api/routers/product.py
@@ -0,0 +1,49 @@
+"""产品路由:列表 + 历史业绩(匿名可访问,业务在 service/product.py)。"""
+from datetime import date
+
+from fastapi import APIRouter, Depends, Query
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from config.deps import get_db
+from service.product import get_history, list_products
+from utils.response import success
+
+router = APIRouter()
+
+
+@router.get("/products")
+async def products(
+ page: int = Query(1, ge=1),
+ page_size: int = Query(10, ge=1, le=100),
+ keyword: str | None = Query(None, max_length=64),
+ product_type: str | None = Query(None, max_length=32),
+ risk_level: str | None = Query(None, max_length=8),
+ status: str = Query("在售", max_length=16),
+ sort_by: str = Query("create_time", max_length=32),
+ sort_order: str = Query("desc", max_length=4),
+ db: AsyncSession = Depends(get_db),
+):
+ data = await list_products(
+ db,
+ page=page,
+ page_size=page_size,
+ keyword=keyword,
+ product_type=product_type,
+ risk_level=risk_level,
+ status=status,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ )
+ return success(data)
+
+
+@router.get("/products/{product_code}/history")
+async def history(
+ product_code: str,
+ start_date: date | None = Query(None),
+ end_date: date | None = Query(None),
+ series: str = Query("nav", max_length=16),
+ db: AsyncSession = Depends(get_db),
+):
+ data = await get_history(db, product_code, start_date, end_date, series)
+ return success(data)
diff --git a/api/routers/questionnaire.py b/api/routers/questionnaire.py
new file mode 100644
index 0000000..b62ad42
--- /dev/null
+++ b/api/routers/questionnaire.py
@@ -0,0 +1,23 @@
+"""问卷路由:风险测评提交(需登录,业务在 service/questionnaire.py)。"""
+from fastapi import APIRouter, Depends
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from api.deps import get_current_user
+from config.deps import get_db
+from model.sys_user import SysUser
+from schemas.questionnaire import RiskAssessmentSubmitReq
+from service.questionnaire import submit_assessment
+from utils.response import success
+
+router = APIRouter()
+
+
+@router.post("/risk-assessment/submit")
+async def submit(
+ body: RiskAssessmentSubmitReq,
+ user: SysUser = Depends(get_current_user),
+ db: AsyncSession = Depends(get_db),
+):
+ answers = [a.model_dump() for a in body.answers]
+ data = await submit_assessment(db, user.id, body.questionnaire_id, answers)
+ return success(data)
diff --git a/model/fin_customer_profile.py b/model/fin_customer_profile.py
new file mode 100644
index 0000000..a9e8389
--- /dev/null
+++ b/model/fin_customer_profile.py
@@ -0,0 +1,32 @@
+"""fin_customer_profile 客户画像主表 ORM 模型。"""
+from __future__ import annotations
+
+from datetime import datetime
+from decimal import Decimal
+from typing import Any
+
+from sqlalchemy import BigInteger, DateTime, Integer, JSON, Numeric, String, func
+from sqlalchemy.orm import Mapped, mapped_column
+
+from model.base import Base
+
+
+class FinCustomerProfile(Base):
+ __tablename__ = "fin_customer_profile"
+ __table_args__ = {"comment": "客户画像主表(RAG/GraphRAG 个性化推荐核心上下文)"}
+
+ # 主键为 customer_id(一对一关联 sys_user.id),非自增 id
+ customer_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
+ risk_level: Mapped[str | None] = mapped_column(String(16))
+ risk_score: Mapped[int | None] = mapped_column(Integer)
+ investment_experience: Mapped[str | None] = mapped_column(String(16))
+ annual_income_range: Mapped[str | None] = mapped_column(String(32))
+ total_assets: Mapped[Decimal | None] = mapped_column(Numeric(18, 2))
+ asset_allocation: Mapped[dict[str, Any] | None] = mapped_column(JSON)
+ product_preference: Mapped[dict[str, Any] | None] = mapped_column(JSON)
+ customer_level: Mapped[str | None] = mapped_column(String(16))
+ confidence_score: Mapped[Decimal] = mapped_column(Numeric(5, 2), server_default="0.50")
+ profile_version: Mapped[int] = mapped_column(Integer, server_default="1")
+ update_time: Mapped[datetime] = mapped_column(
+ DateTime, server_default=func.now(), onupdate=func.now()
+ )
diff --git a/model/fin_product.py b/model/fin_product.py
new file mode 100644
index 0000000..f324ba9
--- /dev/null
+++ b/model/fin_product.py
@@ -0,0 +1,32 @@
+"""fin_product 公募基金产品表 ORM 模型。"""
+from __future__ import annotations
+
+from datetime import date, datetime
+from decimal import Decimal
+
+from sqlalchemy import BigInteger, Date, DateTime, Integer, Numeric, String, func
+from sqlalchemy.orm import Mapped, mapped_column
+
+from model.base import Base
+
+
+class FinProduct(Base):
+ __tablename__ = "fin_product"
+ __table_args__ = {"comment": "公募基金产品表"}
+
+ id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
+ product_code: Mapped[str] = mapped_column(String(32), unique=True)
+ product_name: Mapped[str] = mapped_column(String(128))
+ product_type: Mapped[str] = mapped_column(String(32))
+ risk_level: Mapped[str] = mapped_column(String(8))
+ expected_return: Mapped[Decimal | None] = mapped_column(Numeric(7, 4))
+ nav: Mapped[Decimal | None] = mapped_column(Numeric(12, 6))
+ nav_date: Mapped[date | None] = mapped_column(Date)
+ fee_rate: Mapped[Decimal] = mapped_column(Numeric(6, 4), server_default="0.0000")
+ term_days: Mapped[int] = mapped_column(Integer, server_default="0")
+ fund_manager: Mapped[str | None] = mapped_column(String(64))
+ status: Mapped[str] = mapped_column(String(16), server_default="在售")
+ create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
+ update_time: Mapped[datetime] = mapped_column(
+ DateTime, server_default=func.now(), onupdate=func.now()
+ )
diff --git a/model/fin_risk_assessment.py b/model/fin_risk_assessment.py
new file mode 100644
index 0000000..f9995ba
--- /dev/null
+++ b/model/fin_risk_assessment.py
@@ -0,0 +1,26 @@
+"""fin_risk_assessment 风险评估记录表 ORM 模型。"""
+from __future__ import annotations
+
+from datetime import date, datetime
+from typing import Any
+
+from sqlalchemy import BigInteger, Date, DateTime, Integer, JSON, String, func
+from sqlalchemy.orm import Mapped, mapped_column
+
+from model.base import Base
+
+
+class FinRiskAssessment(Base):
+ __tablename__ = "fin_risk_assessment"
+ __table_args__ = {"comment": "风险评估记录表(购买前问卷确认客户等级)"}
+
+ id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
+ customer_id: Mapped[int] = mapped_column(BigInteger)
+ assessment_date: Mapped[date] = mapped_column(Date)
+ question_version: Mapped[str | None] = mapped_column(String(16))
+ total_score: Mapped[int] = mapped_column(Integer)
+ risk_level: Mapped[str] = mapped_column(String(16))
+ answers: Mapped[list[Any] | None] = mapped_column(JSON)
+ assessor_type: Mapped[str] = mapped_column(String(16), server_default="AI评估")
+ valid_until: Mapped[date] = mapped_column(Date)
+ create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
diff --git a/model/fund_nav_history.py b/model/fund_nav_history.py
new file mode 100644
index 0000000..f05dcbc
--- /dev/null
+++ b/model/fund_nav_history.py
@@ -0,0 +1,23 @@
+"""fund_nav_history 基金净值历史表 ORM 模型。"""
+from __future__ import annotations
+
+from datetime import date, datetime
+from decimal import Decimal
+
+from sqlalchemy import BigInteger, Date, DateTime, Numeric, func
+from sqlalchemy.orm import Mapped, mapped_column
+
+from model.base import Base
+
+
+class FundNavHistory(Base):
+ __tablename__ = "fund_nav_history"
+ __table_args__ = {"comment": "基金净值历史(业绩指标/走势图数据源)"}
+
+ id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
+ product_id: Mapped[int] = mapped_column(BigInteger)
+ nav_date: Mapped[date] = mapped_column(Date)
+ unit_nav: Mapped[Decimal] = mapped_column(Numeric(12, 6))
+ accumulated_nav: Mapped[Decimal | None] = mapped_column(Numeric(12, 6))
+ daily_growth: Mapped[Decimal | None] = mapped_column(Numeric(8, 4))
+ create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
diff --git a/model/ops_question.py b/model/ops_question.py
new file mode 100644
index 0000000..d7cd249
--- /dev/null
+++ b/model/ops_question.py
@@ -0,0 +1,22 @@
+"""ops_question 问卷题目表 ORM 模型。"""
+from __future__ import annotations
+
+from typing import Any
+
+from sqlalchemy import BigInteger, Integer, JSON, String
+from sqlalchemy.orm import Mapped, mapped_column
+
+from model.base import Base
+
+
+class OpsQuestion(Base):
+ __tablename__ = "ops_question"
+ __table_args__ = {"comment": "问卷题目表(题目/选项/分值可运营配置)"}
+
+ id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
+ questionnaire_id: Mapped[int] = mapped_column(BigInteger)
+ question_no: Mapped[int] = mapped_column(Integer)
+ content: Mapped[str] = mapped_column(String(512))
+ option_json: Mapped[list[Any] | None] = mapped_column(JSON)
+ score_json: Mapped[dict[str, Any] | None] = mapped_column(JSON)
+ sort: Mapped[int] = mapped_column(Integer, server_default="0")
diff --git a/model/ops_questionnaire.py b/model/ops_questionnaire.py
new file mode 100644
index 0000000..05bc560
--- /dev/null
+++ b/model/ops_questionnaire.py
@@ -0,0 +1,24 @@
+"""ops_questionnaire 问卷模板表 ORM 模型。"""
+from __future__ import annotations
+
+from datetime import datetime
+
+from sqlalchemy import BigInteger, DateTime, String, func
+from sqlalchemy.orm import Mapped, mapped_column
+
+from model.base import Base
+
+
+class OpsQuestionnaire(Base):
+ __tablename__ = "ops_questionnaire"
+ __table_args__ = {"comment": "问卷模板表"}
+
+ id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
+ name: Mapped[str] = mapped_column(String(64))
+ q_type: Mapped[str] = mapped_column(String(16))
+ version: Mapped[str] = mapped_column(String(16), server_default="v1")
+ status: Mapped[str] = mapped_column(String(16), server_default="启用")
+ create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
+ update_time: Mapped[datetime] = mapped_column(
+ DateTime, server_default=func.now(), onupdate=func.now()
+ )
diff --git a/repositories/fund_nav.py b/repositories/fund_nav.py
new file mode 100644
index 0000000..6d58e8f
--- /dev/null
+++ b/repositories/fund_nav.py
@@ -0,0 +1,32 @@
+"""fund_nav_history 净值历史仓储:按产品代码与日期区间查询走势。
+
+数据现状说明:fund_nav_history.product_id 列在 Mock 数据灌入时存的是基金代码
+(如 110001)而非 fin_product 主键 id。为不改数据库、只通过代码适配,这里用
+CAST 把 BIGINT 列按字符串与 product_code 比对。
+"""
+from __future__ import annotations
+
+from datetime import date
+
+from sqlalchemy import String, cast, select
+
+from model.fund_nav_history import FundNavHistory
+from repositories.base import BaseRepository
+
+
+class FundNavRepo(BaseRepository):
+ model = FundNavHistory
+
+ async def list_series(
+ self, product_code: str, start_date: date, end_date: date
+ ) -> list[FundNavHistory]:
+ stmt = (
+ select(FundNavHistory)
+ .where(
+ cast(FundNavHistory.product_id, String) == product_code,
+ FundNavHistory.nav_date >= start_date,
+ FundNavHistory.nav_date <= end_date,
+ )
+ .order_by(FundNavHistory.nav_date.asc())
+ )
+ return list((await self.db.scalars(stmt)).all())
diff --git a/repositories/product.py b/repositories/product.py
new file mode 100644
index 0000000..2eddc99
--- /dev/null
+++ b/repositories/product.py
@@ -0,0 +1,71 @@
+"""fin_product 产品仓储:列表搜索(关键字/类型/风险/状态筛选 + 排序 + 分页)。"""
+from __future__ import annotations
+
+from sqlalchemy import or_, select
+
+from model.fin_product import FinProduct
+from repositories.base import BaseRepository
+from utils.exceptions import ParamError
+
+# 排序字段白名单:防止 sort_by 注入,字符串映射到 ORM 列(不拼 SQL)
+SORTABLE_FIELDS = {
+ "expected_return": FinProduct.expected_return,
+ "nav": FinProduct.nav,
+ "fee_rate": FinProduct.fee_rate,
+ "risk_level": FinProduct.risk_level,
+ "create_time": FinProduct.create_time,
+}
+
+
+class ProductRepo(BaseRepository):
+ model = FinProduct
+
+ async def get_by_code(self, product_code: str) -> FinProduct | None:
+ return await self.db.scalar(
+ select(FinProduct).where(FinProduct.product_code == product_code)
+ )
+
+ async def search(
+ self,
+ *,
+ keyword: str | None = None,
+ product_type: str | None = None,
+ risk_level: str | None = None,
+ status: str | None = "在售",
+ sort_by: str = "create_time",
+ sort_order: str = "desc",
+ limit: int = 10,
+ offset: int = 0,
+ ) -> tuple[list[FinProduct], int]:
+ conds = []
+ if status and status != "全部":
+ conds.append(FinProduct.status == status)
+ if product_type:
+ conds.append(FinProduct.product_type == product_type)
+ if risk_level:
+ conds.append(FinProduct.risk_level == risk_level)
+ if keyword:
+ like = f"%{keyword}%"
+ conds.append(
+ or_(
+ FinProduct.product_code.like(like),
+ FinProduct.product_name.like(like),
+ FinProduct.fund_manager.like(like),
+ )
+ )
+
+ col = SORTABLE_FIELDS.get(sort_by)
+ if col is None:
+ raise ParamError(f"不支持的排序字段: {sort_by}")
+ order_col = col.desc() if sort_order == "desc" else col.asc()
+
+ stmt = (
+ select(FinProduct)
+ .where(*conds)
+ .order_by(order_col)
+ .limit(limit)
+ .offset(offset)
+ )
+ items = list((await self.db.scalars(stmt)).all())
+ total = await self.count(where=conds)
+ return items, total
diff --git a/repositories/questionnaire.py b/repositories/questionnaire.py
new file mode 100644
index 0000000..b459b3f
--- /dev/null
+++ b/repositories/questionnaire.py
@@ -0,0 +1,24 @@
+"""问卷域仓储:问卷模板 + 题目。"""
+from __future__ import annotations
+
+from sqlalchemy import select
+
+from model.ops_question import OpsQuestion
+from model.ops_questionnaire import OpsQuestionnaire
+from repositories.base import BaseRepository
+
+
+class QuestionnaireRepo(BaseRepository):
+ model = OpsQuestionnaire
+
+
+class QuestionRepo(BaseRepository):
+ model = OpsQuestion
+
+ async def list_by_questionnaire(self, questionnaire_id: int) -> list[OpsQuestion]:
+ stmt = (
+ select(OpsQuestion)
+ .where(OpsQuestion.questionnaire_id == questionnaire_id)
+ .order_by(OpsQuestion.question_no.asc(), OpsQuestion.sort.asc())
+ )
+ return list((await self.db.scalars(stmt)).all())
diff --git a/repositories/risk_assessment.py b/repositories/risk_assessment.py
new file mode 100644
index 0000000..20b0ced
--- /dev/null
+++ b/repositories/risk_assessment.py
@@ -0,0 +1,46 @@
+"""风评域仓储:风评记录 + 客户画像(画像主键为 customer_id)。"""
+from __future__ import annotations
+
+from sqlalchemy import select
+
+from model.fin_customer_profile import FinCustomerProfile
+from model.fin_risk_assessment import FinRiskAssessment
+from repositories.base import BaseRepository
+
+
+class RiskAssessmentRepo(BaseRepository):
+ model = FinRiskAssessment
+
+
+class CustomerProfileRepo(BaseRepository):
+ """客户画像仓储。注意:主键是 customer_id 而非 id,不适用基类 get(pk)。"""
+
+ model = FinCustomerProfile
+
+ async def get_by_customer(self, customer_id: int) -> FinCustomerProfile | None:
+ return await self.db.scalar(
+ select(FinCustomerProfile).where(
+ FinCustomerProfile.customer_id == customer_id
+ )
+ )
+
+ async def upsert_risk(
+ self, customer_id: int, risk_level: str, risk_score: int
+ ) -> FinCustomerProfile:
+ """回写风险等级与评分:无画像则初始化,有则更新并递增画像版本号。"""
+ profile = await self.get_by_customer(customer_id)
+ if profile is None:
+ profile = FinCustomerProfile(
+ customer_id=customer_id,
+ risk_level=risk_level,
+ risk_score=risk_score,
+ profile_version=1,
+ )
+ self.db.add(profile)
+ else:
+ profile.risk_level = risk_level
+ profile.risk_score = risk_score
+ profile.profile_version = (profile.profile_version or 0) + 1
+ await self.db.commit()
+ await self.db.refresh(profile)
+ return profile
diff --git a/schemas/questionnaire.py b/schemas/questionnaire.py
new file mode 100644
index 0000000..7b0da7d
--- /dev/null
+++ b/schemas/questionnaire.py
@@ -0,0 +1,12 @@
+"""问卷提交相关 DTO。"""
+from pydantic import BaseModel, Field
+
+
+class AnswerItem(BaseModel):
+ question_no: int = Field(gt=0)
+ option: str = Field(min_length=1, max_length=8)
+
+
+class RiskAssessmentSubmitReq(BaseModel):
+ questionnaire_id: int = Field(gt=0)
+ answers: list[AnswerItem] = Field(min_length=1)
diff --git a/service/product.py b/service/product.py
new file mode 100644
index 0000000..0bb05b4
--- /dev/null
+++ b/service/product.py
@@ -0,0 +1,155 @@
+"""产品服务:列表(分页/筛选/排序)+ 历史业绩(净值/收益走势)。"""
+from __future__ import annotations
+
+from datetime import date, timedelta
+
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from model.fin_product import FinProduct
+from repositories.fund_nav import FundNavRepo
+from repositories.product import ProductRepo
+from utils.exceptions import NotFoundError, ParamError
+
+
+def _to_item(p: FinProduct) -> dict:
+ """ORM → 响应 dict(Decimal 显式转 float,避免序列化歧义)。"""
+ return {
+ "id": p.id,
+ "product_code": p.product_code,
+ "product_name": p.product_name,
+ "product_type": p.product_type,
+ "risk_level": p.risk_level,
+ "expected_return": float(p.expected_return) if p.expected_return is not None else None,
+ "nav": float(p.nav) if p.nav is not None else None,
+ "nav_date": p.nav_date.isoformat() if p.nav_date else None,
+ "fee_rate": float(p.fee_rate),
+ "term_days": p.term_days,
+ "fund_manager": p.fund_manager,
+ "status": p.status,
+ # 不改表:交易方式标识由现有字段推导(status=在售 可购买;term_days=0 可定投)
+ "support_purchase": p.status == "在售",
+ "support_dca": p.term_days == 0,
+ }
+
+
+async def list_products(
+ db: AsyncSession,
+ *,
+ page: int = 1,
+ page_size: int = 10,
+ keyword: str | None = None,
+ product_type: str | None = None,
+ risk_level: str | None = None,
+ status: str = "在售",
+ sort_by: str = "create_time",
+ sort_order: str = "desc",
+) -> dict:
+ if page < 1:
+ raise ParamError("page 必须 >= 1")
+ if page_size < 1 or page_size > 100:
+ raise ParamError("page_size 必须在 1-100 之间")
+ if sort_order not in ("asc", "desc"):
+ raise ParamError("sort_order 仅支持 asc/desc")
+
+ items, total = await ProductRepo(db).search(
+ keyword=keyword,
+ product_type=product_type,
+ risk_level=risk_level,
+ status=status,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ limit=page_size,
+ offset=(page - 1) * page_size,
+ )
+ return {
+ "total": total,
+ "page": page,
+ "page_size": page_size,
+ "items": [_to_item(p) for p in items],
+ }
+
+
+def _calc_metrics(rows: list) -> dict:
+ """基于净值序列计算区间汇总指标(百分比)。
+
+ - total_growth_rate:总增长率 = 每天日增长率累加
+ - max_return_rate:区间最大收益率 = 从区间内最低点买入到其后最高点的最大涨幅
+ - max_drawdown_rate:区间最大回撤率 = 从区间内最高点回落到其后最低点的最大跌幅
+ """
+ total_growth = sum(
+ float(r.daily_growth) for r in rows if r.daily_growth is not None
+ )
+
+ peak = trough = float(rows[0].unit_nav)
+ max_return = max_drawdown = 0.0
+ for r in rows:
+ nav = float(r.unit_nav)
+ peak = max(peak, nav)
+ trough = min(trough, nav)
+ max_drawdown = max(max_drawdown, (peak - nav) / peak if peak else 0.0)
+ max_return = max(max_return, (nav - trough) / trough if trough else 0.0)
+
+ return {
+ "total_growth_rate": round(total_growth, 4),
+ "max_return_rate": round(max_return * 100, 4),
+ "max_drawdown_rate": round(max_drawdown * 100, 4),
+ }
+
+
+async def get_history(
+ db: AsyncSession,
+ product_code: str,
+ start_date: date | None = None,
+ end_date: date | None = None,
+ series: str = "nav",
+) -> dict:
+ if series not in ("nav", "return"):
+ raise ParamError("series 仅支持 nav/return")
+ if await ProductRepo(db).get_by_code(product_code) is None:
+ raise NotFoundError("基金产品不存在")
+
+ end = end_date or date.today()
+ start = start_date or (end - timedelta(days=90))
+ if start > end:
+ raise ParamError("start_date 不能晚于 end_date")
+
+ rows = await FundNavRepo(db).list_series(product_code, start, end)
+ if not rows:
+ return {
+ "product_code": product_code,
+ "series": series,
+ "total_growth_rate": 0.0,
+ "max_return_rate": 0.0,
+ "max_drawdown_rate": 0.0,
+ "items": [],
+ }
+
+ if series == "nav":
+ items = [
+ {
+ "nav_date": r.nav_date.isoformat(),
+ "unit_nav": float(r.unit_nav),
+ "accumulated_nav": float(r.accumulated_nav) if r.accumulated_nav is not None else None,
+ "daily_growth": float(r.daily_growth) if r.daily_growth is not None else None,
+ }
+ for r in rows
+ ]
+ else:
+ base = float(rows[0].unit_nav) # 区间首日为基准,累计收益实时从净值计算
+ items = [
+ {
+ "nav_date": r.nav_date.isoformat(),
+ "unit_nav": float(r.unit_nav),
+ "cum_return_pct": round((float(r.unit_nav) / base - 1) * 100, 4),
+ }
+ for r in rows
+ ]
+ metrics = _calc_metrics(rows)
+ return {
+ "product_code": product_code,
+ "series": series,
+ "total_growth_rate": metrics["total_growth_rate"],
+ "max_return_rate": metrics["max_return_rate"],
+ "max_drawdown_rate": metrics["max_drawdown_rate"],
+ "items": items,
+ }
diff --git a/service/questionnaire.py b/service/questionnaire.py
new file mode 100644
index 0000000..e1ec9e5
--- /dev/null
+++ b/service/questionnaire.py
@@ -0,0 +1,85 @@
+"""问卷服务:提交风险测评 → 完整性/选项校验 → 算分定级 → 落风评记录 → 回写画像。"""
+from __future__ import annotations
+
+from datetime import date, timedelta
+
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from model.fin_risk_assessment import FinRiskAssessment
+from repositories.questionnaire import QuestionRepo, QuestionnaireRepo
+from repositories.risk_assessment import CustomerProfileRepo, RiskAssessmentRepo
+from utils.exceptions import NotFoundError, ParamError
+
+# 分数 → 风险等级映射(总分 0-100,20 分一档;后续可迁移到 sys_config 运营化)
+_SCORE_LEVELS = (
+ (80, "激进"),
+ (60, "进取"),
+ (40, "平衡"),
+ (20, "稳健"),
+ (0, "保守"),
+)
+
+
+def _score_to_level(score: int) -> str:
+ for threshold, level in _SCORE_LEVELS:
+ if score >= threshold:
+ return level
+ return "保守"
+
+
+async def submit_assessment(
+ db: AsyncSession,
+ customer_id: int,
+ questionnaire_id: int,
+ answers: list[dict],
+) -> dict:
+ questionnaire = await QuestionnaireRepo(db).get(questionnaire_id)
+ if questionnaire is None:
+ raise NotFoundError("问卷不存在")
+ if questionnaire.status != "启用":
+ raise ParamError("问卷未启用")
+
+ questions = await QuestionRepo(db).list_by_questionnaire(questionnaire_id)
+ if not questions:
+ raise ParamError("问卷尚未配置题目")
+
+ # 提交答案按 question_no(题号)建索引,校验必填完整性与选项合法性
+ by_no = {a["question_no"]: a["option"] for a in answers}
+ total_score = 0
+ detail = []
+ for q in questions:
+ option = by_no.get(q.question_no)
+ if option is None:
+ raise ParamError(f"第{q.question_no}题未作答")
+ scores = q.score_json or {}
+ if option not in scores:
+ raise ParamError(f"第{q.question_no}题选项非法: {option}")
+ score = int(scores[option])
+ total_score += score
+ detail.append({"q": q.question_no, "a": option, "score": score})
+
+ risk_level = _score_to_level(total_score)
+ today = date.today()
+ valid_until = today + timedelta(days=365) # 监管要求一年一评
+
+ record = FinRiskAssessment(
+ customer_id=customer_id,
+ assessment_date=today,
+ question_version=questionnaire.version,
+ total_score=total_score,
+ risk_level=risk_level,
+ answers=detail,
+ assessor_type="AI评估",
+ valid_until=valid_until,
+ )
+ record = await RiskAssessmentRepo(db).add(record)
+
+ # 回写画像:无画像初始化,有画像更新风险等级/评分并递增版本号
+ await CustomerProfileRepo(db).upsert_risk(customer_id, risk_level, total_score)
+
+ return {
+ "assessment_id": record.id,
+ "total_score": total_score,
+ "risk_level": risk_level,
+ "valid_until": valid_until.isoformat(),
+ }