Skip to content

Commit 85db128

Browse files
committed
PYTHON-526 Remove the "safe" option.
Use w=0 for unacknowledged write operations.
1 parent e08aa1f commit 85db128

File tree

13 files changed

+44
-195
lines changed

13 files changed

+44
-195
lines changed

doc/api/pymongo/collection.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
.. autoattribute:: secondary_acceptable_latency_ms
2929
.. autoattribute:: write_concern
3030
.. autoattribute:: uuid_subtype
31-
.. automethod:: insert(doc_or_docs[, manipulate=True[, safe=None[, check_keys=True[, continue_on_error=False[, **kwargs]]]]])
32-
.. automethod:: save(to_save[, manipulate=True[, safe=None[, check_keys=True[, **kwargs]]]])
33-
.. automethod:: update(spec, document[, upsert=False[, manipulate=False[, safe=None[, multi=False[, check_keys=True[, **kwargs]]]]]])
34-
.. automethod:: remove([spec_or_id=None[, safe=None[, multi=True[, **kwargs]]]])
31+
.. automethod:: insert(doc_or_docs[, manipulate=True[, check_keys=True[, continue_on_error=False[, **kwargs]]]])
32+
.. automethod:: save(to_save[, manipulate=True[, check_keys=True[, **kwargs]]])
33+
.. automethod:: update(spec, document[, upsert=False[, manipulate=False[, multi=False[, check_keys=True[, **kwargs]]]]])
34+
.. automethod:: remove([spec_or_id=None[, multi=True[, **kwargs]]])
3535
.. automethod:: initialize_unordered_bulk_op
3636
.. automethod:: initialize_ordered_bulk_op
3737
.. automethod:: drop
@@ -53,7 +53,6 @@
5353
.. automethod:: map_reduce
5454
.. automethod:: inline_map_reduce
5555
.. automethod:: find_and_modify
56-
.. autoattribute:: safe
5756
.. automethod:: get_lasterror_options
5857
.. automethod:: set_lasterror_options
5958
.. automethod:: unset_lasterror_options

doc/api/pymongo/database.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
.. autoattribute:: secondary_acceptable_latency_ms
2929
.. autoattribute:: write_concern
3030
.. autoattribute:: uuid_subtype
31-
.. autoattribute:: safe
3231
.. automethod:: get_lasterror_options
3332
.. automethod:: set_lasterror_options
3433
.. automethod:: unset_lasterror_options

doc/api/pymongo/master_slave_connection.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
.. autoclass:: pymongo.master_slave_connection.MasterSlaveConnection
88
:members:
99

10-
.. autoattribute:: safe
1110
.. automethod:: get_lasterror_options
1211
.. automethod:: set_lasterror_options
1312
.. automethod:: unset_lasterror_options

doc/examples/requests.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ the previous example more terse:
8989
... {'region': region, 'browser': browser, 'os': os},
9090
... {'$inc': {'n': 1 }},
9191
... upsert=True,
92-
... safe=False)
92+
... w=0)
9393
... print sum([p['n'] for p in counts.find({'region': region})])
9494
2
9595
>>> client.in_request() # request automatically ended

pymongo/collection.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ def __init__(self, database, name, create=False, **kwargs):
9090
tag_sets=database.tag_sets,
9191
secondary_acceptable_latency_ms=(
9292
database.secondary_acceptable_latency_ms),
93-
safe=database.safe,
9493
uuidrepresentation=database.uuid_subtype,
9594
**database.write_concern)
9695

@@ -213,8 +212,7 @@ def initialize_ordered_bulk_op(self):
213212
"""
214213
return bulk.BulkOperationBuilder(self, ordered=True)
215214

216-
def save(self, to_save, manipulate=True,
217-
safe=None, check_keys=True, **kwargs):
215+
def save(self, to_save, manipulate=True, check_keys=True, **kwargs):
218216
"""Save a document in this collection.
219217
220218
If `to_save` already has an ``"_id"`` then an :meth:`update`
@@ -243,7 +241,6 @@ def save(self, to_save, manipulate=True,
243241
- `to_save`: the document to be saved
244242
- `manipulate` (optional): manipulate the document before
245243
saving it?
246-
- `safe` (optional): **DEPRECATED** - Use `w` instead.
247244
- `check_keys` (optional): check if keys start with '$' or
248245
contain '.', raising :class:`~pymongo.errors.InvalidName`
249246
in either case.
@@ -267,6 +264,8 @@ def save(self, to_save, manipulate=True,
267264
- The ``'_id'`` value of `to_save` or ``[None]`` if `manipulate` is
268265
``False`` and `to_save` has no '_id' field.
269266
267+
.. versionchanged:: 3.0
268+
Removed the `safe` parameter
270269
.. versionadded:: 1.8
271270
Support for passing `getLastError` options as keyword
272271
arguments.
@@ -277,14 +276,14 @@ def save(self, to_save, manipulate=True,
277276
raise TypeError("cannot save object of type %s" % type(to_save))
278277

279278
if "_id" not in to_save:
280-
return self.insert(to_save, manipulate, safe, check_keys, **kwargs)
279+
return self.insert(to_save, manipulate, check_keys, **kwargs)
281280
else:
282281
self.update({"_id": to_save["_id"]}, to_save, True,
283-
manipulate, safe, check_keys=check_keys, **kwargs)
282+
manipulate, check_keys=check_keys, **kwargs)
284283
return to_save.get("_id", None)
285284

286285
def insert(self, doc_or_docs, manipulate=True,
287-
safe=None, check_keys=True, continue_on_error=False, **kwargs):
286+
check_keys=True, continue_on_error=False, **kwargs):
288287
"""Insert a document(s) into this collection.
289288
290289
If `manipulate` is ``True``, the document(s) are manipulated using
@@ -312,7 +311,6 @@ def insert(self, doc_or_docs, manipulate=True,
312311
inserted
313312
- `manipulate` (optional): If ``True`` manipulate the documents
314313
before inserting.
315-
- `safe` (optional): **DEPRECATED** - Use `w` instead.
316314
- `check_keys` (optional): If ``True`` check if keys start with '$'
317315
or contain '.', raising :class:`~pymongo.errors.InvalidName` in
318316
either case.
@@ -345,6 +343,8 @@ def insert(self, doc_or_docs, manipulate=True,
345343
346344
.. note:: `continue_on_error` requires server version **>= 1.9.1**
347345
346+
.. versionchanged:: 3.0
347+
Removed the `safe` parameter
348348
.. versionadded:: 2.1
349349
Support for continue_on_error.
350350
.. versionadded:: 1.8
@@ -386,7 +386,7 @@ def gen():
386386
ids.append(doc.get('_id'))
387387
yield doc
388388

389-
safe, options = self._get_write_mode(safe, **kwargs)
389+
safe, options = self._get_write_mode(kwargs)
390390

391391
if client.max_wire_version > 1 and safe:
392392
# Insert command
@@ -412,7 +412,7 @@ def gen():
412412
return ids
413413

414414
def update(self, spec, document, upsert=False, manipulate=False,
415-
safe=None, multi=False, check_keys=True, **kwargs):
415+
multi=False, check_keys=True, **kwargs):
416416
"""Update a document(s) in this collection.
417417
418418
Raises :class:`TypeError` if either `spec` or `document` is
@@ -464,7 +464,6 @@ def update(self, spec, document, upsert=False, manipulate=False,
464464
:class:`~pymongo.errors.InvalidName`. Only applies to
465465
document replacement, not modification through $
466466
operators.
467-
- `safe` (optional): **DEPRECATED** - Use `w` instead.
468467
- `multi` (optional): update all documents that match
469468
`spec`, rather than just the first matching document. The
470469
default value for `multi` is currently ``False``, but this
@@ -491,6 +490,8 @@ def update(self, spec, document, upsert=False, manipulate=False,
491490
- A document (dict) describing the effect of the update or ``None``
492491
if write acknowledgement is disabled.
493492
493+
.. versionchanged:: 3.0
494+
Removed the `safe` parameter
494495
.. versionadded:: 1.8
495496
Support for passing `getLastError` options as keyword
496497
arguments.
@@ -517,7 +518,7 @@ def update(self, spec, document, upsert=False, manipulate=False,
517518
if manipulate:
518519
document = self.__database._fix_incoming(document, self)
519520

520-
safe, options = self._get_write_mode(safe, **kwargs)
521+
safe, options = self._get_write_mode(kwargs)
521522

522523
if document:
523524
# If a top level key begins with '$' this is a modify operation
@@ -571,7 +572,7 @@ def drop(self):
571572
"""
572573
self.__database.drop_collection(self.__name)
573574

574-
def remove(self, spec_or_id=None, safe=None, multi=True, **kwargs):
575+
def remove(self, spec_or_id=None, multi=True, **kwargs):
575576
"""Remove a document(s) from this collection.
576577
577578
.. warning:: Calls to :meth:`remove` should be performed with
@@ -596,7 +597,6 @@ def remove(self, spec_or_id=None, safe=None, multi=True, **kwargs):
596597
- `spec_or_id` (optional): a dictionary specifying the
597598
documents to be removed OR any other type specifying the
598599
value of ``"_id"`` for the document to be removed
599-
- `safe` (optional): **DEPRECATED** - Use `w` instead.
600600
- `multi` (optional): If ``True`` (the default) remove all documents
601601
matching `spec_or_id`, otherwise remove only the first matching
602602
document.
@@ -620,6 +620,8 @@ def remove(self, spec_or_id=None, safe=None, multi=True, **kwargs):
620620
- A document (dict) describing the effect of the remove or ``None``
621621
if write acknowledgement is disabled.
622622
623+
.. versionchanged:: 3.0
624+
Removed the `safe` parameter
623625
.. versionadded:: 1.8
624626
Support for passing `getLastError` options as keyword arguments.
625627
.. versionchanged:: 1.7 Accept any type other than a ``dict``
@@ -641,7 +643,7 @@ def remove(self, spec_or_id=None, safe=None, multi=True, **kwargs):
641643
if not isinstance(spec_or_id, dict):
642644
spec_or_id = {"_id": spec_or_id}
643645

644-
safe, options = self._get_write_mode(safe, **kwargs)
646+
safe, options = self._get_write_mode(kwargs)
645647

646648
client = self.database.connection
647649

pymongo/common.py

Lines changed: 17 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ def validate_uuid_subtype(dummy, value):
252252
# readpreferencetags is an alias for tag_sets.
253253
VALIDATORS = {
254254
'replicaset': validate_basestring,
255-
'safe': validate_boolean,
256255
'w': validate_int_or_basestring,
257256
'wtimeout': validate_integer,
258257
'wtimeoutms': validate_integer,
@@ -305,7 +304,7 @@ def validate(option, value):
305304
return lower, value
306305

307306

308-
SAFE_OPTIONS = frozenset([
307+
WRITE_CONCERN_OPTIONS = frozenset([
309308
'w',
310309
'wtimeout',
311310
'wtimeoutms',
@@ -324,7 +323,7 @@ def __init__(self, *args, **kwargs):
324323
super(WriteConcern, self).__init__(*args, **kwargs)
325324

326325
def __setitem__(self, key, value):
327-
if key not in SAFE_OPTIONS:
326+
if key not in WRITE_CONCERN_OPTIONS:
328327
raise ConfigurationError("%s is not a valid write "
329328
"concern option." % (key,))
330329
key, value = validate(key, value)
@@ -343,7 +342,6 @@ def __init__(self, **options):
343342
self.__read_pref = ReadPreference.PRIMARY
344343
self.__tag_sets = [{}]
345344
self.__secondary_acceptable_latency_ms = 15
346-
self.__safe = None
347345
self.__uuid_subtype = OLD_UUID_SUBTYPE
348346
self.__write_concern = WriteConcern()
349347
self.__set_options(options)
@@ -352,31 +350,14 @@ def __init__(self, **options):
352350
raise ConfigurationError(
353351
"ReadPreference PRIMARY cannot be combined with tags")
354352

355-
# If safe hasn't been implicitly set by write concerns then set it.
356-
if self.__safe is None:
357-
if options.get("w") == 0:
358-
self.__safe = False
359-
else:
360-
self.__safe = validate_boolean('safe',
361-
options.get("safe", True))
362-
# Always do the most "safe" thing, but warn about conflicts.
363-
if self.__safe and options.get('w') == 0:
364-
365-
warnings.warn("Conflicting write concerns: %s. Write concern "
366-
"options were configured, but w=0 disables all "
367-
"other options." % self.write_concern,
368-
UserWarning)
369-
370-
def __set_safe_option(self, option, value):
353+
def __set_write_concern_option(self, option, value):
371354
"""Validates and sets getlasterror options for this
372355
object (MongoClient, Database, Collection, etc.)
373356
"""
374357
if value is None:
375358
self.__write_concern.pop(option, None)
376359
else:
377360
self.__write_concern[option] = value
378-
if option != "w" or value != 0:
379-
self.__safe = True
380361

381362
def __set_options(self, options):
382363
"""Validates and sets all options passed to this object."""
@@ -393,13 +374,13 @@ def __set_options(self, options):
393374
):
394375
self.__secondary_acceptable_latency_ms = \
395376
validate_positive_float(option, value)
396-
elif option in SAFE_OPTIONS:
377+
elif option in WRITE_CONCERN_OPTIONS:
397378
if option == 'journal':
398-
self.__set_safe_option('j', value)
379+
self.__set_write_concern_option('j', value)
399380
elif option == 'wtimeoutms':
400-
self.__set_safe_option('wtimeout', value)
381+
self.__set_write_concern_option('wtimeout', value)
401382
else:
402-
self.__set_safe_option(option, value)
383+
self.__set_write_concern_option(option, value)
403384

404385
def __set_write_concern(self, value):
405386
"""Property setter for write_concern."""
@@ -546,24 +527,6 @@ def __set_uuid_subtype(self, value):
546527

547528
uuid_subtype = property(__get_uuid_subtype, __set_uuid_subtype)
548529

549-
def __get_safe(self):
550-
"""**DEPRECATED:** Use the 'w' :attr:`write_concern` option instead.
551-
552-
Use getlasterror with every write operation?
553-
554-
.. versionadded:: 2.0
555-
"""
556-
return self.__safe
557-
558-
def __set_safe(self, value):
559-
"""Property setter for safe"""
560-
warnings.warn("safe is deprecated. Please use the"
561-
" 'w' write_concern option instead.",
562-
DeprecationWarning, stacklevel=2)
563-
self.__safe = validate_boolean('safe', value)
564-
565-
safe = property(__get_safe, __set_safe)
566-
567530
def get_lasterror_options(self):
568531
"""DEPRECATED: Use :attr:`write_concern` instead.
569532
@@ -584,7 +547,7 @@ def set_lasterror_options(self, **kwargs):
584547
Set getlasterror options for this instance.
585548
586549
Valid options include j=<bool>, w=<int/string>, wtimeout=<int>,
587-
and fsync=<bool>. Implies safe=True.
550+
and fsync=<bool>.
588551
589552
:Parameters:
590553
- `**kwargs`: Options should be passed as keyword
@@ -598,15 +561,14 @@ def set_lasterror_options(self, **kwargs):
598561
"write_concern instead.", DeprecationWarning,
599562
stacklevel=2)
600563
for key, value in kwargs.iteritems():
601-
self.__set_safe_option(key, value)
564+
self.__set_write_concern_option(key, value)
602565

603566
def unset_lasterror_options(self, *options):
604567
"""DEPRECATED: Use :attr:`write_concern` instead.
605568
606569
Unset getlasterror options for this instance.
607570
608571
If no options are passed unsets all getlasterror options.
609-
This does not set `safe` to False.
610572
611573
:Parameters:
612574
- `*options`: The list of options to unset.
@@ -631,55 +593,22 @@ def _get_wc_override(self):
631593
We don't want to override user write concern options if write concern
632594
is already enabled.
633595
"""
634-
if self.safe and self.__write_concern.get('w') != 0:
596+
if self.__write_concern.get('w') != 0:
635597
return {}
636598
return {'w': 1}
637599

638-
def _get_write_mode(self, safe=None, **options):
600+
def _get_write_mode(self, options):
639601
"""Get the current write mode.
640602
641-
Determines if the current write is safe or not based on the
642-
passed in or inherited safe value, write_concern values, or
643-
passed options.
603+
Determines if the current write is acknowledged or not based on the
604+
inherited write_concern values, or passed options.
644605
645606
:Parameters:
646-
- `safe`: check that the operation succeeded?
647-
- `**options`: overriding write concern options.
607+
- `options`: overriding write concern options.
648608
649609
.. versionadded:: 2.3
650610
"""
651-
# Don't ever send w=1 to the server.
652-
def pop1(dct):
653-
if dct.get('w') == 1:
654-
dct.pop('w')
655-
return dct
656-
657-
if safe is not None:
658-
warnings.warn("The safe parameter is deprecated. Please use "
659-
"write concern options instead.", DeprecationWarning,
660-
stacklevel=3)
661-
validate_boolean('safe', safe)
662-
663-
# Passed options override collection level defaults.
664-
if safe is not None or options:
665-
if safe or options:
666-
if not options:
667-
options = self.__write_concern.copy()
668-
# Backwards compatability edge case. Call getLastError
669-
# with no options if safe=True was passed but collection
670-
# level defaults have been disabled with w=0.
671-
# These should be equivalent:
672-
if options.get('w') == 0:
673-
return True, {}
674-
# Passing w=0 overrides passing safe=True.
675-
return options.get('w') != 0, pop1(options)
611+
write_concern = options or self.__write_concern
612+
if write_concern.get('w') == 0:
676613
return False, {}
677-
678-
# Fall back to collection level defaults.
679-
# w=0 takes precedence over self.safe = True
680-
if self.__write_concern.get('w') == 0:
681-
return False, {}
682-
elif self.safe or self.__write_concern.get('w', 0) != 0:
683-
return True, pop1(self.__write_concern.copy())
684-
685-
return False, {}
614+
return True, write_concern

0 commit comments

Comments
 (0)