PYTHON-3610 Add blacken-docs to pre-commit hook (#1170)

This commit is contained in:
Steven Silvester 2023-03-14 15:37:45 -05:00 committed by GitHub
parent 25ba21770c
commit e9a6482c4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 224 additions and 168 deletions

View File

@ -30,6 +30,13 @@ repos:
files: \.py$
args: [--profile=black]
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.13.0"
hooks:
- id: blacken-docs
additional_dependencies:
- black==22.3.0
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
hooks:

View File

@ -148,7 +148,7 @@ Examples
========
Here's a basic example (for more see the *examples* section of the docs):
.. code-block:: python
.. code-block:: pycon
>>> import pymongo
>>> client = pymongo.MongoClient("localhost", 27017)

View File

@ -29,7 +29,9 @@ Example usage (deserialization):
.. doctest::
>>> from bson.json_util import loads
>>> loads('[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$scope": {}, "$code": "function x() { return 1; }"}}, {"bin": {"$type": "80", "$binary": "AQIDBA=="}}]')
>>> loads(
... '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$scope": {}, "$code": "function x() { return 1; }"}}, {"bin": {"$type": "80", "$binary": "AQIDBA=="}}]'
... )
[{'foo': [1, 2]}, {'bar': {'hello': 'world'}}, {'code': Code('function x() { return 1; }', {})}, {'bin': Binary(b'...', 128)}]
Example usage with :const:`RELAXED_JSON_OPTIONS` (the default):
@ -38,10 +40,14 @@ Example usage with :const:`RELAXED_JSON_OPTIONS` (the default):
>>> from bson import Binary, Code
>>> from bson.json_util import dumps
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary(b"\x01\x02\x03\x04")}])
>>> dumps(
... [
... {"foo": [1, 2]},
... {"bar": {"hello": "world"}},
... {"code": Code("function x() { return 1; }")},
... {"bin": Binary(b"\x01\x02\x03\x04")},
... ]
... )
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'
Example usage (with :const:`CANONICAL_JSON_OPTIONS`):
@ -50,11 +56,15 @@ Example usage (with :const:`CANONICAL_JSON_OPTIONS`):
>>> from bson import Binary, Code
>>> from bson.json_util import dumps, CANONICAL_JSON_OPTIONS
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary(b"\x01\x02\x03\x04")}],
... json_options=CANONICAL_JSON_OPTIONS)
>>> dumps(
... [
... {"foo": [1, 2]},
... {"bar": {"hello": "world"}},
... {"code": Code("function x() { return 1; }")},
... {"bin": Binary(b"\x01\x02\x03\x04")},
... ],
... json_options=CANONICAL_JSON_OPTIONS,
... )
'[{"foo": [{"$numberInt": "1"}, {"$numberInt": "2"}]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'
Example usage (with :const:`LEGACY_JSON_OPTIONS`):
@ -63,11 +73,15 @@ Example usage (with :const:`LEGACY_JSON_OPTIONS`):
>>> from bson import Binary, Code
>>> from bson.json_util import dumps, LEGACY_JSON_OPTIONS
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }", {})},
... {'bin': Binary(b"\x01\x02\x03\x04")}],
... json_options=LEGACY_JSON_OPTIONS)
>>> dumps(
... [
... {"foo": [1, 2]},
... {"bar": {"hello": "world"}},
... {"code": Code("function x() { return 1; }", {})},
... {"bin": Binary(b"\x01\x02\x03\x04")},
... ],
... json_options=LEGACY_JSON_OPTIONS,
... )
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}}, {"bin": {"$binary": "AQIDBA==", "$type": "00"}}]'
Alternatively, you can manually pass the `default` to :func:`json.dumps`.

View File

@ -25,18 +25,18 @@ Example: Moving a document between different databases/collections
>>> from pymongo import MongoClient
>>> from bson.raw_bson import RawBSONDocument
>>> client = MongoClient(document_class=RawBSONDocument)
>>> client.drop_database('db')
>>> client.drop_database('replica_db')
>>> client.drop_database("db")
>>> client.drop_database("replica_db")
>>> db = client.db
>>> result = db.test.insert_many([{'_id': 1, 'a': 1},
... {'_id': 2, 'b': 1},
... {'_id': 3, 'c': 1},
... {'_id': 4, 'd': 1}])
>>> result = db.test.insert_many(
... [{"_id": 1, "a": 1}, {"_id": 2, "b": 1}, {"_id": 3, "c": 1}, {"_id": 4, "d": 1}]
... )
>>> replica_db = client.replica_db
>>> for doc in db.test.find():
... print(f"raw document: {doc.raw}")
... print(f"decoded document: {bson.decode(doc.raw)}")
... result = replica_db.test.insert_one(doc)
... print(f"raw document: {doc.raw}")
... print(f"decoded document: {bson.decode(doc.raw)}")
... result = replica_db.test.insert_one(doc)
...
raw document: b'...'
decoded document: {'_id': 1, 'a': 1}
raw document: b'...'

View File

@ -8,8 +8,9 @@ group method.
.. testsetup::
from pymongo import MongoClient
client = MongoClient()
client.drop_database('aggregation_example')
client.drop_database("aggregation_example")
Setup
-----
@ -20,10 +21,14 @@ aggregations on:
>>> from pymongo import MongoClient
>>> db = MongoClient().aggregation_example
>>> result = db.things.insert_many([{"x": 1, "tags": ["dog", "cat"]},
... {"x": 2, "tags": ["cat"]},
... {"x": 2, "tags": ["mouse", "cat", "dog"]},
... {"x": 3, "tags": []}])
>>> result = db.things.insert_many(
... [
... {"x": 1, "tags": ["dog", "cat"]},
... {"x": 2, "tags": ["cat"]},
... {"x": 2, "tags": ["mouse", "cat", "dog"]},
... {"x": 3, "tags": []},
... ]
... )
>>> result.inserted_ids
[ObjectId('...'), ObjectId('...'), ObjectId('...'), ObjectId('...')]
@ -54,7 +59,7 @@ eg "$sort":
>>> pipeline = [
... {"$unwind": "$tags"},
... {"$group": {"_id": "$tags", "count": {"$sum": 1}}},
... {"$sort": SON([("count", -1), ("_id", -1)])}
... {"$sort": SON([("count", -1), ("_id", -1)])},
... ]
>>> import pprint
>>> pprint.pprint(list(db.things.aggregate(pipeline)))

View File

@ -4,8 +4,9 @@ Bulk Write Operations
.. testsetup::
from pymongo import MongoClient
client = MongoClient()
client.drop_database('bulk_example')
client.drop_database("bulk_example")
This tutorial explains how to take advantage of PyMongo's bulk
write operation features. Executing write operations in batches
@ -27,7 +28,7 @@ bulk insert operations.
>>> import pymongo
>>> db = pymongo.MongoClient().bulk_example
>>> db.test.insert_many([{'i': i} for i in range(10000)]).inserted_ids
>>> db.test.insert_many([{"i": i} for i in range(10000)]).inserted_ids
[...]
>>> db.test.count_documents({})
10000
@ -56,14 +57,17 @@ of operations performed.
>>> from pprint import pprint
>>> from pymongo import InsertOne, DeleteMany, ReplaceOne, UpdateOne
>>> result = db.test.bulk_write([
... DeleteMany({}), # Remove all documents from the previous example.
... InsertOne({'_id': 1}),
... InsertOne({'_id': 2}),
... InsertOne({'_id': 3}),
... UpdateOne({'_id': 1}, {'$set': {'foo': 'bar'}}),
... UpdateOne({'_id': 4}, {'$inc': {'j': 1}}, upsert=True),
... ReplaceOne({'j': 1}, {'j': 2})])
>>> result = db.test.bulk_write(
... [
... DeleteMany({}), # Remove all documents from the previous example.
... InsertOne({"_id": 1}),
... InsertOne({"_id": 2}),
... InsertOne({"_id": 3}),
... UpdateOne({"_id": 1}, {"$set": {"foo": "bar"}}),
... UpdateOne({"_id": 4}, {"$inc": {"j": 1}}, upsert=True),
... ReplaceOne({"j": 1}, {"j": 2}),
... ]
... )
>>> pprint(result.bulk_api_result)
{'nInserted': 3,
'nMatched': 2,
@ -87,9 +91,10 @@ the failure.
>>> from pymongo import InsertOne, DeleteOne, ReplaceOne
>>> from pymongo.errors import BulkWriteError
>>> requests = [
... ReplaceOne({'j': 2}, {'i': 5}),
... InsertOne({'_id': 4}), # Violates the unique key constraint on _id.
... DeleteOne({'i': 5})]
... ReplaceOne({"j": 2}, {"i": 5}),
... InsertOne({"_id": 4}), # Violates the unique key constraint on _id.
... DeleteOne({"i": 5}),
... ]
>>> try:
... db.test.bulk_write(requests)
... except BulkWriteError as bwe:
@ -124,10 +129,11 @@ and fourth operations succeed.
:options: +NORMALIZE_WHITESPACE
>>> requests = [
... InsertOne({'_id': 1}),
... DeleteOne({'_id': 2}),
... InsertOne({'_id': 3}),
... ReplaceOne({'_id': 4}, {'i': 1})]
... InsertOne({"_id": 1}),
... DeleteOne({"_id": 2}),
... InsertOne({"_id": 3}),
... ReplaceOne({"_id": 4}, {"i": 1}),
... ]
>>> try:
... db.test.bulk_write(requests, ordered=False)
... except BulkWriteError as bwe:

View File

@ -19,7 +19,7 @@ We'll start by getting a clean database to use for the example:
>>> from pymongo import MongoClient
>>> client = MongoClient()
>>> client.drop_database('custom_type_example')
>>> client.drop_database("custom_type_example")
>>> db = client.custom_type_example
@ -36,7 +36,7 @@ to save an instance of ``Decimal`` with PyMongo, results in an
>>> from decimal import Decimal
>>> num = Decimal("45.321")
>>> db.test.insert_one({'num': num})
>>> db.test.insert_one({"num": num})
Traceback (most recent call last):
...
bson.errors.InvalidDocument: cannot encode object: Decimal('45.321'), of type: <class 'decimal.Decimal'>
@ -78,8 +78,8 @@ interested in both encoding and decoding our custom type, we use the
>>> from bson.decimal128 import Decimal128
>>> from bson.codec_options import TypeCodec
>>> class DecimalCodec(TypeCodec):
... python_type = Decimal # the Python type acted upon by this type codec
... bson_type = Decimal128 # the BSON type acted upon by this type codec
... python_type = Decimal # the Python type acted upon by this type codec
... bson_type = Decimal128 # the BSON type acted upon by this type codec
... def transform_python(self, value):
... """Function that transforms a custom type value into a type
... that BSON can encode."""
@ -88,6 +88,7 @@ interested in both encoding and decoding our custom type, we use the
... """Function that transforms a vanilla BSON type value into our
... custom type."""
... return value.to_decimal()
...
>>> decimal_codec = DecimalCodec()
@ -125,7 +126,7 @@ with our ``type_registry`` and use it to get a
>>> from bson.codec_options import CodecOptions
>>> codec_options = CodecOptions(type_registry=type_registry)
>>> collection = db.get_collection('test', codec_options=codec_options)
>>> collection = db.get_collection("test", codec_options=codec_options)
Now, we can seamlessly encode and decode instances of
@ -133,7 +134,7 @@ Now, we can seamlessly encode and decode instances of
.. doctest::
>>> collection.insert_one({'num': Decimal("45.321")})
>>> collection.insert_one({"num": Decimal("45.321")})
<pymongo.results.InsertOneResult object at ...>
>>> mydoc = collection.find_one()
>>> import pprint
@ -147,7 +148,7 @@ MongoDB:
.. doctest::
>>> vanilla_collection = db.get_collection('test')
>>> vanilla_collection = db.get_collection("test")
>>> pprint.pprint(vanilla_collection.find_one())
{'_id': ObjectId('...'), 'num': Decimal128('45.321')}
@ -170,13 +171,14 @@ an integer:
... def my_method(self):
... """Method implementing some custom logic."""
... return int(self)
...
If we try to save an instance of this type without first registering a type
codec for it, we get an error:
.. doctest::
>>> collection.insert_one({'num': DecimalInt("45.321")})
>>> collection.insert_one({"num": DecimalInt("45.321")})
Traceback (most recent call last):
...
bson.errors.InvalidDocument: cannot encode object: Decimal('45.321'), of type: <class 'decimal.Decimal'>
@ -192,6 +194,7 @@ This is trivial to do since the same transformation as the one used for
... def python_type(self):
... """The Python type acted upon by this type codec."""
... return DecimalInt
...
>>> decimalint_codec = DecimalIntCodec()
@ -211,9 +214,9 @@ object, we can seamlessly encode instances of ``DecimalInt``:
>>> type_registry = TypeRegistry([decimal_codec, decimalint_codec])
>>> codec_options = CodecOptions(type_registry=type_registry)
>>> collection = db.get_collection('test', codec_options=codec_options)
>>> collection = db.get_collection("test", codec_options=codec_options)
>>> collection.drop()
>>> collection.insert_one({'num': DecimalInt("45.321")})
>>> collection.insert_one({"num": DecimalInt("45.321")})
<pymongo.results.InsertOneResult object at ...>
>>> mydoc = collection.find_one()
>>> pprint.pprint(mydoc)
@ -236,26 +239,26 @@ writing a ``TypeDecoder`` that modifies how this datatype is decoded.
On Python 3.x, :class:`~bson.binary.Binary` data (``subtype = 0``) is decoded
as a ``bytes`` instance:
.. code-block:: python
.. code-block:: pycon
>>> # On Python 3.x.
>>> from bson.binary import Binary
>>> newcoll = db.get_collection('new')
>>> newcoll.insert_one({'_id': 1, 'data': Binary(b"123", subtype=0)})
>>> newcoll = db.get_collection("new")
>>> newcoll.insert_one({"_id": 1, "data": Binary(b"123", subtype=0)})
>>> doc = newcoll.find_one()
>>> type(doc['data'])
>>> type(doc["data"])
bytes
On Python 2.7.x, the same data is decoded as a :class:`~bson.binary.Binary`
instance:
.. code-block:: python
.. code-block:: pycon
>>> # On Python 2.7.x
>>> newcoll = db.get_collection('new')
>>> newcoll = db.get_collection("new")
>>> doc = newcoll.find_one()
>>> type(doc['data'])
>>> type(doc["data"])
bson.binary.Binary
@ -291,6 +294,7 @@ BSON-encodable value. The following fallback encoder encodes python's
... if isinstance(value, Decimal):
... return Decimal128(value)
... return value
...
After declaring the callback, we must create a type registry and codec options
with this fallback encoder before it can be used for initializing a collection:
@ -299,14 +303,14 @@ with this fallback encoder before it can be used for initializing a collection:
>>> type_registry = TypeRegistry(fallback_encoder=fallback_encoder)
>>> codec_options = CodecOptions(type_registry=type_registry)
>>> collection = db.get_collection('test', codec_options=codec_options)
>>> collection = db.get_collection("test", codec_options=codec_options)
>>> collection.drop()
We can now seamlessly encode instances of :py:class:`~decimal.Decimal`:
.. doctest::
>>> collection.insert_one({'num': Decimal("45.321")})
>>> collection.insert_one({"num": Decimal("45.321")})
<pymongo.results.InsertOneResult object at ...>
>>> mydoc = collection.find_one()
>>> pprint.pprint(mydoc)
@ -343,12 +347,15 @@ We start by defining some arbitrary custom types:
class MyStringType(object):
def __init__(self, value):
self.__value = value
def __repr__(self):
return "MyStringType('%s')" % (self.__value,)
class MyNumberType(object):
def __init__(self, value):
self.__value = value
def __repr__(self):
return "MyNumberType(%s)" % (self.__value,)
@ -362,11 +369,15 @@ back into Python objects:
import pickle
from bson.binary import Binary, USER_DEFINED_SUBTYPE
def fallback_pickle_encoder(value):
return Binary(pickle.dumps(value), USER_DEFINED_SUBTYPE)
class PickledBinaryDecoder(TypeDecoder):
bson_type = Binary
def transform_bson(self, value):
if value.subtype == USER_DEFINED_SUBTYPE:
return pickle.loads(value)
@ -384,19 +395,23 @@ Finally, we create a ``CodecOptions`` instance:
.. code-block:: python
codec_options = CodecOptions(type_registry=TypeRegistry(
[PickledBinaryDecoder()], fallback_encoder=fallback_pickle_encoder))
codec_options = CodecOptions(
type_registry=TypeRegistry(
[PickledBinaryDecoder()], fallback_encoder=fallback_pickle_encoder
)
)
We can now round trip our custom objects to MongoDB:
.. code-block:: python
collection = db.get_collection('test_fe', codec_options=codec_options)
collection.insert_one({'_id': 1, 'str': MyStringType("hello world"),
'num': MyNumberType(2)})
collection = db.get_collection("test_fe", codec_options=codec_options)
collection.insert_one(
{"_id": 1, "str": MyStringType("hello world"), "num": MyNumberType(2)}
)
mydoc = collection.find_one()
assert isinstance(mydoc['str'], MyStringType)
assert isinstance(mydoc['num'], MyNumberType)
assert isinstance(mydoc["str"], MyStringType)
assert isinstance(mydoc["num"], MyNumberType)
Limitations

View File

@ -6,8 +6,9 @@ Datetimes and Timezones
import datetime
from pymongo import MongoClient
from bson.codec_options import CodecOptions
client = MongoClient()
client.drop_database('dt_example')
client.drop_database("dt_example")
db = client.dt_example
These examples show how to handle Python :class:`datetime.datetime` objects
@ -24,8 +25,7 @@ time into MongoDB:
.. doctest::
>>> result = db.objects.insert_one(
... {"last_modified": datetime.datetime.utcnow()})
>>> result = db.objects.insert_one({"last_modified": datetime.datetime.utcnow()})
Always use :meth:`datetime.datetime.utcnow`, which returns the current time in
UTC, instead of :meth:`datetime.datetime.now`, which returns the current local
@ -33,8 +33,7 @@ time. Avoid doing this:
.. doctest::
>>> result = db.objects.insert_one(
... {"last_modified": datetime.datetime.now()})
>>> result = db.objects.insert_one({"last_modified": datetime.datetime.now()})
The value for `last_modified` is very different between these two examples, even
though both documents were stored at around the same local time. This will be
@ -42,7 +41,7 @@ confusing to the application that reads them:
.. doctest::
>>> [doc['last_modified'] for doc in db.objects.find()] # doctest: +SKIP
>>> [doc["last_modified"] for doc in db.objects.find()] # doctest: +SKIP
[datetime.datetime(2015, 7, 8, 18, 17, 28, 324000),
datetime.datetime(2015, 7, 8, 11, 17, 42, 911000)]
@ -52,12 +51,11 @@ timezone they're in. By default, PyMongo retrieves naive datetimes:
.. doctest::
>>> result = db.tzdemo.insert_one(
... {'date': datetime.datetime(2002, 10, 27, 6, 0, 0)})
>>> db.tzdemo.find_one()['date']
>>> result = db.tzdemo.insert_one({"date": datetime.datetime(2002, 10, 27, 6, 0, 0)})
>>> db.tzdemo.find_one()["date"]
datetime.datetime(2002, 10, 27, 6, 0)
>>> options = CodecOptions(tz_aware=True)
>>> db.get_collection('tzdemo', codec_options=options).find_one()['date'] # doctest: +SKIP
>>> db.get_collection("tzdemo", codec_options=options).find_one()["date"] # doctest: +SKIP
datetime.datetime(2002, 10, 27, 6, 0,
tzinfo=<bson.tz_util.FixedOffset object at 0x10583a050>)
@ -71,11 +69,10 @@ those datetimes to UTC automatically:
.. doctest::
>>> import pytz
>>> pacific = pytz.timezone('US/Pacific')
>>> aware_datetime = pacific.localize(
... datetime.datetime(2002, 10, 27, 6, 0, 0))
>>> pacific = pytz.timezone("US/Pacific")
>>> aware_datetime = pacific.localize(datetime.datetime(2002, 10, 27, 6, 0, 0))
>>> result = db.times.insert_one({"date": aware_datetime})
>>> db.times.find_one()['date']
>>> db.times.find_one()["date"]
datetime.datetime(2002, 10, 27, 14, 0)
Reading Time
@ -150,7 +147,7 @@ cannot be represented using the builtin Python :class:`~datetime.datetime`:
.. doctest::
>>> x = encode({"x": datetime(1970, 1, 1)})
>>> y = encode({"x": DatetimeMS(-2**62)})
>>> y = encode({"x": DatetimeMS(-(2**62))})
>>> codec_auto = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_AUTO)
>>> decode(x, codec_options=codec_auto)
{'x': datetime.datetime(1970, 1, 1, 0, 0)}
@ -165,7 +162,7 @@ resulting :class:`~datetime.datetime` objects to be within
.. doctest::
>>> x = encode({"x": DatetimeMS(2**62)})
>>> y = encode({"x": DatetimeMS(-2**62)})
>>> y = encode({"x": DatetimeMS(-(2**62))})
>>> codec_clamp = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_CLAMP)
>>> decode(x, codec_options=codec_clamp)
{'x': datetime.datetime(9999, 12, 31, 23, 59, 59, 999000)}

View File

@ -4,8 +4,9 @@ Geospatial Indexing Example
.. testsetup::
from pymongo import MongoClient
client = MongoClient()
client.drop_database('geo_example')
client.drop_database("geo_example")
This example shows how to create and use a :data:`~pymongo.GEO2D`
index in PyMongo. To create a spherical (earth-like) geospatial index use :data:`~pymongo.GEOSPHERE` instead.
@ -33,10 +34,9 @@ insert a couple of example locations:
.. doctest::
>>> result = db.places.insert_many([{"loc": [2, 5]},
... {"loc": [30, 5]},
... {"loc": [1, 2]},
... {"loc": [4, 4]}])
>>> result = db.places.insert_many(
... [{"loc": [2, 5]}, {"loc": [30, 5]}, {"loc": [1, 2]}, {"loc": [4, 4]}]
... )
>>> result.inserted_ids
[ObjectId('...'), ObjectId('...'), ObjectId('...'), ObjectId('...')]
@ -51,7 +51,7 @@ Using the geospatial index we can find documents near another point:
>>> import pprint
>>> for doc in db.places.find({"loc": {"$near": [3, 6]}}).limit(3):
... pprint.pprint(doc)
... pprint.pprint(doc)
...
{'_id': ObjectId('...'), 'loc': [2, 5]}
{'_id': ObjectId('...'), 'loc': [4, 4]}
@ -66,7 +66,7 @@ The $maxDistance operator requires the use of :class:`~bson.son.SON`:
>>> from bson.son import SON
>>> query = {"loc": SON([("$near", [3, 6]), ("$maxDistance", 100)])}
>>> for doc in db.places.find(query).limit(3):
... pprint.pprint(doc)
... pprint.pprint(doc)
...
{'_id': ObjectId('...'), 'loc': [2, 5]}
{'_id': ObjectId('...'), 'loc': [4, 4]}
@ -78,8 +78,9 @@ It's also possible to query for all items within a given rectangle
.. doctest::
>>> query = {"loc": {"$within": {"$box": [[2, 2], [5, 6]]}}}
>>> for doc in db.places.find(query).sort('_id'):
>>> for doc in db.places.find(query).sort("_id"):
... pprint.pprint(doc)
...
{'_id': ObjectId('...'), 'loc': [2, 5]}
{'_id': ObjectId('...'), 'loc': [4, 4]}
@ -88,8 +89,8 @@ Or circle (specified by center point and radius):
.. doctest::
>>> query = {"loc": {"$within": {"$center": [[0, 0], 6]}}}
>>> for doc in db.places.find(query).sort('_id'):
... pprint.pprint(doc)
>>> for doc in db.places.find(query).sort("_id"):
... pprint.pprint(doc)
...
{'_id': ObjectId('...'), 'loc': [2, 5]}
{'_id': ObjectId('...'), 'loc': [1, 2]}

View File

@ -38,10 +38,12 @@ handler to end background greenlets when your application receives SIGHUP:
import signal
def graceful_reload(signum, traceback):
"""Explicitly close some global MongoClient object."""
client.close()
signal.signal(signal.SIGHUP, graceful_reload)
Applications using uWSGI prior to 1.9.16 are affected by this issue,

View File

@ -4,8 +4,9 @@ GridFS Example
.. testsetup::
from pymongo import MongoClient
client = MongoClient()
client.drop_database('gridfs_example')
client.drop_database("gridfs_example")
This example shows how to use :mod:`gridfs` to store large binary
objects (e.g. files) in MongoDB.

View File

@ -55,12 +55,12 @@ selector function:
>>> def server_selector(server_descriptions):
... servers = [
... server for server in server_descriptions
... if server.address[0] == 'localhost'
... server for server in server_descriptions if server.address[0] == "localhost"
... ]
... if not servers:
... return server_descriptions
... return servers
...

View File

@ -81,7 +81,7 @@ Subclasses of :py:class:`collections.abc.Mapping` can also be used, such as :cla
>>> from pymongo import MongoClient
>>> client = MongoClient(document_class=SON[str, int])
>>> collection = client.test.test
>>> inserted = collection.insert_one({"x": 1, "y": 2 })
>>> inserted = collection.insert_one({"x": 1, "y": 2})
>>> result = collection.find_one({"x": 1})
>>> assert result is not None
>>> assert result["x"] == 1
@ -103,8 +103,8 @@ These methods automatically add an "_id" field.
>>> from pymongo import MongoClient
>>> from pymongo.collection import Collection
>>> class Movie(TypedDict):
... name: str
... year: int
... name: str
... year: int
...
>>> client: MongoClient = MongoClient()
>>> collection: Collection[Movie] = client.test.test
@ -113,7 +113,7 @@ These methods automatically add an "_id" field.
>>> assert result is not None
>>> assert result["year"] == 1993
>>> # This will raise a type-checking error, despite being present, because it is added by PyMongo.
>>> assert result["_id"] # type:ignore[typeddict-item]
>>> assert result["_id"] # type:ignore[typeddict-item]
This same typing scheme works for all of the insert methods (:meth:`~pymongo.collection.Collection.insert_one`,
:meth:`~pymongo.collection.Collection.insert_many`, and :meth:`~pymongo.collection.Collection.bulk_write`).
@ -158,18 +158,18 @@ Note: to use :py:class:`~typing.TypedDict` and :py:class:`~typing.NotRequired` i
>>> from pymongo.collection import Collection
>>> from bson import ObjectId
>>> class Movie(TypedDict):
... name: str
... year: int
... name: str
... year: int
...
>>> class ExplicitMovie(TypedDict):
... _id: ObjectId
... name: str
... year: int
... _id: ObjectId
... name: str
... year: int
...
>>> class NotRequiredMovie(TypedDict):
... _id: NotRequired[ObjectId]
... name: str
... year: int
... _id: NotRequired[ObjectId]
... name: str
... year: int
...
>>> client: MongoClient = MongoClient()
>>> collection: Collection[Movie] = client.test.test
@ -180,7 +180,9 @@ Note: to use :py:class:`~typing.TypedDict` and :py:class:`~typing.NotRequired` i
>>> assert result["_id"] # type:ignore[typeddict-item]
>>> collection: Collection[ExplicitMovie] = client.test.test
>>> # Note that the _id keyword argument must be supplied
>>> inserted = collection.insert_one(ExplicitMovie(_id=ObjectId(), name="Jurassic Park", year=1993))
>>> inserted = collection.insert_one(
... ExplicitMovie(_id=ObjectId(), name="Jurassic Park", year=1993)
... )
>>> result = collection.find_one({"name": "Jurassic Park"})
>>> assert result is not None
>>> # This will not raise a type-checking error.
@ -207,13 +209,13 @@ match a well-defined schema using :py:class:`~typing.TypedDict` (Python 3.8+).
>>> from pymongo import MongoClient
>>> from pymongo.database import Database
>>> class Movie(TypedDict):
... name: str
... year: int
... name: str
... year: int
...
>>> client: MongoClient = MongoClient()
>>> db: Database[Movie] = client.test
>>> collection = db.test
>>> inserted = collection.insert_one({"name": "Jurassic Park", "year": 1993 })
>>> inserted = collection.insert_one({"name": "Jurassic Park", "year": 1993})
>>> result = collection.find_one({"name": "Jurassic Park"})
>>> assert result is not None
>>> assert result["year"] == 1993
@ -244,11 +246,11 @@ You can specify the document type returned by :mod:`bson` decoding functions by
>>> from typing import Any, Dict
>>> from bson import CodecOptions, encode, decode
>>> class MyDict(Dict[str, Any]):
... def foo(self):
... return "bar"
... def foo(self):
... return "bar"
...
>>> options = CodecOptions(document_class=MyDict)
>>> doc = {"x": 1, "y": 2 }
>>> doc = {"x": 1, "y": 2}
>>> bsonbytes = encode(doc, codec_options=options)
>>> rt_document = decode(bsonbytes, codec_options=options)
>>> assert rt_document.foo() == "bar"

View File

@ -244,8 +244,7 @@ Key order in subdocuments -- why does my query work in the shell but not PyMongo
collection = MongoClient().test.collection
collection.drop()
collection.insert_one({'_id': 1.0,
'subdocument': SON([('b', 1.0), ('a', 1.0)])})
collection.insert_one({"_id": 1.0, "subdocument": SON([("b", 1.0), ("a", 1.0)])})
The key-value pairs in a BSON document can have any order (except that ``_id``
is always first). The mongo shell preserves key order when reading and writing
@ -537,6 +536,7 @@ objects as before:
<pymongo.results.InsertOneResult object at 0x...>
>>> for x in client.db.collection.find():
... print(x)
...
{'_id': ObjectId('...'), 'x': datetime.datetime(1970, 1, 1, 0, 0)}
{'_id': ObjectId('...'), 'x': DatetimeMS(4611686018427387904)}

View File

@ -6,6 +6,7 @@ PyMongo 4 Migration Guide
.. testsetup::
from pymongo import MongoClient, ReadPreference
client = MongoClient()
database = client.my_database
collection = database.my_collection

View File

@ -4,8 +4,9 @@ Tutorial
.. testsetup::
from pymongo import MongoClient
client = MongoClient()
client.drop_database('test-database')
client.drop_database("test-database")
This tutorial is intended as an introduction to working with
**MongoDB** and **PyMongo**.
@ -45,13 +46,13 @@ specify the host and port explicitly, as follows:
.. doctest::
>>> client = MongoClient('localhost', 27017)
>>> client = MongoClient("localhost", 27017)
Or use the MongoDB URI format:
.. doctest::
>>> client = MongoClient('mongodb://localhost:27017/')
>>> client = MongoClient("mongodb://localhost:27017/")
Getting a Database
------------------
@ -70,7 +71,7 @@ instead:
.. doctest::
>>> db = client['test-database']
>>> db = client["test-database"]
Getting a Collection
--------------------
@ -87,7 +88,7 @@ or (using dictionary style access):
.. doctest::
>>> collection = db['test-collection']
>>> collection = db["test-collection"]
An important note about collections (and databases) in MongoDB is that
they are created lazily - none of the above commands have actually
@ -104,10 +105,12 @@ post:
.. doctest::
>>> import datetime
>>> post = {"author": "Mike",
... "text": "My first blog post!",
... "tags": ["mongodb", "python", "pymongo"],
... "date": datetime.datetime.utcnow()}
>>> post = {
... "author": "Mike",
... "text": "My first blog post!",
... "tags": ["mongodb", "python", "pymongo"],
... "date": datetime.datetime.utcnow(),
... }
Note that documents can contain native Python types (like
:class:`datetime.datetime` instances) which will be automatically
@ -212,7 +215,7 @@ Note that an ObjectId is not the same as its string representation:
.. doctest::
>>> post_id_as_str = str(post_id)
>>> posts.find_one({"_id": post_id_as_str}) # No result
>>> posts.find_one({"_id": post_id_as_str}) # No result
>>>
A common task in web applications is to get an ObjectId from the
@ -240,14 +243,20 @@ command to the server:
.. doctest::
>>> new_posts = [{"author": "Mike",
... "text": "Another post!",
... "tags": ["bulk", "insert"],
... "date": datetime.datetime(2009, 11, 12, 11, 14)},
... {"author": "Eliot",
... "title": "MongoDB is fun",
... "text": "and pretty easy too!",
... "date": datetime.datetime(2009, 11, 10, 10, 45)}]
>>> new_posts = [
... {
... "author": "Mike",
... "text": "Another post!",
... "tags": ["bulk", "insert"],
... "date": datetime.datetime(2009, 11, 12, 11, 14),
... },
... {
... "author": "Eliot",
... "title": "MongoDB is fun",
... "text": "and pretty easy too!",
... "date": datetime.datetime(2009, 11, 10, 10, 45),
... },
... ]
>>> result = posts.insert_many(new_posts)
>>> result.inserted_ids
[ObjectId('...'), ObjectId('...')]
@ -274,7 +283,7 @@ document in the ``posts`` collection:
.. doctest::
>>> for post in posts.find():
... pprint.pprint(post)
... pprint.pprint(post)
...
{'_id': ObjectId('...'),
'author': 'Mike',
@ -300,7 +309,7 @@ author is "Mike":
.. doctest::
>>> for post in posts.find({"author": "Mike"}):
... pprint.pprint(post)
... pprint.pprint(post)
...
{'_id': ObjectId('...'),
'author': 'Mike',
@ -343,7 +352,7 @@ than a certain date, but also sort the results by author:
>>> d = datetime.datetime(2009, 11, 12, 12)
>>> for post in posts.find({"date": {"$lt": d}}).sort("author"):
... pprint.pprint(post)
... pprint.pprint(post)
...
{'_id': ObjectId('...'),
'author': 'Eliot',
@ -373,8 +382,7 @@ First, we'll need to create the index:
.. doctest::
>>> result = db.profiles.create_index([('user_id', pymongo.ASCENDING)],
... unique=True)
>>> result = db.profiles.create_index([("user_id", pymongo.ASCENDING)], unique=True)
>>> sorted(list(db.profiles.index_information()))
['_id_', 'user_id_1']
@ -386,9 +394,7 @@ Now let's set up some user profiles:
.. doctest::
>>> user_profiles = [
... {'user_id': 211, 'name': 'Luke'},
... {'user_id': 212, 'name': 'Ziltoid'}]
>>> user_profiles = [{"user_id": 211, "name": "Luke"}, {"user_id": 212, "name": "Ziltoid"}]
>>> result = db.profiles.insert_many(user_profiles)
The index prevents us from inserting a document whose ``user_id`` is already in
@ -397,8 +403,8 @@ the collection:
.. doctest::
:options: +IGNORE_EXCEPTION_DETAIL
>>> new_profile = {'user_id': 213, 'name': 'Drew'}
>>> duplicate_profile = {'user_id': 212, 'name': 'Tommy'}
>>> new_profile = {"user_id": 213, "name": "Drew"}
>>> duplicate_profile = {"user_id": 212, "name": "Tommy"}
>>> result = db.profiles.insert_one(new_profile) # This is fine.
>>> result = db.profiles.insert_one(duplicate_profile)
Traceback (most recent call last):

View File

@ -23,12 +23,11 @@ Causally Consistent Reads
with client.start_session(causal_consistency=True) as session:
collection = client.db.collection
collection.update_one({'_id': 1}, {'$set': {'x': 10}}, session=session)
secondary_c = collection.with_options(
read_preference=ReadPreference.SECONDARY)
collection.update_one({"_id": 1}, {"$set": {"x": 10}}, session=session)
secondary_c = collection.with_options(read_preference=ReadPreference.SECONDARY)
# A secondary read waits for replication of the write.
secondary_c.find_one({'_id': 1}, session=session)
secondary_c.find_one({"_id": 1}, session=session)
If `causal_consistency` is True (the default), read operations that use
the session are causally after previous read and write operations. Using a
@ -57,8 +56,11 @@ operation:
with client.start_session() as session:
with session.start_transaction():
orders.insert_one({"sku": "abc123", "qty": 100}, session=session)
inventory.update_one({"sku": "abc123", "qty": {"$gte": 100}},
{"$inc": {"qty": -100}}, session=session)
inventory.update_one(
{"sku": "abc123", "qty": {"$gte": 100}},
{"$inc": {"qty": -100}},
session=session,
)
Upon normal completion of ``with session.start_transaction()`` block, the
transaction automatically calls :meth:`ClientSession.commit_transaction`.

View File

@ -2533,14 +2533,13 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
.. code-block:: python
try:
with db.collection.watch(
[{'$match': {'operationType': 'insert'}}]) as stream:
with db.collection.watch([{"$match": {"operationType": "insert"}}]) as stream:
for insert_change in stream:
print(insert_change)
except pymongo.errors.PyMongoError:
# The ChangeStream encountered an unrecoverable error or the
# resume attempt failed to recreate the cursor.
logging.error('...')
logging.error("...")
For a precise description of the resume process see the
`change streams specification`_.

View File

@ -591,14 +591,13 @@ class Database(common.BaseObject, Generic[_DocumentType]):
.. code-block:: python
try:
with db.watch(
[{'$match': {'operationType': 'insert'}}]) as stream:
with db.watch([{"$match": {"operationType": "insert"}}]) as stream:
for insert_change in stream:
print(insert_change)
except pymongo.errors.PyMongoError:
# The ChangeStream encountered an unrecoverable error or the
# resume attempt failed to recreate the cursor.
logging.error('...')
logging.error("...")
For a precise description of the resume process see the
`change streams specification`_.

View File

@ -27,7 +27,7 @@ access:
>>> c = MongoClient()
>>> c.test_database
Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'test_database')
>>> c['test-database']
>>> c["test-database"]
Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'test-database')
"""
@ -935,14 +935,13 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
.. code-block:: python
try:
with client.watch(
[{'$match': {'operationType': 'insert'}}]) as stream:
with client.watch([{"$match": {"operationType": "insert"}}]) as stream:
for insert_change in stream:
print(insert_change)
except pymongo.errors.PyMongoError:
# The ChangeStream encountered an unrecoverable error or the
# resume attempt failed to recreate the cursor.
logging.error('...')
logging.error("...")
For a precise description of the resume process see the
`change streams specification`_.