我有一个 FastAPI 项目,它使用
asyncpg
连接到 PostgreSQL。
我使用 poetry
,以下是我的 pyproject.toml
文件。
[tool.poetry]
name = "my_project"
version = "0.1.0"
description = ""
authors = ["Me"]
[tool.poetry.dependencies]
python = "^3.10"
fastapi = "^0.104.0"
uvicorn = "^0.23.2"
sqlmodel = "^0.0.8"
asyncpg = "^0.28.0"
greenlet = "^3.0.0"
pytest = "^7.4.2"
pytest-asyncio = "^0.21.1"
httpx = "^0.25.0"
passlib = "^1.7.4"
python-jose = "^3.3.0"
python-multipart = "^0.0.6"
bcrypt = "^4.0.1"
black = "^23.10.1"
bandit = "^1.7.5"
alembic = "^1.12.1"
python-json-logger = "^2.0.7"
coverage = "^7.4.0"
pytest-cov = "^4.1.0"
cryptography = "^42.0.4"
python-dotenv = "^1.0.1"
[tool.poetry.dev-dependencies]
但是,我注意到,当我运行
poetry install
时,生成的 poetry.lock
文件在长文件的两部分中具有来自 psycopg2
的依赖项,我不打算在这里全部过去。
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"]
mysql-connector = ["mysql-connector-python"]
oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"]
postgresql = ["psycopg2 (>=2.7)"]
postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"]
postgresql-psycopg2binary = ["psycopg2-binary"]
postgresql-psycopg2cffi = ["psycopg2cffi"]
pymysql = ["pymysql", "pymysql (<1)"]
sqlcipher = ["sqlcipher3-binary"]
尽管使用了
asyncpg
,但仍然依赖于非异步 psycopg2
。
此外,当我为我的项目构建 Docker 容器时,这会导致另一个问题。
以下是我正在使用的Dockerfile
。
# Base image
FROM python:3.10 AS python-base
# Environment variables
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
POETRY_HOME="/opt/poetry" \
POETRY_VIRTUALENVS_IN_PROJECT=true \
POETRY_NO_INTERACTION=1 \
PYSETUP_PATH="/opt/pysetup" \
VENV_PATH="/opt/pysetup/.venv"
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"
# Builder stage
FROM python-base AS builder-base
RUN buildDeps="build-essential" \
&& apt-get update \
&& apt-get install --no-install-recommends -y \
curl \
build-essential \
&& apt-get install -y --no-install-recommends "$buildDeps" \
&& apt-get install -y iputils-ping \
&& apt-get install -y dnsutils \
&& apt-get install -y wget \
&& rm -rf /var/lib/apt/lists/*
WORKDIR $PYSETUP_PATH
COPY poetry.lock pyproject.toml ./
# Use the same version of Poetry as used locally
ENV POETRY_VERSION=1.5.1
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=${POETRY_HOME} python3 - --version ${POETRY_VERSION} && \
chmod a+x /opt/poetry/bin/poetry
RUN poetry config virtualenvs.in-project false
RUN poetry install --no-interaction --no-dev
# Development stage
FROM python-base AS development
ENV FASTAPI_ENV=development
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
WORKDIR $PYSETUP_PATH
RUN poetry install
WORKDIR /app
COPY . .
EXPOSE 8000
CMD ["poetry", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
这是
docker-compose.yml
的一个。
version: '3.8'
services:
web:
build: .
env_file:
- .env
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydatabase
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
运行的结果
docker-compose up
我收到以下错误
Traceback (most recent call last):
File "/opt/pysetup/.venv/bin/uvicorn", line 8, in <module>
sys.exit(main())
File "/opt/pysetup/.venv/lib/python3.10/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/main.py", line 416, in main
run(
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/main.py", line 587, in run
server.run()
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/server.py", line 61, in run
return asyncio.run(self.serve(sockets=sockets))
File "/usr/local/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/server.py", line 68, in serve
config.load()
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/config.py", line 467, in load
self.loaded_app = import_from_string(self.app)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/importer.py", line 24, in import_from_string
raise exc from None
File "/opt/pysetup/.venv/lib/python3.10/site-packages/uvicorn/importer.py", line 21, in import_from_string
module = importlib.import_module(module_str)
File "/usr/local/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/app/app/main.py", line 9, in <module>
from app.router.api_v1.endpoints import api_router
File "/app/app/router/api_v1/endpoints.py", line 3, in <module>
from app.login.api import router as login_router
File "/app/app/login/api.py", line 9, in <module>
from app.core.security import create_access_token
File "/app/app/core/security.py", line 15, in <module>
from app.core.db import get_async_session
File "/app/app/core/db.py", line 14, in <module>
async_engine = create_async_engine(db_connection_str, echo=True, future=True)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/sqlalchemy/ext/asyncio/engine.py", line 43, in create_async_engine
sync_engine = _create_engine(*arg, **kw)
File "<string>", line 2, in create_engine
File "/opt/pysetup/.venv/lib/python3.10/site-packages/sqlalchemy/util/deprecations.py", line 309, in warned
return fn(*args, **kwargs)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/sqlalchemy/engine/create.py", line 548, in create_engine
dbapi = dialect_cls.dbapi(**dbapi_args)
File "/opt/pysetup/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 811, in dbapi
import psycopg2
ModuleNotFoundError: No module named 'psycopg2'
我用
poetry show—-tree | grep psycopg2
检查了是否有任何已安装的软件包依赖于 psycopg2,结果没有。
与
poetry show --tree | grep postgresql
相同
我还尝试删除
venv
并从头开始重新创建所有内容,但没有不同的结果。
我需要将
psycopg2
添加到依赖项列表中吗?如果是,为什么有必要?
此外,如果我安装它,我收到以下错误
sqlalchemy.exc.InvalidRequestError: The asyncio extension requires an async driver to be used. The loaded 'psycopg2' is not async.
我设法找到了问题。 在
.env
文件中,用于连接数据库的字符串是
DB_ASYNC_TEST_CONNECTION_STR="postgresql://postgres:pass/db_tests"
将其更改为
postgresql+asyncpg://
解决了错误
`ModuleNotFoundError:没有名为“psycopg2”的模块
尽管如此,在
poetry.lock
中,仍然存在来自 psycopg2.
的依赖关系
`