Skip to content

Commit a5949f5

Browse files
committed
motor -> pymongo
1 parent e5eab6d commit a5949f5

22 files changed

+44
-62
lines changed

.github/workflows/backend-ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ jobs:
128128
docker compose -f docker-compose.ci.yaml up -d --wait --wait-timeout 120
129129
docker compose -f docker-compose.ci.yaml ps
130130
131-
- name: Run integration tests (non-k8s)
131+
- name: Run integration tests
132132
timeout-minutes: 10
133133
env:
134134
MONGO_ROOT_USER: root
@@ -144,7 +144,7 @@ jobs:
144144
COVERAGE_CORE: sysmon
145145
run: |
146146
cd backend
147-
uv run pytest tests/integration -v -rs \
147+
uv run pytest tests/integration -p no:xdist -v -rs \
148148
--ignore=tests/integration/k8s \
149149
--cov=app --cov-branch \
150150
--cov-report=xml --cov-report=term

backend/app/core/database_context.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,23 @@
44
from dataclasses import dataclass
55
from typing import Any, AsyncContextManager, Protocol, TypeVar, runtime_checkable
66

7-
from motor.motor_asyncio import (
8-
AsyncIOMotorClient,
9-
AsyncIOMotorClientSession,
10-
AsyncIOMotorCollection,
11-
AsyncIOMotorCursor,
12-
AsyncIOMotorDatabase,
13-
)
7+
from pymongo.asynchronous.client_session import AsyncClientSession
8+
from pymongo.asynchronous.collection import AsyncCollection
9+
from pymongo.asynchronous.cursor import AsyncCursor
10+
from pymongo.asynchronous.database import AsyncDatabase
11+
from pymongo.asynchronous.mongo_client import AsyncMongoClient
1412
from pymongo.errors import ServerSelectionTimeoutError
1513

1614
from app.core.logging import logger
1715

1816
# Python 3.12 type aliases using the new 'type' statement
19-
# MongoDocument represents the raw document type returned by Motor operations
17+
# MongoDocument represents the raw document type returned by PyMongo operations
2018
type MongoDocument = dict[str, Any]
21-
type DBClient = AsyncIOMotorClient[MongoDocument]
22-
type Database = AsyncIOMotorDatabase[MongoDocument]
23-
type Collection = AsyncIOMotorCollection[MongoDocument]
24-
type Cursor = AsyncIOMotorCursor[MongoDocument]
25-
type DBSession = AsyncIOMotorClientSession
19+
type DBClient = AsyncMongoClient[MongoDocument]
20+
type Database = AsyncDatabase[MongoDocument]
21+
type Collection = AsyncCollection[MongoDocument]
22+
type Cursor = AsyncCursor[MongoDocument]
23+
type DBSession = AsyncClientSession
2624

2725
# Type variable for generic database provider
2826
T = TypeVar("T")
@@ -106,10 +104,8 @@ async def connect(self) -> None:
106104

107105
logger.info(f"Connecting to MongoDB database: {self._db_name}")
108106

109-
# Always explicitly bind to current event loop for consistency
110-
import asyncio
111-
112-
client: DBClient = AsyncIOMotorClient(
107+
# PyMongo Async automatically uses the current event loop
108+
client: DBClient = AsyncMongoClient(
113109
self._config.mongodb_url,
114110
serverSelectionTimeoutMS=self._config.server_selection_timeout_ms,
115111
connectTimeoutMS=self._config.connect_timeout_ms,
@@ -119,7 +115,6 @@ async def connect(self) -> None:
119115
retryReads=self._config.retry_reads,
120116
w=self._config.write_concern,
121117
journal=self._config.journal,
122-
io_loop=asyncio.get_running_loop(), # Always bind to current loop
123118
)
124119

125120
# Verify connection
@@ -128,7 +123,7 @@ async def connect(self) -> None:
128123
logger.info("Successfully connected to MongoDB")
129124
except ServerSelectionTimeoutError as e:
130125
logger.error(f"Failed to connect to MongoDB: {e}")
131-
client.close()
126+
await client.close()
132127
raise
133128

134129
self._client = client
@@ -137,7 +132,7 @@ async def connect(self) -> None:
137132
async def disconnect(self) -> None:
138133
if self._client is not None:
139134
logger.info("Closing MongoDB connection")
140-
self._client.close()
135+
await self._client.close()
141136
self._client = None
142137
self._database = None
143138

backend/app/services/coordinator/coordinator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from uuid import uuid4
77

88
import redis.asyncio as redis
9-
from motor.motor_asyncio import AsyncIOMotorClient
9+
from pymongo.asynchronous.mongo_client import AsyncMongoClient
1010

1111
from app.core.database_context import DBClient
1212
from app.core.lifecycle import LifecycleEnabled
@@ -500,7 +500,7 @@ async def run_coordinator() -> None:
500500
config = ProducerConfig(bootstrap_servers=settings.KAFKA_BOOTSTRAP_SERVERS)
501501
producer = UnifiedProducer(config, schema_registry_manager)
502502

503-
db_client: DBClient = AsyncIOMotorClient(settings.MONGODB_URL, tz_aware=True, serverSelectionTimeoutMS=5000)
503+
db_client: DBClient = AsyncMongoClient(settings.MONGODB_URL, tz_aware=True, serverSelectionTimeoutMS=5000)
504504
db_name = settings.DATABASE_NAME
505505
database = db_client[db_name]
506506

backend/app/services/k8s_worker/worker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from kubernetes import client as k8s_client
1010
from kubernetes import config as k8s_config
1111
from kubernetes.client.rest import ApiException
12-
from motor.motor_asyncio import AsyncIOMotorClient
12+
from pymongo.asynchronous.mongo_client import AsyncMongoClient
1313

1414
from app.core.database_context import Database, DBClient
1515
from app.core.lifecycle import LifecycleEnabled
@@ -521,7 +521,7 @@ async def run_kubernetes_worker() -> None:
521521

522522
logger.info("Initializing database connection...")
523523
settings = get_settings()
524-
db_client: DBClient = AsyncIOMotorClient(settings.MONGODB_URL, tz_aware=True, serverSelectionTimeoutMS=5000)
524+
db_client: DBClient = AsyncMongoClient(settings.MONGODB_URL, tz_aware=True, serverSelectionTimeoutMS=5000)
525525
db_name = settings.DATABASE_NAME
526526
database = db_client[db_name]
527527
await db_client.admin.command("ping")

backend/pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ dependencies = [
5555
"markdown-it-py==4.0.0",
5656
"MarkupSafe==3.0.2",
5757
"mdurl==0.1.2",
58-
"motor==3.6.0",
5958
"msgpack==1.1.0",
6059
"multidict==6.7.0",
6160
"oauthlib==3.2.2",

backend/scripts/seed_users.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818
from typing import Any
1919

2020
from bson import ObjectId
21-
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
2221
from passlib.context import CryptContext
22+
from pymongo.asynchronous.database import AsyncDatabase
23+
from pymongo.asynchronous.mongo_client import AsyncMongoClient
2324

2425
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
2526

2627

2728
async def upsert_user(
28-
db: AsyncIOMotorDatabase[dict[str, Any]],
29+
db: AsyncDatabase[dict[str, Any]],
2930
username: str,
3031
email: str,
3132
password: str,
@@ -73,7 +74,7 @@ async def seed_users() -> None:
7374

7475
print(f"Connecting to MongoDB (database: {db_name})...")
7576

76-
client: AsyncIOMotorClient[dict[str, Any]] = AsyncIOMotorClient(mongodb_url)
77+
client: AsyncMongoClient[dict[str, Any]] = AsyncMongoClient(mongodb_url)
7778
db = client[db_name]
7879

7980
# Default user

backend/tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from dishka import AsyncContainer
1212
from dotenv import load_dotenv
1313
from httpx import ASGITransport
14-
from motor.motor_asyncio import AsyncIOMotorDatabase
14+
from pymongo.asynchronous.database import AsyncDatabase as AsyncIOMotorDatabase
1515
import redis.asyncio as redis
1616

1717
# Load test environment variables BEFORE any app imports

backend/tests/fixtures/real_services.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
import pytest
1111
import pytest_asyncio
12-
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
12+
from pymongo.asynchronous.database import AsyncDatabase as AsyncIOMotorDatabase
13+
from pymongo.asynchronous.mongo_client import AsyncMongoClient as AsyncIOMotorClient
1314
import redis.asyncio as redis
1415
from aiokafka import AIOKafkaProducer, AIOKafkaConsumer
1516
from aiokafka.errors import KafkaConnectionError

backend/tests/integration/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Integration tests conftest - with infrastructure cleanup."""
22
import pytest_asyncio
3-
from motor.motor_asyncio import AsyncIOMotorDatabase
3+
from pymongo.asynchronous.database import AsyncDatabase as AsyncIOMotorDatabase
44
import redis.asyncio as redis
55

66

backend/tests/integration/core/test_container.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22
from dishka import AsyncContainer
3-
from motor.motor_asyncio import AsyncIOMotorDatabase
3+
from pymongo.asynchronous.database import AsyncDatabase as AsyncIOMotorDatabase
44

55
from app.services.event_service import EventService
66

0 commit comments

Comments
 (0)