Skip to content

Commit dd5237c

Browse files
author
Mike Dirolf
committed
adding DuplicateKeyError for safe inserts/updates
1 parent e3fd6e3 commit dd5237c

File tree

5 files changed

+34
-4
lines changed

5 files changed

+34
-4
lines changed

pymongo/collection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from objectid import ObjectId
2424
from cursor import Cursor
2525
from son import SON
26-
from errors import InvalidName, OperationFailure
26+
from errors import InvalidName
2727
from code import Code
2828

2929
_ZERO = "\x00\x00\x00\x00"

pymongo/connection.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
import warnings
4545

4646
from errors import ConnectionFailure, ConfigurationError, AutoReconnect
47-
from errors import OperationFailure
47+
from errors import OperationFailure, DuplicateKeyError
4848
from database import Database
4949
from cursor_manager import CursorManager
5050
import bson
@@ -441,7 +441,11 @@ def __check_response_to_last_error(self, response):
441441
return
442442
if error["err"] == "not master":
443443
self._reset()
444-
raise OperationFailure(error["err"])
444+
445+
if "code" in error and error["code"] in [11000, 11001]:
446+
raise DuplicateKeyError(error["err"])
447+
else:
448+
raise OperationFailure(error["err"])
445449

446450
def _send_message(self, message, with_last_error=False):
447451
"""Say something to Mongo.

pymongo/cursor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import message
2323
from son import SON
2424
from code import Code
25-
from errors import InvalidOperation, OperationFailure, AutoReconnect
25+
from errors import InvalidOperation, AutoReconnect
2626

2727
_QUERY_OPTIONS = {
2828
"tailable_cursor": 2,

pymongo/errors.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class OperationFailure(Exception):
4242
"""
4343

4444

45+
class DuplicateKeyError(OperationFailure):
46+
"""Raised when a safe insert or update fails due to a duplicate key error.
47+
"""
48+
49+
4550
class InvalidOperation(Exception):
4651
"""Raised when a client attempts to perform an invalid operation.
4752
"""

test/test_collection.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from pymongo.binary import Binary
3232
from pymongo.collection import Collection
3333
from pymongo.errors import InvalidName, OperationFailure, InvalidDocument
34+
from pymongo.errors import DuplicateKeyError
3435
from pymongo import ASCENDING, DESCENDING
3536
from pymongo.son import SON
3637

@@ -462,6 +463,26 @@ def test_unique_index(self):
462463
db.test.save({"hello": "world"})
463464
self.assert_(db.error())
464465

466+
def test_duplicate_key_error(self):
467+
db = self.db
468+
db.drop_collection("test")
469+
470+
db.test.create_index("x", unique=True)
471+
472+
db.test.insert({"_id": 1, "x": 1}, safe=True)
473+
db.test.insert({"_id": 2, "x": 2}, safe=True)
474+
475+
self.assertRaises(DuplicateKeyError,
476+
db.test.insert, {"_id": 1}, safe=True)
477+
self.assertRaises(DuplicateKeyError,
478+
db.test.insert, {"x": 1}, safe=True)
479+
480+
self.assertRaises(DuplicateKeyError,
481+
db.test.save, {"x": 2}, safe=True)
482+
self.assertRaises(DuplicateKeyError,
483+
db.test.update, {"x": 1}, {"$inc": {"x": 1}}, safe=True)
484+
485+
465486
def test_index_on_subfield(self):
466487
db = self.db
467488
db.drop_collection("test")

0 commit comments

Comments
 (0)