prisma-client-py
prisma-client-py copied to clipboard
Add Support for async requests or http3 Async Client
Bug description
Prisma internals do not support async requests client or http3 protocol for making async requests to external APIs and other fastapi endpoints.
How to reproduce
from fastapi import FastAPI
from pydantic import BaseModel
import http3
class HealthResponse(BaseModel):
status: str
app = FastAPI()
@router.get("/users")
async def list_all_users():
async with Prisma() as db:
users = await db.user.find_many(take=1)
return users
@app.get("/health", response_model=HealthResponse, tags=["Health"])
async def check_health():
client = http3.AsyncClient()
response = await client.get("http://localhost:8000/users")
if response.status_code == 200:
return {"status": "healthy"}
return {"status": "unhealthy"}
Expected behavior
The engine connection should work with async requests.
Reinstalling h11 to lower version that prisma supports fix the errors for now.
Prisma information
generator client {
provider = "prisma-client-py"
interface = "asyncio"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum Role {
USER
ADMIN
}
model User {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
email String @unique
password Bytes
disabled Boolean @default(false)
role Role @default(USER)
}
Environment & setup
[tool.poetry]
name = "backend"
version = "1.0.0"
description = ""
authors = ["Ali Parandeh <[email protected]>"]
[tool.poetry.dependencies]
python = "^3.9"
fastapi = "^0.79.0"
prisma = "^0.6.6"
SQLAlchemy = "^1.4.40"
uvicorn = "^0.18.2"
black = "^22.6.0"
python-multipart = "^0.0.5"
bcrypt = "^3.2.2"
aiohttp = "^3.8.1"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
- OS: MacOS Monterey
- Database: PostgreSQL
- Python version: 3.9.10
- Prisma version: ^0.6.6
ERROR
Because httpx (0.23.0) depends on httpcore (>=0.15.0,<0.16.0)
and httpx (0.22.0) depends on httpcore (>=0.14.5,<0.15.0), httpx (0.22.0 || 0.23.0) requires httpcore (>=0.14.5,<0.16.0).
And because httpx (0.21.3) depends on httpcore (>=0.14.0,<0.15.0), httpx (0.21.3 || 0.22.0 || 0.23.0) requires httpcore (>=0.14.0,<0.16.0).
And because httpx (0.21.2) depends on httpcore (>=0.14.0,<0.15.0)
and httpx (0.21.1) depends on httpcore (>=0.14.0,<0.15.0), httpx (0.21.1 || 0.21.2 || 0.21.3 || 0.22.0 || 0.23.0) requires httpcore (>=0.14.0,<0.16.0).
And because httpx (0.21.0) depends on httpcore (>=0.14.0,<0.15.0)
and httpx (0.20.0) depends on httpcore (>=0.13.3,<0.14.0), httpx (0.20.0 || 0.21.0 || 0.21.1 || 0.21.2 || 0.21.3 || 0.22.0 || 0.23.0) requires httpcore (>=0.13.3,<0.16.0).
Because httpx (0.19.0) depends on httpcore (>=0.13.3,<0.14.0)
and no versions of httpx match >0.19.0,<0.20.0 || >0.20.0,<0.21.0 || >0.21.0,<0.21.1 || >0.21.1,<0.21.2 || >0.21.2,<0.21.3 || >0.21.3,<0.22.0 || >0.22.0,<0.23.0 || >0.23.0, httpx (>=0.19.0,<0.20.0 || >0.20.0,<0.21.0 || >0.21.0,<0.21.1 || >0.21.1,<0.21.2 || >0.21.2,<0.21.3 || >0.21.3,<0.22.0 || >0.22.0,<0.23.0 || >0.23.0) requires httpcore (>=0.13.3,<0.14.0).
Thus, httpx (>=0.19.0) requires httpcore (>=0.13.3,<0.16.0).
Because httpcore (0.15.0) depends on h11 (>=0.11,<0.13)
and no versions of httpcore match >0.15.0,<0.16.0, httpcore (>=0.15.0,<0.16.0) requires h11 (>=0.11,<0.13).
(1) Thus, httpx (>=0.19.0) requires h11 (>=0.11,<0.13) or httpcore (>=0.13.3,<0.15.0).
Because no versions of httpcore match >0.14.5,<0.14.6 || >0.14.6,<0.14.7 || >0.14.7,<0.15.0
and httpcore (0.14.5) depends on h11 (>=0.11,<0.13), httpcore (>=0.14.5,<0.14.6 || >0.14.6,<0.14.7 || >0.14.7,<0.15.0) requires h11 (>=0.11,<0.13).
And because httpcore (0.14.6) depends on h11 (>=0.11,<0.13)
and httpcore (0.14.7) depends on h11 (>=0.11,<0.13), httpcore (>=0.14.5,<0.15.0) requires h11 (>=0.11,<0.13).
(2) So, because httpx (>=0.19.0) requires h11 (>=0.11,<0.13) or httpcore (>=0.13.3,<0.15.0) (1), httpx (>=0.19.0) requires h11 (>=0.11,<0.13) or httpcore (>=0.13.3,<0.14.5)
Because no versions of httpcore match >0.14.0,<0.14.1 || >0.14.1,<0.14.2 || >0.14.2,<0.14.3 || >0.14.3,<0.14.4 || >0.14.4,<0.14.5
and httpcore (0.14.0) depends on h11 (>=0.11,<0.13), httpcore (>=0.14.0,<0.14.1 || >0.14.1,<0.14.2 || >0.14.2,<0.14.3 || >0.14.3,<0.14.4 || >0.14.4,<0.14.5) requires h11 (>=0.11,<0.13).
And because httpcore (0.14.1) depends on h11 (>=0.11,<0.13)
and httpcore (0.14.2) depends on h11 (>=0.11,<0.13), httpcore (>=0.14.0,<0.14.3 || >0.14.3,<0.14.4 || >0.14.4,<0.14.5) requires h11 (>=0.11,<0.13).
And because httpcore (0.14.3) depends on h11 (>=0.11,<0.13)
and httpcore (0.14.4) depends on h11 (>=0.11,<0.13), httpcore (>=0.14.0,<0.14.5) requires h11 (>=0.11,<0.13).
(3) So, because httpx (>=0.19.0) requires h11 (>=0.11,<0.13) or httpcore (>=0.13.3,<0.14.5) (2), httpx (>=0.19.0) requires h11 (>=0.11,<0.13) or httpcore (>=0.13.3,<0.14.0)
Because no versions of httpcore match >0.13.3,<0.13.4 || >0.13.4,<0.13.5 || >0.13.5,<0.13.6 || >0.13.6,<0.13.7 || >0.13.7,<0.14.0
and httpcore (0.13.3) depends on h11 (>=0.11,<0.13), httpcore (>=0.13.3,<0.13.4 || >0.13.4,<0.13.5 || >0.13.5,<0.13.6 || >0.13.6,<0.13.7 || >0.13.7,<0.14.0) requires h11 (>=0.11,<0.13).
And because httpcore (0.13.4) depends on h11 (>=0.11,<0.13)
and httpcore (0.13.5) depends on h11 (>=0.11,<0.13), httpcore (>=0.13.3,<0.13.6 || >0.13.6,<0.13.7 || >0.13.7,<0.14.0) requires h11 (>=0.11,<0.13).
And because httpcore (0.13.6) depends on h11 (>=0.11,<0.13)
and httpcore (0.13.7) depends on h11 (>=0.11,<0.13), httpcore (>=0.13.3,<0.14.0) requires h11 (>=0.11,<0.13).
And because httpx (>=0.19.0) requires h11 (>=0.11,<0.13) or httpcore (>=0.13.3,<0.14.0) (3), httpx (>=0.19.0) requires h11 (>=0.11,<0.13)
Because no versions of http3 match >0.6.7,<0.7.0
and http3 (0.6.7) depends on h11 (>=0.8.0,<0.9.0), http3 (>=0.6.7,<0.7.0) requires h11 (>=0.8.0,<0.9.0).
Thus, http3 (>=0.6.7,<0.7.0) is incompatible with httpx (>=0.19.0).
And because prisma (0.6.6) depends on httpx (>=0.19.0)
and no versions of prisma match >0.6.6,<0.7.0, http3 (>=0.6.7,<0.7.0) is incompatible with prisma (>=0.6.6,<0.7.0).
So, because backend depends on both prisma (^0.6.6) and http3 (^0.6.7), version solving failed.
INFO: 127.0.0.1:62948 - "GET /users/ HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/engine/query.py", line 161, in spawn
data = await self.request('GET', '/status')
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/engine/http.py", line 96, in request
resp = await self.session.request(method, url, **kwargs)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/_async_http.py", line 28, in request
return Response(await self.session.request(method, url, **kwargs))
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpx/_client.py", line 1527, in request
return await self.send(request, auth=auth, follow_redirects=follow_redirects)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpx/_client.py", line 1614, in send
response = await self._send_handling_auth(
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpx/_client.py", line 1642, in _send_handling_auth
response = await self._send_handling_redirects(
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpx/_client.py", line 1679, in _send_handling_redirects
response = await self._send_single_request(request)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpx/_client.py", line 1716, in _send_single_request
response = await transport.handle_async_request(request)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpx/_transports/default.py", line 353, in handle_async_request
resp = await self._pool.handle_async_request(req)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpcore/_async/connection_pool.py", line 253, in handle_async_request
raise exc
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpcore/_async/connection_pool.py", line 237, in handle_async_request
response = await connection.handle_async_request(request)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpcore/_async/connection.py", line 90, in handle_async_request
return await self._connection.handle_async_request(request)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpcore/_async/http11.py", line 105, in handle_async_request
raise exc
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpcore/_async/http11.py", line 84, in handle_async_request
) = await self._receive_response_headers(**kwargs)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/httpcore/_async/http11.py", line 156, in _receive_response_headers
headers = event.headers.raw_items()
AttributeError: 'list' object has no attribute 'raw_items'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
return await self.app(scope, receive, send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/fastapi/applications.py", line 269, in __call__
await super().__call__(scope, receive, send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/applications.py", line 124, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in __call__
raise exc
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 93, in __call__
raise exc
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
await self.app(scope, receive, sender)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
raise e
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 670, in __call__
await route.handle(scope, receive, send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 266, in handle
await self.app(scope, receive, send)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 65, in app
response = await func(request)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/fastapi/routing.py", line 227, in app
raw_response = await run_endpoint_function(
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/fastapi/routing.py", line 160, in run_endpoint_function
return await dependant.call(**values)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/./routes/users.py", line 16, in list_all_users
async with Prisma() as db:
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/client.py", line 212, in __aenter__
await self.connect()
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/client.py", line 248, in connect
await self.__engine.connect(
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/engine/query.py", line 109, in connect
await self.spawn(file, timeout=timeout, datasources=datasources)
File "/Users/aliparandeh/Documents/Github/BYAI/backend/.venv/lib/python3.9/site-packages/prisma/engine/query.py", line 180, in spawn
raise errors.EngineConnectionError(
prisma.engine.errors.EngineConnectionError: Could not connect to the query engine
Resolved Package List that allows Prisma to work with HTTP3
aiohttp==3.8.1; python_version >= "3.6"
aiosignal==1.2.0; python_version >= "3.6"
anyio==3.6.1; python_version >= "3.7" and python_full_version >= "3.7.0"
async-timeout==4.0.2; python_version >= "3.6"
attrs==22.1.0; python_version >= "3.6"
bcrypt==3.2.2; python_version >= "3.6"
black==22.6.0; python_full_version >= "3.6.2"
certifi==2022.6.15; python_version >= "3.7" and python_full_version >= "3.7.0"
cffi==1.15.1; python_version >= "3.6"
charset-normalizer==2.1.0; python_full_version >= "3.6.0" and python_version >= "3.6"
click==8.1.3; python_version >= "3.7" and python_full_version >= "3.7.0"
colorama==0.4.5; python_version >= "3.7" and python_full_version >= "3.7.0" and platform_system == "Windows"
fastapi==0.79.0; python_full_version >= "3.6.1"
frozenlist==1.3.1; python_version >= "3.7"
greenlet==1.1.2; python_version >= "3" and python_full_version < "3.0.0" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0") or python_version >= "3" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0") and python_full_version >= "3.5.0"
h11==0.12.0; python_version >= "3.7" and python_full_version >= "3.7.0"
httpcore==0.15.0; python_version >= "3.7" and python_full_version >= "3.7.0"
httpx==0.23.0; python_version >= "3.7" and python_full_version >= "3.7.0"
idna==3.3; python_version >= "3.7" and python_full_version >= "3.7.0"
jinja2==3.1.2; python_version >= "3.7" and python_full_version >= "3.7.0"
markupsafe==2.1.1; python_version >= "3.7" and python_full_version >= "3.7.0"
multidict==6.0.2; python_version >= "3.7"
mypy-extensions==0.4.3; python_full_version >= "3.6.2"
pathspec==0.9.0; python_full_version >= "3.6.2"
platformdirs==2.5.2; python_version >= "3.7" and python_full_version >= "3.6.2"
prisma==0.6.6; python_full_version >= "3.7.0"
pycparser==2.21; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pydantic==1.9.2; python_full_version >= "3.7.0"
python-dotenv==0.20.0; python_version >= "3.5" and python_full_version >= "3.7.0"
python-multipart==0.0.5
rfc3986==1.5.0; python_version >= "3.7" and python_full_version >= "3.7.0"
six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0"
sniffio==1.2.0; python_version >= "3.7" and python_full_version >= "3.7.0"
sqlalchemy==1.4.40; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.6.0")
starlette==0.19.1; python_version >= "3.6" and python_full_version >= "3.6.1"
tomli==2.0.1; python_full_version < "3.11.0a7" and python_full_version >= "3.6.2" and python_version >= "3.7"
typing-extensions==4.3.0; python_version >= "3.7" and python_full_version >= "3.7.0" and python_version < "3.10"
uvicorn==0.18.2; python_version >= "3.7"
yarl==1.8.1; python_version >= "3.7"
@Ali-Parandeh Sorry you're running into this, dependency resolution in Python can be hell sometimes.
Is there a reason you need to use aiohttp? Removing that dependency works for me.
@RobertCraigie I was trying to implement a /health endpoint where I send an async GET request to /users to get some data in FastAPI from the DB using prisma-python to check that everything is working.
If the request is not async then FastAPI just hangs.
@Ali-Parandeh Ah okay, in that case you could switch to using httpx instead as that is what Prisma Client Python uses internally and they have async support: https://www.python-httpx.org/async/.
Actually I've just realised that http3 is actually just an old version of httpx, you should definitely upgrade to use httpx.
@Ali-Parandeh can this be closed now?
Ahhh I see. Thank you I will use that instead. Yes please you can close this issue