Coder Social home page Coder Social logo

bali-framework / bali Goto Github PK

View Code? Open in Web Editor NEW
248.0 4.0 30.0 1.5 MB

Simplify declarative cloud-native development base on FastAPI and gRPC. https://bali-framework.github.io/bali/

License: MIT License

Python 99.57% Dockerfile 0.43%
python fastapi grpc micorservices

bali's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

bali's Issues

在python3.12环境下安装bali失败

root@cartdrgdip:/app/pyfgserver# python3 --version
Python 3.12.3
root@cartdrgdip:/app/pyfgserver# pip install bali-core
WARNING: Skipping /usr/lib/python3.12/dist-packages/argcomplete-3.1.4.dist-info due to invalid metadata entry 'name'
Collecting bali-core
  Using cached bali_core-3.5.1-py3-none-any.whl.metadata (10 kB)
Collecting greenlet<=2.0.1,>1.0 (from bali-core)
  Using cached greenlet-2.0.1.tar.gz (163 kB)
  Preparing metadata (setup.py) ... done
Collecting aiomysql (from bali-core)
  Using cached aiomysql-0.2.0-py3-none-any.whl.metadata (11 kB)
Collecting aiosqlite (from bali-core)
  Using cached aiosqlite-0.20.0-py3-none-any.whl.metadata (4.3 kB)
Collecting dateparser>=1.1.0 (from bali-core)
  Using cached dateparser-1.2.0-py2.py3-none-any.whl.metadata (28 kB)
Collecting fastapi<=0.92,>=0.69.0 (from fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached fastapi-0.92.0-py3-none-any.whl.metadata (25 kB)
Collecting fastapi-migrate==0.1.1 (from bali-core)
  Using cached fastapi_migrate-0.1.1-py3-none-any.whl.metadata (425 bytes)
Collecting fastapi-pagination<=0.10,>=0.9.0 (from bali-core)
  Using cached fastapi_pagination-0.10.0-py3-none-any.whl.metadata (7.9 kB)
Collecting grpcio<=1.50.0,>=1.32.0 (from bali-core)
  Using cached grpcio-1.50.0.tar.gz (22.1 MB)
  Preparing metadata (setup.py) ... done
Collecting grpcio-tools<=1.50.0,>=1.32.0 (from bali-core)
  Using cached grpcio-tools-1.50.0.tar.gz (2.3 MB)
  Preparing metadata (setup.py) ... done
Collecting grpc-interceptor==0.15.0 (from bali-core)
  Using cached grpc_interceptor-0.15.0-py3-none-any.whl.metadata (7.4 kB)
Collecting importlib-metadata<5.0.0 (from bali-core)
  Using cached importlib_metadata-4.13.0-py3-none-any.whl.metadata (4.9 kB)
Collecting kombu<6.0,>=5.2.4 (from bali-core)
  Using cached kombu-5.3.7-py3-none-any.whl.metadata (3.1 kB)
Collecting MarkupSafe==2.0.1 (from bali-core)
  Using cached MarkupSafe-2.0.1-cp312-cp312-linux_x86_64.whl
Collecting PyMySQL<=1.0.2,>=0.9 (from bali-core)
  Using cached PyMySQL-1.0.2-py3-none-any.whl.metadata (5.1 kB)
Collecting passlib==1.7.2 (from passlib[bcrypt]==1.7.2->bali-core)
  Using cached passlib-1.7.2-py2.py3-none-any.whl.metadata (1.7 kB)
Collecting pillow<8.4,>=7.2.0 (from bali-core)
  Using cached Pillow-8.3.2.tar.gz (48.8 MB)
  Preparing metadata (setup.py) ... done
Collecting pydantic-sqlalchemy<1,>=0.0.7 (from bali-core)
  Using cached pydantic_sqlalchemy-0.0.9-py3-none-any.whl.metadata (6.1 kB)
Collecting pyhumps (from bali-core)
  Using cached pyhumps-3.8.0-py3-none-any.whl.metadata (4.0 kB)
Collecting pytz==2021.1 (from bali-core)
  Using cached pytz-2021.1-py2.py3-none-any.whl.metadata (21 kB)
Collecting redis<4.3,>=3.5.3 (from bali-core)
  Using cached redis-4.2.2-py3-none-any.whl.metadata (51 kB)
Collecting regex==2022.1.18 (from bali-core)
  Using cached regex-2022.1.18-cp312-cp312-linux_x86_64.whl
Collecting sqla-wrapper<5.6,>=5.0.0 (from bali-core)
  Using cached sqla_wrapper-5.5-py3-none-any.whl.metadata (2.7 kB)
Collecting typer>=0.4 (from bali-core)
  Using cached typer-0.12.3-py3-none-any.whl.metadata (15 kB)
Collecting alembic<2.0.0,>=1.4.2 (from fastapi-migrate==0.1.1->bali-core)
  Using cached alembic-1.13.2-py3-none-any.whl.metadata (7.4 kB)
Collecting click<8.0.0,>=7.1.2 (from fastapi-migrate==0.1.1->bali-core)
  Using cached click-7.1.2-py2.py3-none-any.whl.metadata (2.9 kB)
Requirement already satisfied: bcrypt>=3.1.0 in /usr/lib/python3/dist-packages (from passlib[bcrypt]==1.7.2->bali-core) (3.2.2)
Collecting python-dateutil (from dateparser>=1.1.0->bali-core)
  Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)
Collecting tzlocal (from dateparser>=1.1.0->bali-core)
  Using cached tzlocal-5.2-py3-none-any.whl.metadata (7.8 kB)
Collecting pydantic!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0,>=1.6.2 (from fastapi<=0.92,>=0.69.0->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached pydantic-1.10.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (151 kB)
Collecting starlette<0.26.0,>=0.25.0 (from fastapi<=0.92,>=0.69.0->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached starlette-0.25.0-py3-none-any.whl.metadata (5.8 kB)
Collecting email-validator>=1.1.1 (from fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached email_validator-2.2.0-py3-none-any.whl.metadata (25 kB)
Collecting httpx>=0.23.0 (from fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached httpx-0.27.0-py3-none-any.whl.metadata (7.2 kB)
Requirement already satisfied: itsdangerous>=1.1.0 in /usr/lib/python3.12/dist-packages (from fastapi[all]<=0.92,>=0.69.0->bali-core) (2.2.0)
Requirement already satisfied: jinja2>=2.11.2 in /usr/lib/python3/dist-packages (from fastapi[all]<=0.92,>=0.69.0->bali-core) (3.1.2)
Collecting orjson>=3.2.1 (from fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached orjson-3.10.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (50 kB)
Collecting python-multipart>=0.0.5 (from fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached python_multipart-0.0.9-py3-none-any.whl.metadata (2.5 kB)
Requirement already satisfied: pyyaml>=5.3.1 in /usr/lib/python3/dist-packages (from fastapi[all]<=0.92,>=0.69.0->bali-core) (6.0.1)
Collecting ujson!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,>=4.0.1 (from fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (9.3 kB)
Collecting uvicorn>=0.12.0 (from uvicorn[standard]>=0.12.0; extra == "all"->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached uvicorn-0.30.1-py3-none-any.whl.metadata (6.3 kB)
Requirement already satisfied: six>=1.5.2 in /usr/lib/python3/dist-packages (from grpcio<=1.50.0,>=1.32.0->bali-core) (1.16.0)
Collecting protobuf<5.0dev,>=4.21.6 (from grpcio-tools<=1.50.0,>=1.32.0->bali-core)
  Using cached protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl.metadata (541 bytes)
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from grpcio-tools<=1.50.0,>=1.32.0->bali-core) (68.1.2)
Collecting zipp>=0.5 (from importlib-metadata<5.0.0->bali-core)
  Using cached zipp-3.19.2-py3-none-any.whl.metadata (3.6 kB)
Collecting amqp<6.0.0,>=5.1.1 (from kombu<6.0,>=5.2.4->bali-core)
  Using cached amqp-5.2.0-py3-none-any.whl.metadata (8.9 kB)
Collecting vine (from kombu<6.0,>=5.2.4->bali-core)
  Using cached vine-5.1.0-py3-none-any.whl.metadata (2.7 kB)
Collecting sqlalchemy<2.0.0,>=1.3.16 (from pydantic-sqlalchemy<1,>=0.0.7->bali-core)
  Using cached SQLAlchemy-1.4.52-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (10 kB)
Collecting deprecated>=1.2.3 (from redis<4.3,>=3.5.3->bali-core)
  Using cached Deprecated-1.2.14-py2.py3-none-any.whl.metadata (5.4 kB)
Requirement already satisfied: packaging>=20.4 in /usr/lib/python3/dist-packages (from redis<4.3,>=3.5.3->bali-core) (24.0)
Collecting async-timeout>=4.0.2 (from redis<4.3,>=3.5.3->bali-core)
  Using cached async_timeout-4.0.3-py3-none-any.whl.metadata (4.2 kB)
INFO: pip is looking at multiple versions of typer to determine which version is compatible with other requirements. This could take a while.
Collecting typer>=0.4 (from bali-core)
  Using cached typer-0.12.2-py3-none-any.whl.metadata (15 kB)
  Using cached typer-0.12.1-py3-none-any.whl.metadata (15 kB)
  Using cached typer-0.12.0-py3-none-any.whl.metadata (15 kB)
Collecting typer-slim==0.12.0 (from typer-slim[standard]==0.12.0->typer>=0.4->bali-core)
  Using cached typer_slim-0.12.0-py3-none-any.whl.metadata (15 kB)
Collecting typer-cli==0.12.0 (from typer>=0.4->bali-core)
  Using cached typer_cli-0.12.0-py3-none-any.whl.metadata (3.5 kB)
INFO: pip is looking at multiple versions of typer-slim to determine which version is compatible with other requirements. This could take a while.
Collecting typer>=0.4 (from bali-core)
  Using cached typer-0.11.1-py3-none-any.whl.metadata (13 kB)
  Using cached typer-0.11.0-py3-none-any.whl.metadata (13 kB)
INFO: pip is still looking at multiple versions of typer to determine which version is compatible with other requirements. This could take a while.
  Using cached typer-0.10.0-py3-none-any.whl.metadata (14 kB)
Collecting typing-extensions>=3.7.4.3 (from typer>=0.4->bali-core)
  Using cached typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB)
Collecting Mako (from alembic<2.0.0,>=1.4.2->fastapi-migrate==0.1.1->bali-core)
  Using cached Mako-1.3.5-py3-none-any.whl.metadata (2.9 kB)
Collecting wrapt<2,>=1.10 (from deprecated>=1.2.3->redis<4.3,>=3.5.3->bali-core)
  Using cached wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)
Collecting dnspython>=2.0.0 (from email-validator>=1.1.1->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached dnspython-2.6.1-py3-none-any.whl.metadata (5.8 kB)
Requirement already satisfied: idna>=2.0.0 in /usr/lib/python3/dist-packages (from email-validator>=1.1.1->fastapi[all]<=0.92,>=0.69.0->bali-core) (3.6)
Collecting anyio (from httpx>=0.23.0->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached anyio-4.4.0-py3-none-any.whl.metadata (4.6 kB)
Requirement already satisfied: certifi in /usr/lib/python3/dist-packages (from httpx>=0.23.0->fastapi[all]<=0.92,>=0.69.0->bali-core) (2023.11.17)
Collecting httpcore==1.* (from httpx>=0.23.0->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached httpcore-1.0.5-py3-none-any.whl.metadata (20 kB)
Collecting sniffio (from httpx>=0.23.0->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached sniffio-1.3.1-py3-none-any.whl.metadata (3.9 kB)
Collecting h11<0.15,>=0.13 (from httpcore==1.*->httpx>=0.23.0->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)
Collecting httptools>=0.5.0 (from uvicorn[standard]>=0.12.0; extra == "all"->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.6 kB)
Collecting python-dotenv>=0.13 (from uvicorn[standard]>=0.12.0; extra == "all"->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)
Collecting uvloop!=0.15.0,!=0.15.1,>=0.14.0 (from uvicorn[standard]>=0.12.0; extra == "all"->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.9 kB)
Collecting watchfiles>=0.13 (from uvicorn[standard]>=0.12.0; extra == "all"->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.9 kB)
Collecting websockets>=10.4 (from uvicorn[standard]>=0.12.0; extra == "all"->fastapi[all]<=0.92,>=0.69.0->bali-core)
  Using cached websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)
Using cached bali_core-3.5.1-py3-none-any.whl (47 kB)
Using cached fastapi_migrate-0.1.1-py3-none-any.whl (8.0 kB)
Using cached grpc_interceptor-0.15.0-py3-none-any.whl (20 kB)
Using cached passlib-1.7.2-py2.py3-none-any.whl (507 kB)
Using cached pytz-2021.1-py2.py3-none-any.whl (510 kB)
Using cached dateparser-1.2.0-py2.py3-none-any.whl (294 kB)
Using cached fastapi-0.92.0-py3-none-any.whl (56 kB)
Using cached fastapi_pagination-0.10.0-py3-none-any.whl (21 kB)
Using cached importlib_metadata-4.13.0-py3-none-any.whl (23 kB)
Using cached kombu-5.3.7-py3-none-any.whl (200 kB)
Using cached pydantic_sqlalchemy-0.0.9-py3-none-any.whl (4.5 kB)
Using cached PyMySQL-1.0.2-py3-none-any.whl (43 kB)
Using cached redis-4.2.2-py3-none-any.whl (226 kB)
Using cached sqla_wrapper-5.5-py3-none-any.whl (16 kB)
Using cached click-7.1.2-py2.py3-none-any.whl (82 kB)
Using cached typer-0.10.0-py3-none-any.whl (46 kB)
Using cached aiomysql-0.2.0-py3-none-any.whl (44 kB)
Using cached aiosqlite-0.20.0-py3-none-any.whl (15 kB)
Using cached pyhumps-3.8.0-py3-none-any.whl (6.1 kB)
Using cached alembic-1.13.2-py3-none-any.whl (232 kB)
Using cached amqp-5.2.0-py3-none-any.whl (50 kB)
Using cached async_timeout-4.0.3-py3-none-any.whl (5.7 kB)
Using cached Deprecated-1.2.14-py2.py3-none-any.whl (9.6 kB)
Using cached email_validator-2.2.0-py3-none-any.whl (33 kB)
Using cached httpx-0.27.0-py3-none-any.whl (75 kB)
Using cached httpcore-1.0.5-py3-none-any.whl (77 kB)
Using cached orjson-3.10.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (141 kB)
Using cached protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl (294 kB)
Using cached pydantic-1.10.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB)
Using cached python_multipart-0.0.9-py3-none-any.whl (22 kB)
Using cached SQLAlchemy-1.4.52-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB)
Using cached starlette-0.25.0-py3-none-any.whl (66 kB)
Using cached typing_extensions-4.12.2-py3-none-any.whl (37 kB)
Using cached ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (53 kB)
Using cached uvicorn-0.30.1-py3-none-any.whl (62 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached zipp-3.19.2-py3-none-any.whl (9.0 kB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached tzlocal-5.2-py3-none-any.whl (17 kB)
Using cached anyio-4.4.0-py3-none-any.whl (86 kB)
Using cached dnspython-2.6.1-py3-none-any.whl (307 kB)
Using cached h11-0.14.0-py3-none-any.whl (58 kB)
Using cached httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (344 kB)
Using cached python_dotenv-1.0.1-py3-none-any.whl (19 kB)
Using cached sniffio-1.3.1-py3-none-any.whl (10 kB)
Using cached uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.2 MB)
Using cached watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB)
Using cached websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (131 kB)
Using cached wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (87 kB)
Using cached Mako-1.3.5-py3-none-any.whl (78 kB)
Building wheels for collected packages: greenlet, grpcio, grpcio-tools, pillow
  Building wheel for greenlet (setup.py) ... error
  error: subprocess-exited-with-error
  
  × python setup.py bdist_wheel did not run successfully.
  │ exit code: 1
  ╰─> [158 lines of output]
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.linux-x86_64-cpython-312
      creating build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/__init__.py -> build/lib.linux-x86_64-cpython-312/greenlet
      creating build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/__init__.py -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      creating build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_generator.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_greenlet.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_throw.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/__init__.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_gc.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_cpp.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_generator_nested.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/leakcheck.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_stack_saved.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_contextvars.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_version.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_greenlet_trash.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_extension_interface.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_weakref.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_leaks.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/test_tracing.py -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      running egg_info
      writing src/greenlet.egg-info/PKG-INFO
      writing dependency_links to src/greenlet.egg-info/dependency_links.txt
      writing requirements to src/greenlet.egg-info/requires.txt
      writing top-level names to src/greenlet.egg-info/top_level.txt
      reading manifest file 'src/greenlet.egg-info/SOURCES.txt'
      reading manifest template 'MANIFEST.in'
      warning: no previously-included files found matching 'benchmarks/*.json'
      no previously-included directories found matching 'docs/_build'
      warning: no files found matching '*.py' under directory 'appveyor'
      warning: no previously-included files matching '*.pyc' found anywhere in distribution
      warning: no previously-included files matching '*.pyd' found anywhere in distribution
      warning: no previously-included files matching '*.so' found anywhere in distribution
      warning: no previously-included files matching '.coverage' found anywhere in distribution
      adding license file 'LICENSE'
      adding license file 'LICENSE.PSF'
      adding license file 'AUTHORS'
      writing manifest file 'src/greenlet.egg-info/SOURCES.txt'
      copying src/greenlet/greenlet.cpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet.h -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_allocator.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_compiler_compat.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_cpython_compat.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_exceptions.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_greenlet.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_internal.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_refs.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_slp_switch.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_thread_state.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_thread_state_dict_cleanup.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/greenlet_thread_support.hpp -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/slp_platformselect.h -> build/lib.linux-x86_64-cpython-312/greenlet
      copying src/greenlet/platform/setup_switch_x64_masm.cmd -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_aarch64_gcc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_alpha_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_amd64_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_arm32_gcc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_arm32_ios.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_arm64_masm.asm -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_arm64_masm.obj -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_arm64_msvc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_csky_gcc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_m68k_gcc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_mips_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_ppc64_aix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_ppc64_linux.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_ppc_aix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_ppc_linux.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_ppc_macosx.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_ppc_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_riscv_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_s390_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_sparc_sun_gcc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_x32_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_x64_masm.asm -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_x64_masm.obj -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_x64_msvc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_x86_msvc.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/platform/switch_x86_unix.h -> build/lib.linux-x86_64-cpython-312/greenlet/platform
      copying src/greenlet/tests/_test_extension.c -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      copying src/greenlet/tests/_test_extension_cpp.cpp -> build/lib.linux-x86_64-cpython-312/greenlet/tests
      running build_ext
      building 'greenlet._greenlet' extension
      creating build/temp.linux-x86_64-cpython-312
      creating build/temp.linux-x86_64-cpython-312/src
      creating build/temp.linux-x86_64-cpython-312/src/greenlet
      x86_64-linux-gnu-gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O2 -Wall -fPIC -I/usr/include/python3.12 -c src/greenlet/greenlet.cpp -o build/temp.linux-x86_64-cpython-312/src/greenlet/greenlet.o
      In file included from src/greenlet/greenlet_internal.hpp:20,
                       from src/greenlet/greenlet.cpp:19:
      src/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::operator<<(const PyThreadState*)’:
      src/greenlet/greenlet_greenlet.hpp:831:41: error: ‘_PyCFrame’ {aka ‘struct _PyCFrame’} has no member named ‘use_tracing’
        831 |     this->use_tracing = tstate->cframe->use_tracing;
            |                                         ^~~~~~~~~~~
      src/greenlet/greenlet_greenlet.hpp:834:37: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_limit’; did you mean ‘py_recursion_limit’?
        834 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
            |                                     ^~~~~~~~~~~~~~~
            |                                     py_recursion_limit
      src/greenlet/greenlet_greenlet.hpp:834:63: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_remaining’; did you mean ‘c_recursion_remaining’?
        834 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
            |                                                               ^~~~~~~~~~~~~~~~~~~
            |                                                               c_recursion_remaining
      src/greenlet/greenlet_greenlet.hpp:848:42: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘trash_delete_nesting’
        848 |     this->trash_delete_nesting = tstate->trash_delete_nesting;
            |                                          ^~~~~~~~~~~~~~~~~~~~
      src/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::operator>>(PyThreadState*)’:
      src/greenlet/greenlet_greenlet.hpp:867:21: error: ‘_PyCFrame’ {aka ‘struct _PyCFrame’} has no member named ‘use_tracing’
        867 |     tstate->cframe->use_tracing = this->use_tracing;
            |                     ^~~~~~~~~~~
      src/greenlet/greenlet_greenlet.hpp:870:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘recursion_remaining’; did you mean ‘c_recursion_remaining’?
        870 |     tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;
            |             ^~~~~~~~~~~~~~~~~~~
            |             c_recursion_remaining
      src/greenlet/greenlet_greenlet.hpp:870:43: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘recursion_limit’; did you mean ‘py_recursion_limit’?
        870 |     tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;
            |                                           ^~~~~~~~~~~~~~~
            |                                           py_recursion_limit
      src/greenlet/greenlet_greenlet.hpp:881:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘trash_delete_nesting’
        881 |     tstate->trash_delete_nesting = this->trash_delete_nesting;
            |             ^~~~~~~~~~~~~~~~~~~~
      src/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::will_switch_from(PyThreadState*)’:
      src/greenlet/greenlet_greenlet.hpp:891:48: error: ‘_PyCFrame’ {aka ‘struct _PyCFrame’} has no member named ‘use_tracing’
        891 |     this->use_tracing = origin_tstate->cframe->use_tracing;
            |                                                ^~~~~~~~~~~
      src/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::set_initial_state(const PyThreadState*)’:
      src/greenlet/greenlet_greenlet.hpp:899:37: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_limit’; did you mean ‘py_recursion_limit’?
        899 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
            |                                     ^~~~~~~~~~~~~~~
            |                                     py_recursion_limit
      src/greenlet/greenlet_greenlet.hpp:899:63: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_remaining’; did you mean ‘c_recursion_remaining’?
        899 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
            |                                                               ^~~~~~~~~~~~~~~~~~~
            |                                                               c_recursion_remaining
      In file included from /usr/include/c++/13/ext/alloc_traits.h:34,
                       from /usr/include/c++/13/bits/basic_string.h:39,
                       from /usr/include/c++/13/string:54,
                       from src/greenlet/greenlet.cpp:10:
      /usr/include/c++/13/bits/alloc_traits.h: In instantiation of ‘struct std::__allocator_traits_base::__rebind<greenlet::PythonAllocator<_greenlet*>, _greenlet*, void>’:
      /usr/include/c++/13/bits/alloc_traits.h:94:11:   required by substitution of ‘template<class _Alloc, class _Up> using std::__alloc_rebind = typename std::__allocator_traits_base::__rebind<_Alloc, _Up>::type [with _Alloc = greenlet::PythonAllocator<_greenlet*>; _Up = _greenlet*]’
      /usr/include/c++/13/bits/alloc_traits.h:228:8:   required by substitution of ‘template<class _Alloc> template<class _Tp> using std::allocator_traits< <template-parameter-1-1> >::rebind_alloc = std::__alloc_rebind<_Alloc, _Tp> [with _Tp = _greenlet*; _Alloc = greenlet::PythonAllocator<_greenlet*>]’
      /usr/include/c++/13/ext/alloc_traits.h:126:65:   required from ‘struct __gnu_cxx::__alloc_traits<greenlet::PythonAllocator<_greenlet*>, _greenlet*>::rebind<_greenlet*>’
      /usr/include/c++/13/bits/stl_vector.h:88:21:   required from ‘struct std::_Vector_base<_greenlet*, greenlet::PythonAllocator<_greenlet*> >’
      /usr/include/c++/13/bits/stl_vector.h:428:11:   required from ‘class std::vector<_greenlet*, greenlet::PythonAllocator<_greenlet*> >’
      src/greenlet/greenlet_thread_state.hpp:115:16:   required from here
      /usr/include/c++/13/bits/alloc_traits.h:70:31: error: static assertion failed: allocator_traits<A>::rebind_alloc<A::value_type> must be A
         70 |                         _Tp>::value,
            |                               ^~~~~
      /usr/include/c++/13/bits/alloc_traits.h:70:31: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
      src/greenlet/greenlet.cpp: In function ‘PyObject* mod_get_tstate_trash_delete_nesting(PyObject*)’:
      src/greenlet/greenlet.cpp:3090:36: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘trash_delete_nesting’
       3090 |     return PyLong_FromLong(tstate->trash_delete_nesting);
            |                                    ^~~~~~~~~~~~~~~~~~~~
      error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for greenlet
  Running setup.py clean for greenlet

install failed

python version: 3.9.2
pip version: 22.0.4

ERROR: Could not build wheels for ujson, which is required to install pyproject.toml-based projects

Is necessary for 'fastapi[all]' in requirement.txt

我怎样去修改Resource中自定义action的response.status_code

我似乎并不能像fastapi示例那样直接在函数上加上response对象

@app.put("/get-or-create-task/{task_id}", status_code=200)
def get_or_create_task(task_id: str, response: Response):
    if task_id not in tasks:
        tasks[task_id] = "This didn't exist before"
        response.status_code = status.HTTP_201_CREATED
    return tasks[task_id]

如果加上了response对象参数,发送接口时会提示缺少response关键字参数,这在重写ModelResource的方法时应该也会遇到;而且似乎Resource是无法使用fastapi中的Depends这个十分方便的特性,想问下是不是除了基础的crud,其他的api其实还是需要fastapi原生的方法来写,比如上传下载文件之类的,然后include_router到_app.routes里?
说到这边还有个疑问,Resource/ModelResource怎样和APIRoute配合形成类似flask和sanic中blueprint的效果?

Added cache api

from bali.core import cache

# Usage example (API)

# Read cache 
cache.get(key)

# Set cache 
cache.set(key, value, timeout=10)

How to create a background task in gRPC service

As FastAPI docs metioned, backgroud task could been added using background_tasks.add_task:

https://fastapi.tiangolo.com/tutorial/background-tasks/.

@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(write_notification, email, message="some notification")
    return {"message": "Notification sent in the background"}

But how to create a background task in gRPC service's RPC?

Dependencies updates

The following packages should been updated:
grpcio
pillow
pydantic-sqlalchemy
sqla-wrapper
SQLAlchemy
typer

Permission

Permission must defined in resource.permission_class

class GreeterResource(Resource):

    schema = Greeter

    permission_class = {
         "get": IsAdmin,
    }

All actions using same permission class

class GreeterResource(Resource):

    schema = Greeter

    permission_class = [IsAdmin,]

The permission class will return a boolean result to determine whether the request is allowed, and will fill in request.user infos

logging out of the box

image

Now we have a logging configuration file in projects.

It's complex to setting up logging.

Updated PYTHONPATH

I added the following path to PYTHONPATH manually in the Dockerfile

ENV PYTHONPATH="$PYTHONPATH:/finance"
ENV PYTHONPATH="$PYTHONPATH:/finance/clients"
ENV PYTHONPATH="$PYTHONPATH:/finance/clients/auth"
ENV PYTHONPATH="$PYTHONPATH:/finance/clients/user"
ENV PYTHONPATH="$PYTHONPATH:/finance/services/rpc"

Now we need it included in bali initialized period.

Enhanced configuration

  • 1. Store config in the environment

According to 12 factor's config specification. Our configuration still in python code.

image

We need to enhance it using environment or dotenv.

  • 2. Optimized the stage template code

image

Feature: `Bali.register()` - support separate registration of `HTTP Router` and `RPC Service`

Feature:

  • Add custom parameters that allow separate registration of HTTP Router and RPC Service.

Background:

  • When you use the router to add a routing prefix and then continue to register the resource with app.register(), duplicate HTTP API registrations occur.
  • So I think it is necessary to add parameters in the app.register() method, allow only registering rpc_service, skip registering http router.

here:

fix:

  • add http=True, rpc=True.
@singleton
class Bali:

    ...

    def register(self, resources_cls, http=True, rpc=True):
        if not isinstance(resources_cls, list):
            resources_cls = [resources_cls]

        for resource_cls in resources_cls:
            # Register HTTP service
            if http:
                  self._app.include_router(
                      router=resource_cls.as_router(),
                      prefix=resource_cls._http_endpoint,
                  )

            # Register RPC service
            if rpc and self._rpc_servicer:
                resource_cls.as_servicer(self)

        if http:
            add_pagination(self._app)

usage:

  • after fix, usage:
from bali.application import Bali

from proto.config import settings
from internal.router import router_v1
from internal.event.event import EventHandler
from internal.resource import TodoResource

app = Bali(
    base_settings=None,
    title=settings.SERVER_NAME,
    routers=[{
        'router': router_v1,  
        # 'prefix': '/v1',
    }],
    backend_cors_origins=['http://127.0.0.1'],  # ["*"]
    # rpc_service=grpc_server_async,
    event_handler=EventHandler
)

# 
# 
# 
app.register(TodoResource, http=false)  # fix here!

if __name__ == "__main__":
    app.start()

Design a ModelAPI for gRPC View

An base class include "Create" "List" "Retrieve" "Update" "Destroy" methods. Subclasses complete business logic through declarative style like "rest_framework" did.

cache memoize enabled

Need a cache memoize feature according django-cache-memoize https://pypi.org/project/django-cache-memoize/

# Import the cache_memoize from bali core 
from bali.core import cache_memoize

# Attach decorator to cacheable function with a timeout of 100 seconds.
@cache_memoize(100)
def expensive_function(start, end):
    return random.randint(start, end)

关于 MySQL 连接失效的问题

sqlalchemy 有三个 配置 可能可以帮助解决问题。具体的设置值还需要更多资料和实践支持:

增加连接池内连接数
:param pool_size=5: the number of connections to keep open
inside the connection pool. This used with
:class:~sqlalchemy.pool.QueuePool as
well as :class:~sqlalchemy.pool.SingletonThreadPool. With
:class:~sqlalchemy.pool.QueuePool, a pool_size setting
of 0 indicates no limit; to disable pooling, set poolclass to
:class:~sqlalchemy.pool.NullPool instead.

定期完全重置连接池
:param pool_recycle=-1: this setting causes the pool to recycle
connections after the given number of seconds has passed. It
defaults to -1, or no timeout. For example, setting to 3600
means connections will be recycled after one hour. Note that
MySQL in particular will disconnect automatically if no
activity is detected on a connection for eight hours (although
this is configurable with the MySQLDB connection itself and the
server configuration as well).

连接前进行 " 预 ping "(在直接使用 pymysql 编程的场景下,它是一种可以工作的策略,尚不清楚对运行中的事务的影响)
:param pool_pre_ping: boolean, if True will enable the connection pool
"pre-ping" feature that tests connections for liveness upon
each checkout.

打开openapi页面时有的sqlalchemy转换报错

python: 3.10.4
bali-core: 3.2.2
app.register注册含有这个的ModelResource类

class Permission(BaseMixin, db.BaseModel):  # type: ignore
    table_comment = "权限表"
    name_doc = "权限名称"
    description_doc = "权限描述"
    module_doc = "所属模块"

    name: str = db.Column(db.String(120), doc=name_doc,
                          comment=name_doc, nullable=False)
    description: str = db.Column(
        db.Text(500), doc=description_doc, comment=description_doc)
    permission_role: 'Permission' = db.relationship(
        'GroupRole', back_populates='permission')
    permission_roles = association_proxy('permission_role', 'role')
    permission_role_ids = association_proxy('permission_role', 'role_id')
    module_id: int = db.Column(db.ForeignKey(
        't_module.id'), doc=module_doc, comment=module_doc)

打开swagger就会报错

INFO:     127.0.0.1:60036 - "GET /openapi.json HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 376, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\bali\application.py", line 71, in __call__
    await self._app.__call__(scope, receive, send)  # pragma: no cover
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\fastapi\applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
    raise exc
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    raise exc
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__
    raise e
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\starlette\routing.py", line 61, in app
    response = await func(request)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\fastapi\applications.py", line 216, in openapi
    return JSONResponse(self.openapi())
  File "C:\Users\Administrator\PycharmProjects\test_platform\backend\main.py", line 56, in custom_openapi
    openapi_schema = get_openapi(
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\fastapi\openapi\utils.py", line 418, in get_openapi
    definitions = get_model_definitions(
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\fastapi\utils.py", line 29, in get_model_definitions
    m_schema, m_definitions, m_nested_models = model_process_schema(
  File "pydantic\schema.py", line 580, in pydantic.schema.model_process_schema
  File "pydantic\schema.py", line 621, in pydantic.schema.model_type_schema
  File "pydantic\schema.py", line 254, in pydantic.schema.field_schema
  File "pydantic\schema.py", line 461, in pydantic.schema.field_type_schema
  File "pydantic\schema.py", line 847, in pydantic.schema.field_singleton_schema
  File "pydantic\schema.py", line 698, in pydantic.schema.field_singleton_sub_fields_schema
  File "pydantic\schema.py", line 526, in pydantic.schema.field_type_schema
  File "pydantic\schema.py", line 921, in pydantic.schema.field_singleton_schema
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
TypeError: issubclass() arg 1 must be a class

像如下的model就不会,看上去似乎没有什么区别

class Tag(BaseMixin, db.BaseModel):  # type: ignore
    table_comment = "标签表"
    name_doc = "标签名称"
    color_doc = "标签颜色"
    tag_type_doc = "标签类型"
    description_doc = "标签描述"

    name: str = db.Column(db.String(120), doc=name_doc,
                          comment=name_doc, nullable=False)
    color: str = db.Column(db.String(120), doc=color_doc, comment=color_doc)
    tag_type: int = db.Column(
        db.Integer, doc=tag_type_doc, comment=tag_type_doc, default=get_tag_enum)
    description: str = db.Column(
        db.Text(500), doc=description_doc, comment=description_doc)
    tag_project: 'ProjectInfo' = db.relationship(
        'ProjectTag', back_populates='tag', lazy='selectin', join_depth=2)
    tag_projects = association_proxy('tag_project', 'project')
    tag_project_ids = association_proxy('tag_project', 'project_id')
    tag_testcase_site: 'TestcaseSite' = db.relationship(
        'TestcaseSiteTag', back_populates='tag', lazy='selectin', join_depth=2)
    tag_testcase_sites = association_proxy(
        'tag_testcase_site', 'testcase_site')
    tag_testcase_site_ids = association_proxy(
        'tag_testcase_site', 'testcase_site_id')
    tag_testcase: 'Testcase' = db.relationship(
        'TestcaseTag', back_populates='tag', lazy='selectin', join_depth=2)
    tag_testcases = association_proxy('tag_testcase', 'testcase')
    tag_testcase_ids = association_proxy('tag_testcase', 'testcase_id')

并且from bali.schemas import model_to_schema这个函数转化有关系字段的模型(relationship/association_proxy)也有问题

Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\clsregistry.py", line 393, in _resolve_name
    rval = d[token]
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\util\_collections.py", line 746, in __missing__
    self[key] = val = self.creator(key)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\clsregistry.py", line 372, in _access_cls
    return self.fallback[key]
KeyError: 'ProjectMaster'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Administrator\PycharmProjects\test_platform\backend\main.py", line 13, in <module>
    from app.system.view import (
  File "C:\Users\Administrator\PycharmProjects\test_platform\backend\app\system\view.py", line 11, in <module>
    from app.system.schema import (
  File "C:\Users\Administrator\PycharmProjects\test_platform\backend\app\system\schema.py", line 15, in <module>
    _UserSchema = model_to_schema(User)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\bali\schemas\__init__.py", line 25, in model_to_schema
    for attr in mapper.attrs:
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\util\langhelpers.py", line 1184, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\mapper.py", line 2488, in attrs
    self._check_configure()
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\mapper.py", line 1924, in _check_configure
    _configure_registries({self.registry}, cascade=True)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\mapper.py", line 3483, in _configure_registries
    _do_configure_registries(registries, cascade)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\mapper.py", line 3522, in _do_configure_registries
    mapper._post_configure_properties()
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\mapper.py", line 1941, in _post_configure_properties
    prop.init()
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\interfaces.py", line 231, in init
    self.do_init()
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\relationships.py", line 2145, in do_init
    self._process_dependent_arguments()
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\relationships.py", line 2240, in _process_dependent_arguments
    self.target = self.entity.persist_selectable
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\util\langhelpers.py", line 1113, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\relationships.py", line 2107, in entity
    argument = self._clsregistry_resolve_name(self.argument)()
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\clsregistry.py", line 397, in _resolve_name
    self._raise_for_name(name, err)
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\orm\clsregistry.py", line 375, in _raise_for_name
    util.raise_(
  File "C:\ProgramData\Anaconda3\envs\test_platform\lib\site-packages\sqlalchemy\util\compat.py", line 208, in raise_
    raise exception
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class User->t_user, expression 'ProjectMaster' failed to locate a name ('ProjectMaster'). If this is a class name, consider adding this relationship() to the <class 'app.system.model.User'> class after both dependent classes have been defined.     

由于无法使用model_to_schema,所以我直接使用的pydantic.BaseModel去定义的schema

class ModelSerializer(BaseModel):
    created_time: datetime | None
    updated_time: datetime | None
    id: int | None

    class Config:
        orm_mode = True
        fields = {'is_active': {'exclude': True}}
        anystr_strip_whitespace = True
        max_anystr_length = 120
        arbitrary_types_allowed = True

    @classmethod
    def from_orm(cls: Type, obj: Any) -> ModelSerializer:
        # 用来主动调用from_orm datetime->str
        original = super().from_orm(obj)
        for k, v in original.__fields__.items():
            if v.type_ == datetime:
                original.__dict__[k] = original.__dict__[k].strftime(settings.DATETIME_FORMAT)
        return original

class PermissionSchema(ModelSerializer):
    name: constr(min_length=2)
    description: constr()
    permission_roles: list['Role'] | None
    permission_role_ids: list[int] | None
    module_id: int


class TagSchema(ModelSerializer):
    name: constr(min_length=2)
    color: constr(min_length=2)
    tag_type: int
    description: constr()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.