Non-blocking MongoDB driver for Python asyncio and Tornado applications
npx @tessl/cli install tessl/pypi-motor@3.7.00
# Motor
1
2
A full-featured, non-blocking MongoDB driver for Python asyncio and Tornado applications. Motor provides a coroutine-based API for non-blocking access to MongoDB, enabling high-throughput database operations in asynchronous Python applications.
3
4
## Package Information
5
6
- **Package Name**: motor
7
- **Language**: Python
8
- **Installation**: `pip install motor`
9
- **License**: Apache License 2.0
10
- **Documentation**: https://motor.readthedocs.io/en/stable/
11
12
## Core Imports
13
14
For asyncio applications:
15
16
```python
17
import motor.motor_asyncio as motor
18
```
19
20
For Tornado applications:
21
22
```python
23
import motor.motor_tornado as motor
24
```
25
26
Specific imports:
27
28
```python
29
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase, AsyncIOMotorCollection
30
from motor.motor_tornado import MotorClient, MotorDatabase, MotorCollection
31
```
32
33
## Basic Usage
34
35
### AsyncIO Example
36
37
```python
38
import asyncio
39
import motor.motor_asyncio
40
41
async def main():
42
# Connect to MongoDB
43
client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://localhost:27017')
44
45
# Get database and collection
46
db = client.my_database
47
collection = db.my_collection
48
49
# Insert a document
50
result = await collection.insert_one({'name': 'Alice', 'age': 30})
51
print(f"Inserted document with ID: {result.inserted_id}")
52
53
# Find documents
54
async for document in collection.find({'age': {'$gte': 18}}):
55
print(document)
56
57
# Find one document
58
user = await collection.find_one({'name': 'Alice'})
59
print(f"Found user: {user}")
60
61
# Update a document
62
await collection.update_one(
63
{'name': 'Alice'},
64
{'$set': {'age': 31}}
65
)
66
67
# Delete a document
68
await collection.delete_one({'name': 'Alice'})
69
70
# Close the connection
71
client.close()
72
73
asyncio.run(main())
74
```
75
76
### Tornado Example
77
78
```python
79
import tornado.ioloop
80
import motor.motor_tornado
81
82
def main():
83
client = motor.motor_tornado.MotorClient('mongodb://localhost:27017')
84
db = client.my_database
85
collection = db.my_collection
86
87
# Insert and handle with callback
88
future = collection.insert_one({'name': 'Bob', 'age': 25})
89
tornado.ioloop.IOLoop.current().run_sync(lambda: future)
90
91
client.close()
92
93
if __name__ == '__main__':
94
main()
95
```
96
97
## Architecture
98
99
Motor uses a sophisticated metaprogramming system to create framework-specific classes from framework-agnostic base classes:
100
101
- **Framework-Agnostic Core**: Base classes in `motor.core` define all MongoDB operations
102
- **Framework-Specific Wrappers**: Classes in `motor_asyncio` and `motor_tornado` adapt the core for each framework
103
- **Metaprogramming Decorators**: Transform synchronous PyMongo operations into asynchronous Motor operations
104
- **Dual API Support**: Complete API compatibility with both asyncio and Tornado frameworks
105
106
This design enables Motor to provide identical functionality for both asyncio and Tornado while maintaining a single codebase for core MongoDB operations.
107
108
## Capabilities
109
110
### AsyncIO Client Operations
111
112
Core MongoDB client, database, and collection operations optimized for Python's asyncio framework. Supports async/await syntax and native asyncio.Future objects.
113
114
```python { .api }
115
class AsyncIOMotorClient:
116
def __init__(self, host='localhost', port=27017, **kwargs): ...
117
def get_database(self, name=None, **kwargs) -> AsyncIOMotorDatabase: ...
118
def get_default_database(self, **kwargs) -> AsyncIOMotorDatabase: ...
119
async def list_databases(self, session=None, **kwargs): ...
120
async def list_database_names(self, session=None, **kwargs) -> list[str]: ...
121
async def server_info(self) -> dict: ...
122
async def start_session(self, **kwargs): ...
123
def close(self) -> None: ...
124
125
class AsyncIOMotorDatabase:
126
def get_collection(self, name, **kwargs) -> AsyncIOMotorCollection: ...
127
async def create_collection(self, name, **kwargs) -> AsyncIOMotorCollection: ...
128
async def drop_collection(self, name_or_collection, **kwargs): ...
129
async def list_collection_names(self, **kwargs) -> list[str]: ...
130
async def command(self, command, **kwargs): ...
131
132
class AsyncIOMotorCollection:
133
async def insert_one(self, document, **kwargs): ...
134
async def insert_many(self, documents, **kwargs): ...
135
async def find_one(self, filter=None, **kwargs): ...
136
def find(self, filter=None, **kwargs) -> AsyncIOMotorCursor: ...
137
async def update_one(self, filter, update, **kwargs): ...
138
async def update_many(self, filter, update, **kwargs): ...
139
async def delete_one(self, filter, **kwargs): ...
140
async def delete_many(self, filter, **kwargs): ...
141
async def count_documents(self, filter, **kwargs) -> int: ...
142
143
class AsyncIOMotorClientSession:
144
async def start_transaction(self, **kwargs): ...
145
async def commit_transaction(self): ...
146
async def abort_transaction(self): ...
147
async def with_transaction(self, coro, **kwargs): ...
148
async def end_session(self): ...
149
async def __aenter__(self): ...
150
async def __aexit__(self, exc_type, exc_val, exc_tb): ...
151
```
152
153
[AsyncIO Operations](./asyncio-operations.md)
154
155
### Tornado Client Operations
156
157
Core MongoDB client, database, and collection operations optimized for Tornado's IOLoop and Future objects. Provides callback-based and Future-based async operations.
158
159
```python { .api }
160
class MotorClient:
161
def __init__(self, host='localhost', port=27017, **kwargs): ...
162
def get_database(self, name=None, **kwargs) -> MotorDatabase: ...
163
def get_default_database(self, **kwargs) -> MotorDatabase: ...
164
def list_databases(self, session=None, **kwargs) -> tornado.concurrent.Future: ...
165
def list_database_names(self, session=None, **kwargs) -> tornado.concurrent.Future: ...
166
def server_info(self) -> tornado.concurrent.Future: ...
167
def start_session(self, **kwargs) -> tornado.concurrent.Future: ...
168
def close(self) -> None: ...
169
170
class MotorDatabase:
171
def get_collection(self, name, **kwargs) -> MotorCollection: ...
172
def create_collection(self, name, **kwargs) -> tornado.concurrent.Future: ...
173
def drop_collection(self, name_or_collection, **kwargs) -> tornado.concurrent.Future: ...
174
def list_collection_names(self, **kwargs) -> tornado.concurrent.Future: ...
175
def command(self, command, **kwargs) -> tornado.concurrent.Future: ...
176
177
class MotorCollection:
178
def insert_one(self, document, **kwargs) -> tornado.concurrent.Future: ...
179
def insert_many(self, documents, **kwargs) -> tornado.concurrent.Future: ...
180
def find_one(self, filter=None, **kwargs) -> tornado.concurrent.Future: ...
181
def find(self, filter=None, **kwargs) -> MotorCursor: ...
182
def update_one(self, filter, update, **kwargs) -> tornado.concurrent.Future: ...
183
def update_many(self, filter, update, **kwargs) -> tornado.concurrent.Future: ...
184
def delete_one(self, filter, **kwargs) -> tornado.concurrent.Future: ...
185
def delete_many(self, filter, **kwargs) -> tornado.concurrent.Future: ...
186
def count_documents(self, filter, **kwargs) -> tornado.concurrent.Future: ...
187
188
class MotorClientSession:
189
def start_transaction(self, **kwargs): ...
190
def commit_transaction(self) -> tornado.concurrent.Future: ...
191
def abort_transaction(self) -> tornado.concurrent.Future: ...
192
def with_transaction(self, coro, **kwargs) -> tornado.concurrent.Future: ...
193
def end_session(self) -> tornado.concurrent.Future: ...
194
```
195
196
[Tornado Operations](./tornado-operations.md)
197
198
### GridFS File Storage
199
200
GridFS support for storing and retrieving large files in MongoDB. Provides streaming file operations for both asyncio and Tornado frameworks.
201
202
```python { .api }
203
class AsyncIOMotorGridFSBucket:
204
def __init__(self, database, bucket_name='fs', **kwargs): ...
205
async def upload_from_stream(self, filename, source, **kwargs): ...
206
async def upload_from_stream_with_id(self, file_id, filename, source, **kwargs): ...
207
async def open_download_stream(self, file_id, **kwargs) -> AsyncIOMotorGridOut: ...
208
async def open_download_stream_by_name(self, filename, **kwargs) -> AsyncIOMotorGridOut: ...
209
def open_upload_stream(self, filename, **kwargs) -> AsyncIOMotorGridIn: ...
210
def open_upload_stream_with_id(self, file_id, filename, **kwargs) -> AsyncIOMotorGridIn: ...
211
async def delete(self, file_id, **kwargs): ...
212
async def rename(self, file_id, new_filename, **kwargs): ...
213
214
class AsyncIOMotorGridOut:
215
# Properties
216
_id: Any
217
filename: str
218
length: int
219
content_type: str
220
upload_date: datetime.datetime
221
metadata: dict
222
223
# Methods
224
async def open(self): ...
225
async def read(self, size=-1) -> bytes: ...
226
async def readline(self, size=-1) -> bytes: ...
227
async def readchunk(self) -> bytes: ...
228
def seek(self, pos, whence=0) -> int: ...
229
def tell(self) -> int: ...
230
def close(self) -> None: ...
231
232
class AsyncIOMotorGridIn:
233
# Properties
234
_id: Any
235
filename: str
236
content_type: str
237
chunk_size: int
238
closed: bool
239
240
# Methods
241
async def write(self, data) -> None: ...
242
async def writelines(self, lines) -> None: ...
243
async def close(self) -> None: ...
244
async def abort(self) -> None: ...
245
```
246
247
[GridFS Operations](./gridfs-operations.md)
248
249
### Cursor Operations
250
251
Cursor functionality for iterating over query results, command results, and change streams. Supports both async iteration and traditional cursor methods.
252
253
```python { .api }
254
class AsyncIOMotorCursor:
255
def limit(self, limit) -> AsyncIOMotorCursor: ...
256
def skip(self, skip) -> AsyncIOMotorCursor: ...
257
def sort(self, key_or_list, direction=None) -> AsyncIOMotorCursor: ...
258
def batch_size(self, batch_size) -> AsyncIOMotorCursor: ...
259
async def to_list(self, length=None) -> list: ...
260
def __aiter__(self): ...
261
async def __anext__(self): ...
262
263
class AsyncIOMotorCommandCursor:
264
def batch_size(self, batch_size) -> AsyncIOMotorCommandCursor: ...
265
async def to_list(self, length=None) -> list: ...
266
def __aiter__(self): ...
267
async def __anext__(self): ...
268
269
class AsyncIOMotorLatentCommandCursor(AsyncIOMotorCommandCursor):
270
def batch_size(self, batch_size) -> AsyncIOMotorLatentCommandCursor: ...
271
async def to_list(self, length=None) -> list: ...
272
def __aiter__(self): ...
273
async def __anext__(self): ...
274
275
class AsyncIOMotorChangeStream:
276
async def next(self): ...
277
def __aiter__(self): ...
278
async def __anext__(self): ...
279
async def close(self): ...
280
def resume_token(self): ...
281
```
282
283
[Cursor Operations](./cursor-operations.md)
284
285
### Change Streams
286
287
Real-time change monitoring for watching database, collection, or document changes. Enables reactive applications that respond to data modifications.
288
289
```python { .api }
290
def watch(pipeline=None, **kwargs) -> AsyncIOMotorChangeStream: ...
291
292
class AsyncIOMotorChangeStream:
293
async def next(self): ...
294
def __aiter__(self): ...
295
async def __anext__(self): ...
296
async def close(self): ...
297
@property
298
def resume_token(self): ...
299
```
300
301
[Change Streams](./change-streams.md)
302
303
### Web Integration
304
305
HTTP handlers for serving GridFS files through web frameworks. Includes optimized handlers for both Tornado and aiohttp with support for HTTP caching, range requests, and content negotiation.
306
307
```python { .api }
308
# Tornado Integration
309
class GridFSHandler(tornado.web.RequestHandler):
310
def initialize(self, database, **kwargs): ...
311
async def get(self, filename, include_body=True): ...
312
async def head(self, filename): ...
313
314
# aiohttp Integration
315
class AIOHTTPGridFS:
316
def __init__(self, database, root_collection='fs', **kwargs): ...
317
async def __call__(self, request) -> aiohttp.web.Response: ...
318
319
def get_gridfs_file(bucket, filename, request): ...
320
def get_cache_time(filename, modified, mime_type) -> int: ...
321
def set_extra_headers(response, gridout) -> None: ...
322
```
323
324
[Web Integration](./web-integration.md)
325
326
### Client-Side Field Level Encryption
327
328
Encryption and decryption of fields for client-side field level encryption (CSFLE). Provides key management, field encryption/decryption, and secure data operations.
329
330
```python { .api }
331
class AsyncIOMotorClientEncryption:
332
def __init__(
333
self,
334
kms_providers: dict,
335
key_vault_namespace: str,
336
key_vault_client: AsyncIOMotorClient,
337
codec_options: CodecOptions,
338
**kwargs
339
): ...
340
async def create_data_key(
341
self,
342
kms_provider: str,
343
master_key: Optional[dict] = None,
344
key_alt_names: Optional[list] = None,
345
key_material: Optional[bytes] = None
346
) -> Binary: ...
347
async def encrypt(
348
self,
349
value: Any,
350
algorithm: str,
351
key_id: Optional[Binary] = None,
352
key_alt_name: Optional[str] = None,
353
**kwargs
354
) -> Binary: ...
355
async def decrypt(self, value: Binary) -> Any: ...
356
async def close(self) -> None: ...
357
```
358
359
[Client Encryption](./client-encryption.md)
360
361
## Common Patterns
362
363
### Connection Management
364
365
```python
366
# AsyncIO with connection pooling
367
client = motor.motor_asyncio.AsyncIOMotorClient(
368
'mongodb://localhost:27017',
369
maxPoolSize=10,
370
minPoolSize=5
371
)
372
373
# Always close connections
374
try:
375
# Your database operations
376
pass
377
finally:
378
client.close()
379
```
380
381
### Error Handling
382
383
```python
384
import pymongo.errors
385
386
try:
387
await collection.insert_one(document)
388
except pymongo.errors.DuplicateKeyError:
389
print("Document already exists")
390
except pymongo.errors.ConnectionFailure:
391
print("Failed to connect to MongoDB")
392
```
393
394
### Transaction Support
395
396
```python
397
async def run_in_transaction():
398
async with await client.start_session() as session:
399
async with session.start_transaction():
400
await collection1.insert_one(doc1, session=session)
401
await collection2.update_one(filter, update, session=session)
402
```
403
404
## Types
405
406
```python { .api }
407
from typing import Any, Optional, Union, Dict, List
408
from datetime import datetime
409
import tornado.concurrent
410
from pymongo.results import InsertOneResult, InsertManyResult, UpdateResult, DeleteResult
411
from bson import Binary, CodecOptions
412
413
# Common type aliases used throughout Motor
414
Document = Dict[str, Any]
415
Filter = Dict[str, Any]
416
Update = Dict[str, Any]
417
Pipeline = List[Dict[str, Any]]
418
419
class InsertOneResult:
420
inserted_id: Any
421
acknowledged: bool
422
423
class InsertManyResult:
424
inserted_ids: List[Any]
425
acknowledged: bool
426
427
class UpdateResult:
428
matched_count: int
429
modified_count: int
430
upserted_id: Optional[Any]
431
acknowledged: bool
432
433
class DeleteResult:
434
deleted_count: int
435
acknowledged: bool
436
```