Skip to content

Commit 87876b5

Browse files
committed
Merge branch 'master' of github.com:mongodb/mongo-python-driver
2 parents d6b3865 + 84db915 commit 87876b5

7 files changed

+66
-57
lines changed

doc/migrate-to-pymongo4.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,6 @@ pymongo.GEOHAYSTACK is removed
837837

838838
Removed :attr:`pymongo.GEOHAYSTACK`. Replace with "geoHaystack" or create a
839839
2d index and use $geoNear or $geoWithin instead.
840-
See https://dochub.mongodb.org/core/4.4-deprecate-geoHaystack.
841840

842841
UUIDLegacy is removed
843842
---------------------

test/asynchronous/test_client_bulk_write.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ async def test_formats_write_error_correctly(self):
8484

8585

8686
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
87+
# Note: tests 1 and 2 are in test_read_write_concern_spec.py
8788
class TestClientBulkWriteCRUD(AsyncIntegrationTest):
8889
async def asyncSetUp(self):
8990
await super().asyncSetUp()
@@ -92,7 +93,7 @@ async def asyncSetUp(self):
9293
self.max_message_size_bytes = await async_client_context.max_message_size_bytes
9394

9495
@async_client_context.require_version_min(8, 0, 0, -24)
95-
async def test_batch_splits_if_num_operations_too_large(self):
96+
async def test_3_batch_splits_if_num_operations_too_large(self):
9697
listener = OvertCommandListener()
9798
client = await self.async_rs_or_single_client(event_listeners=[listener])
9899

@@ -116,7 +117,7 @@ async def test_batch_splits_if_num_operations_too_large(self):
116117
self.assertEqual(first_event.operation_id, second_event.operation_id)
117118

118119
@async_client_context.require_version_min(8, 0, 0, -24)
119-
async def test_batch_splits_if_ops_payload_too_large(self):
120+
async def test_4_batch_splits_if_ops_payload_too_large(self):
120121
listener = OvertCommandListener()
121122
client = await self.async_rs_or_single_client(event_listeners=[listener])
122123

@@ -148,7 +149,7 @@ async def test_batch_splits_if_ops_payload_too_large(self):
148149

149150
@async_client_context.require_version_min(8, 0, 0, -24)
150151
@async_client_context.require_failCommand_fail_point
151-
async def test_collects_write_concern_errors_across_batches(self):
152+
async def test_5_collects_write_concern_errors_across_batches(self):
152153
listener = OvertCommandListener()
153154
client = await self.async_rs_or_single_client(
154155
event_listeners=[listener],
@@ -189,7 +190,7 @@ async def test_collects_write_concern_errors_across_batches(self):
189190
self.assertEqual(len(bulk_write_events), 2)
190191

191192
@async_client_context.require_version_min(8, 0, 0, -24)
192-
async def test_collects_write_errors_across_batches_unordered(self):
193+
async def test_6_collects_write_errors_across_batches_unordered(self):
193194
listener = OvertCommandListener()
194195
client = await self.async_rs_or_single_client(event_listeners=[listener])
195196

@@ -218,7 +219,7 @@ async def test_collects_write_errors_across_batches_unordered(self):
218219
self.assertEqual(len(bulk_write_events), 2)
219220

220221
@async_client_context.require_version_min(8, 0, 0, -24)
221-
async def test_collects_write_errors_across_batches_ordered(self):
222+
async def test_6_collects_write_errors_across_batches_ordered(self):
222223
listener = OvertCommandListener()
223224
client = await self.async_rs_or_single_client(event_listeners=[listener])
224225

@@ -247,7 +248,7 @@ async def test_collects_write_errors_across_batches_ordered(self):
247248
self.assertEqual(len(bulk_write_events), 1)
248249

249250
@async_client_context.require_version_min(8, 0, 0, -24)
250-
async def test_handles_cursor_requiring_getMore(self):
251+
async def test_7_handles_cursor_requiring_getMore(self):
251252
listener = OvertCommandListener()
252253
client = await self.async_rs_or_single_client(event_listeners=[listener])
253254

@@ -287,7 +288,7 @@ async def test_handles_cursor_requiring_getMore(self):
287288

288289
@async_client_context.require_version_min(8, 0, 0, -24)
289290
@async_client_context.require_no_standalone
290-
async def test_handles_cursor_requiring_getMore_within_transaction(self):
291+
async def test_8_handles_cursor_requiring_getMore_within_transaction(self):
291292
listener = OvertCommandListener()
292293
client = await self.async_rs_or_single_client(event_listeners=[listener])
293294

@@ -329,7 +330,7 @@ async def test_handles_cursor_requiring_getMore_within_transaction(self):
329330

330331
@async_client_context.require_version_min(8, 0, 0, -24)
331332
@async_client_context.require_failCommand_fail_point
332-
async def test_handles_getMore_error(self):
333+
async def test_9_handles_getMore_error(self):
333334
listener = OvertCommandListener()
334335
client = await self.async_rs_or_single_client(event_listeners=[listener])
335336

@@ -382,7 +383,7 @@ async def test_handles_getMore_error(self):
382383
self.assertTrue(kill_cursors_event)
383384

384385
@async_client_context.require_version_min(8, 0, 0, -24)
385-
async def test_returns_error_if_unacknowledged_too_large_insert(self):
386+
async def test_10_returns_error_if_unacknowledged_too_large_insert(self):
386387
listener = OvertCommandListener()
387388
client = await self.async_rs_or_single_client(event_listeners=[listener])
388389

@@ -441,7 +442,7 @@ async def _setup_namespace_test_models(self):
441442
return num_models, models
442443

443444
@async_client_context.require_version_min(8, 0, 0, -24)
444-
async def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
445+
async def test_11_no_batch_splits_if_new_namespace_is_not_too_large(self):
445446
listener = OvertCommandListener()
446447
client = await self.async_rs_or_single_client(event_listeners=[listener])
447448

@@ -471,7 +472,7 @@ async def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
471472
self.assertEqual(event.command["nsInfo"][0]["ns"], "db.coll")
472473

473474
@async_client_context.require_version_min(8, 0, 0, -24)
474-
async def test_batch_splits_if_new_namespace_is_too_large(self):
475+
async def test_11_batch_splits_if_new_namespace_is_too_large(self):
475476
listener = OvertCommandListener()
476477
client = await self.async_rs_or_single_client(event_listeners=[listener])
477478

@@ -508,25 +509,27 @@ async def test_batch_splits_if_new_namespace_is_too_large(self):
508509
self.assertEqual(second_event.command["nsInfo"][0]["ns"], namespace)
509510

510511
@async_client_context.require_version_min(8, 0, 0, -24)
511-
async def test_returns_error_if_no_writes_can_be_added_to_ops(self):
512+
async def test_12_returns_error_if_no_writes_can_be_added_to_ops(self):
512513
client = await self.async_rs_or_single_client()
513514

514515
# Document too large.
515516
b_repeated = "b" * self.max_message_size_bytes
516517
models = [InsertOne(namespace="db.coll", document={"a": b_repeated})]
517-
with self.assertRaises(DocumentTooLarge):
518+
with self.assertRaises(DocumentTooLarge) as context:
518519
await client.bulk_write(models=models)
520+
self.assertIsNone(context.exception.partial_result)
519521

520522
# Namespace too large.
521523
c_repeated = "c" * self.max_message_size_bytes
522524
namespace = f"db.{c_repeated}"
523525
models = [InsertOne(namespace=namespace, document={"a": "b"})]
524-
with self.assertRaises(DocumentTooLarge):
526+
with self.assertRaises(DocumentTooLarge) as context:
525527
await client.bulk_write(models=models)
528+
self.assertIsNone(context.exception.partial_result)
526529

527530
@async_client_context.require_version_min(8, 0, 0, -24)
528531
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
529-
async def test_returns_error_if_auto_encryption_configured(self):
532+
async def test_13_returns_error_if_auto_encryption_configured(self):
530533
opts = AutoEncryptionOpts(
531534
key_vault_namespace="db.coll",
532535
kms_providers={"aws": {"accessKeyId": "foo", "secretAccessKey": "bar"}},
@@ -536,6 +539,7 @@ async def test_returns_error_if_auto_encryption_configured(self):
536539
models = [InsertOne(namespace="db.coll", document={"a": "b"})]
537540
with self.assertRaises(InvalidOperation) as context:
538541
await client.bulk_write(models=models)
542+
self.assertIsNone(context.exception.partial_result)
539543
self.assertIn(
540544
"bulk_write does not currently support automatic encryption", context.exception._message
541545
)
@@ -579,6 +583,8 @@ async def test_upserted_result(self):
579583
self.assertEqual(result.update_results[1].did_upsert, True)
580584
self.assertEqual(result.update_results[2].did_upsert, False)
581585

586+
# Note: test 14 is optional and intentionally not implemented because we provide multiple APIs to specify explain.
587+
582588
@async_client_context.require_version_min(8, 0, 0, -24)
583589
async def test_15_unacknowledged_write_across_batches(self):
584590
listener = OvertCommandListener()

test/asynchronous/test_encryption.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,7 +1306,7 @@ async def asyncSetUp(self):
13061306
kms_providers_invalid = copy.deepcopy(kms_providers)
13071307
kms_providers_invalid["azure"]["identityPlatformEndpoint"] = "doesnotexist.invalid:443"
13081308
kms_providers_invalid["gcp"]["endpoint"] = "doesnotexist.invalid:443"
1309-
kms_providers_invalid["kmip"]["endpoint"] = "doesnotexist.local:5698"
1309+
kms_providers_invalid["kmip"]["endpoint"] = "doesnotexist.invalid:5698"
13101310
self.client_encryption_invalid = self.create_client_encryption(
13111311
kms_providers=kms_providers_invalid,
13121312
key_vault_namespace="keyvault.datakeys",
@@ -1364,15 +1364,10 @@ async def test_03_aws_region_key_endpoint_port(self):
13641364
},
13651365
)
13661366

1367-
@unittest.skipUnless(any(AWS_CREDS.values()), "AWS environment credentials are not set")
1368-
async def test_04_aws_endpoint_invalid_port(self):
1369-
master_key = {
1370-
"region": "us-east-1",
1371-
"key": ("arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0"),
1372-
"endpoint": "kms.us-east-1.amazonaws.com:12345",
1373-
}
1374-
with self.assertRaisesRegex(EncryptionError, "kms.us-east-1.amazonaws.com:12345"):
1375-
await self.client_encryption.create_data_key("aws", master_key=master_key)
1367+
async def test_04_kmip_endpoint_invalid_port(self):
1368+
master_key = {"keyId": "1", "endpoint": "localhost:12345"}
1369+
with self.assertRaisesRegex(EncryptionError, "localhost:12345"):
1370+
await self.client_encryption.create_data_key("kmip", master_key=master_key)
13761371

13771372
@unittest.skipUnless(any(AWS_CREDS.values()), "AWS environment credentials are not set")
13781373
async def test_05_aws_endpoint_wrong_region(self):
@@ -1478,7 +1473,7 @@ async def test_11_kmip_master_key_endpoint(self):
14781473
self.assertEqual("test", await self.client_encryption_invalid.decrypt(encrypted))
14791474

14801475
async def test_12_kmip_master_key_invalid_endpoint(self):
1481-
key = {"keyId": "1", "endpoint": "doesnotexist.local:5698"}
1476+
key = {"keyId": "1", "endpoint": "doesnotexist.invalid:5698"}
14821477
with self.assertRaisesRegex(EncryptionError, self.kmip_host_error):
14831478
await self.client_encryption.create_data_key("kmip", key)
14841479

@@ -2166,7 +2161,7 @@ async def test_01_aws(self):
21662161
await self.client_encryption_invalid_hostname.create_data_key("aws", key)
21672162

21682163
async def test_02_azure(self):
2169-
key = {"keyVaultEndpoint": "doesnotexist.local", "keyName": "foo"}
2164+
key = {"keyVaultEndpoint": "doesnotexist.invalid", "keyName": "foo"}
21702165
# Missing client cert error.
21712166
with self.assertRaisesRegex(EncryptionError, self.cert_error):
21722167
await self.client_encryption_no_client_cert.create_data_key("azure", key)
@@ -2241,7 +2236,7 @@ async def test_06_named_kms_providers_apply_tls_options_aws(self):
22412236
await self.client_encryption_with_names.create_data_key("aws:with_tls", key)
22422237

22432238
async def test_06_named_kms_providers_apply_tls_options_azure(self):
2244-
key = {"keyVaultEndpoint": "doesnotexist.local", "keyName": "foo"}
2239+
key = {"keyVaultEndpoint": "doesnotexist.invalid", "keyName": "foo"}
22452240
# Missing client cert error.
22462241
with self.assertRaisesRegex(EncryptionError, self.cert_error):
22472242
await self.client_encryption_with_names.create_data_key("azure:no_client_cert", key)

test/asynchronous/test_read_write_concern_spec.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ async def test_raise_wtimeout(self):
180180
WriteConcern(w=async_client_context.w, wtimeout=1), WTimeoutError
181181
)
182182

183+
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
184+
# Test 1 (included here instead of test_client_bulk_write.py)
183185
@async_client_context.require_failCommand_fail_point
184186
async def test_error_includes_errInfo(self):
185187
expected_wce = {
@@ -214,6 +216,8 @@ async def test_error_includes_errInfo(self):
214216
}
215217
self.assertEqual(ctx.exception.details, expected_details)
216218

219+
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
220+
# Test 2 (included here instead of test_client_bulk_write.py)
217221
@async_client_context.require_version_min(4, 9)
218222
async def test_write_error_details_exposes_errinfo(self):
219223
listener = OvertCommandListener()

test/test_client_bulk_write.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def test_formats_write_error_correctly(self):
8484

8585

8686
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
87+
# Note: tests 1 and 2 are in test_read_write_concern_spec.py
8788
class TestClientBulkWriteCRUD(IntegrationTest):
8889
def setUp(self):
8990
super().setUp()
@@ -92,7 +93,7 @@ def setUp(self):
9293
self.max_message_size_bytes = client_context.max_message_size_bytes
9394

9495
@client_context.require_version_min(8, 0, 0, -24)
95-
def test_batch_splits_if_num_operations_too_large(self):
96+
def test_3_batch_splits_if_num_operations_too_large(self):
9697
listener = OvertCommandListener()
9798
client = self.rs_or_single_client(event_listeners=[listener])
9899

@@ -116,7 +117,7 @@ def test_batch_splits_if_num_operations_too_large(self):
116117
self.assertEqual(first_event.operation_id, second_event.operation_id)
117118

118119
@client_context.require_version_min(8, 0, 0, -24)
119-
def test_batch_splits_if_ops_payload_too_large(self):
120+
def test_4_batch_splits_if_ops_payload_too_large(self):
120121
listener = OvertCommandListener()
121122
client = self.rs_or_single_client(event_listeners=[listener])
122123

@@ -148,7 +149,7 @@ def test_batch_splits_if_ops_payload_too_large(self):
148149

149150
@client_context.require_version_min(8, 0, 0, -24)
150151
@client_context.require_failCommand_fail_point
151-
def test_collects_write_concern_errors_across_batches(self):
152+
def test_5_collects_write_concern_errors_across_batches(self):
152153
listener = OvertCommandListener()
153154
client = self.rs_or_single_client(
154155
event_listeners=[listener],
@@ -189,7 +190,7 @@ def test_collects_write_concern_errors_across_batches(self):
189190
self.assertEqual(len(bulk_write_events), 2)
190191

191192
@client_context.require_version_min(8, 0, 0, -24)
192-
def test_collects_write_errors_across_batches_unordered(self):
193+
def test_6_collects_write_errors_across_batches_unordered(self):
193194
listener = OvertCommandListener()
194195
client = self.rs_or_single_client(event_listeners=[listener])
195196

@@ -218,7 +219,7 @@ def test_collects_write_errors_across_batches_unordered(self):
218219
self.assertEqual(len(bulk_write_events), 2)
219220

220221
@client_context.require_version_min(8, 0, 0, -24)
221-
def test_collects_write_errors_across_batches_ordered(self):
222+
def test_6_collects_write_errors_across_batches_ordered(self):
222223
listener = OvertCommandListener()
223224
client = self.rs_or_single_client(event_listeners=[listener])
224225

@@ -247,7 +248,7 @@ def test_collects_write_errors_across_batches_ordered(self):
247248
self.assertEqual(len(bulk_write_events), 1)
248249

249250
@client_context.require_version_min(8, 0, 0, -24)
250-
def test_handles_cursor_requiring_getMore(self):
251+
def test_7_handles_cursor_requiring_getMore(self):
251252
listener = OvertCommandListener()
252253
client = self.rs_or_single_client(event_listeners=[listener])
253254

@@ -287,7 +288,7 @@ def test_handles_cursor_requiring_getMore(self):
287288

288289
@client_context.require_version_min(8, 0, 0, -24)
289290
@client_context.require_no_standalone
290-
def test_handles_cursor_requiring_getMore_within_transaction(self):
291+
def test_8_handles_cursor_requiring_getMore_within_transaction(self):
291292
listener = OvertCommandListener()
292293
client = self.rs_or_single_client(event_listeners=[listener])
293294

@@ -329,7 +330,7 @@ def test_handles_cursor_requiring_getMore_within_transaction(self):
329330

330331
@client_context.require_version_min(8, 0, 0, -24)
331332
@client_context.require_failCommand_fail_point
332-
def test_handles_getMore_error(self):
333+
def test_9_handles_getMore_error(self):
333334
listener = OvertCommandListener()
334335
client = self.rs_or_single_client(event_listeners=[listener])
335336

@@ -382,7 +383,7 @@ def test_handles_getMore_error(self):
382383
self.assertTrue(kill_cursors_event)
383384

384385
@client_context.require_version_min(8, 0, 0, -24)
385-
def test_returns_error_if_unacknowledged_too_large_insert(self):
386+
def test_10_returns_error_if_unacknowledged_too_large_insert(self):
386387
listener = OvertCommandListener()
387388
client = self.rs_or_single_client(event_listeners=[listener])
388389

@@ -437,7 +438,7 @@ def _setup_namespace_test_models(self):
437438
return num_models, models
438439

439440
@client_context.require_version_min(8, 0, 0, -24)
440-
def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
441+
def test_11_no_batch_splits_if_new_namespace_is_not_too_large(self):
441442
listener = OvertCommandListener()
442443
client = self.rs_or_single_client(event_listeners=[listener])
443444

@@ -467,7 +468,7 @@ def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
467468
self.assertEqual(event.command["nsInfo"][0]["ns"], "db.coll")
468469

469470
@client_context.require_version_min(8, 0, 0, -24)
470-
def test_batch_splits_if_new_namespace_is_too_large(self):
471+
def test_11_batch_splits_if_new_namespace_is_too_large(self):
471472
listener = OvertCommandListener()
472473
client = self.rs_or_single_client(event_listeners=[listener])
473474

@@ -504,25 +505,27 @@ def test_batch_splits_if_new_namespace_is_too_large(self):
504505
self.assertEqual(second_event.command["nsInfo"][0]["ns"], namespace)
505506

506507
@client_context.require_version_min(8, 0, 0, -24)
507-
def test_returns_error_if_no_writes_can_be_added_to_ops(self):
508+
def test_12_returns_error_if_no_writes_can_be_added_to_ops(self):
508509
client = self.rs_or_single_client()
509510

510511
# Document too large.
511512
b_repeated = "b" * self.max_message_size_bytes
512513
models = [InsertOne(namespace="db.coll", document={"a": b_repeated})]
513-
with self.assertRaises(DocumentTooLarge):
514+
with self.assertRaises(DocumentTooLarge) as context:
514515
client.bulk_write(models=models)
516+
self.assertIsNone(context.exception.partial_result)
515517

516518
# Namespace too large.
517519
c_repeated = "c" * self.max_message_size_bytes
518520
namespace = f"db.{c_repeated}"
519521
models = [InsertOne(namespace=namespace, document={"a": "b"})]
520-
with self.assertRaises(DocumentTooLarge):
522+
with self.assertRaises(DocumentTooLarge) as context:
521523
client.bulk_write(models=models)
524+
self.assertIsNone(context.exception.partial_result)
522525

523526
@client_context.require_version_min(8, 0, 0, -24)
524527
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
525-
def test_returns_error_if_auto_encryption_configured(self):
528+
def test_13_returns_error_if_auto_encryption_configured(self):
526529
opts = AutoEncryptionOpts(
527530
key_vault_namespace="db.coll",
528531
kms_providers={"aws": {"accessKeyId": "foo", "secretAccessKey": "bar"}},
@@ -532,6 +535,7 @@ def test_returns_error_if_auto_encryption_configured(self):
532535
models = [InsertOne(namespace="db.coll", document={"a": "b"})]
533536
with self.assertRaises(InvalidOperation) as context:
534537
client.bulk_write(models=models)
538+
self.assertIsNone(context.exception.partial_result)
535539
self.assertIn(
536540
"bulk_write does not currently support automatic encryption", context.exception._message
537541
)
@@ -575,6 +579,8 @@ def test_upserted_result(self):
575579
self.assertEqual(result.update_results[1].did_upsert, True)
576580
self.assertEqual(result.update_results[2].did_upsert, False)
577581

582+
# Note: test 14 is optional and intentionally not implemented because we provide multiple APIs to specify explain.
583+
578584
@client_context.require_version_min(8, 0, 0, -24)
579585
def test_15_unacknowledged_write_across_batches(self):
580586
listener = OvertCommandListener()

0 commit comments

Comments
 (0)