def simplify(case): # TODO this is a hack if isinstance(case, SON) and "$ref" not in case: simplified = SON(case) # make a copy! if random.choice([True, False]): # delete if not len(simplified.keys()): return (False, case) del simplified[random.choice(simplified.keys())] return (True, simplified) else: # simplify a value if not len(simplified.items()): return (False, case) (key, value) = random.choice(simplified.items()) (success, value) = simplify(value) simplified[key] = value return (success, success and simplified or case) if isinstance(case, list): simplified = list(case) if random.choice([True, False]): # delete if not len(simplified): return (False, case) simplified.pop(random.randrange(len(simplified))) return (True, simplified) else: # simplify an item if not len(simplified): return (False, case) index = random.randrange(len(simplified)) (success, value) = simplify(simplified[index]) simplified[index] = value return (success, success and simplified or case) return (False, case)
def test_copying(self): simple_son = SON([]) complex_son = SON([('son', simple_son), ('list', [simple_son, simple_son])]) regex_son = SON([("x", re.compile("^hello.*"))]) reflexive_son = SON([('son', simple_son)]) reflexive_son["reflexive"] = reflexive_son simple_son1 = copy.copy(simple_son) self.assertEqual(simple_son, simple_son1) complex_son1 = copy.copy(complex_son) self.assertEqual(complex_son, complex_son1) regex_son1 = copy.copy(regex_son) self.assertEqual(regex_son, regex_son1) reflexive_son1 = copy.copy(reflexive_son) self.assertEqual(reflexive_son, reflexive_son1) # Test deepcopying simple_son1 = copy.deepcopy(simple_son) self.assertEqual(simple_son, simple_son1) regex_son1 = copy.deepcopy(regex_son) self.assertEqual(regex_son, regex_son1) complex_son1 = copy.deepcopy(complex_son) self.assertEqual(complex_son, complex_son1) reflexive_son1 = copy.deepcopy(reflexive_son) self.assertEqual(reflexive_son.keys(), reflexive_son1.keys()) self.assertEqual(id(reflexive_son1), id(reflexive_son1["reflexive"]))
def _command(self, command, value=1, check=True, allowable_errors=None, uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, read_preference=None, **kwargs): """Internal command helper. """ if isinstance(command, basestring): command_name = command.lower() command = SON([(command, value)]) else: command_name = command.keys()[0].lower() as_class = kwargs.pop('as_class', None) fields = kwargs.pop('fields', None) if fields is not None and not isinstance(fields, dict): fields = helpers._fields_list_to_dict(fields) command.update(kwargs) orig = mode = read_preference or self.read_preference if command_name not in SECONDARY_OK_COMMANDS: mode = ReadPreference.PRIMARY # Special-case: mapreduce can go to secondaries only if inline elif command_name == 'mapreduce': out = command.get('out') if not isinstance(out, dict) or not out.get('inline'): mode = ReadPreference.PRIMARY # Special-case: aggregate with $out cannot go to secondaries. elif command_name == 'aggregate': for stage in command.get('pipeline', []): if '$out' in stage: mode = ReadPreference.PRIMARY break # Warn if mode will override read_preference. if mode != orig: warnings.warn("%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, orig.name), UserWarning) cursor = self["$cmd"].find(command, fields=fields, limit=-1, as_class=as_class, read_preference=mode, compile_re=compile_re, _uuid_subtype=uuid_subtype) for doc in cursor: result = doc if check: msg = "command %s failed: %%s" % repr(command).replace("%", "%%") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result, cursor.conn_id
def test_clears(self): """ Test clear() """ test_son = SON([(1, 100), (2, 200), (3, 300)]) test_son.clear() self.assertNotIn(1, test_son) self.assertEqual(0, len(test_son)) self.assertEqual(0, len(test_son.keys())) self.assertEqual({}, test_son.to_dict())
def test_clears(self): """ Test clear() """ test_son = SON([(1, 100), (2, 200), (3, 300)]) test_son.clear() self.assertFalse(1 in test_son) self.assertEqual(0, len(test_son)) self.assertEqual(0, len(test_son.keys())) self.assertEqual({}, test_son.to_dict())
def command(self, command, value=1, check=True, allowable_errors=[], uuid_subtype=OLD_UUID_SUBTYPE, **kwargs): """Issue a MongoDB command. Send command `command` to the database and return the response. If `command` is an instance of :class:`basestring` (:class:`str` in python 3) then the command {`command`: `value`} will be sent. Otherwise, `command` must be an instance of :class:`dict` and will be sent as is. Any additional keyword arguments will be added to the final command document before it is sent. For example, a command like ``{buildinfo: 1}`` can be sent using: >>> db.command("buildinfo") For a command where the value matters, like ``{collstats: collection_name}`` we can do: >>> db.command("collstats", collection_name) For commands that take additional arguments we can use kwargs. So ``{filemd5: object_id, root: file_root}`` becomes: >>> db.command("filemd5", object_id, root=file_root) :Parameters: - `command`: document representing the command to be issued, or the name of the command (for simple commands only). .. note:: the order of keys in the `command` document is significant (the "verb" must come first), so commands which require multiple keys (e.g. `findandmodify`) should use an instance of :class:`~bson.son.SON` or a string and kwargs instead of a Python `dict`. - `value` (optional): value to use for the command verb when `command` is passed as a string - `check` (optional): check the response for errors, raising :class:`~pymongo.errors.OperationFailure` if there are any - `allowable_errors`: if `check` is ``True``, error messages in this list will be ignored by error-checking - `uuid_subtype` (optional): The BSON binary subtype to use for a UUID used in this command. - `read_preference`: The read preference for this connection. See :class:`~pymongo.read_preferences.ReadPreference` for available options. - `tag_sets`: Read from replica-set members with these tags. To specify a priority-order for tag sets, provide a list of tag sets: ``[{'dc': 'ny'}, {'dc': 'la'}, {}]``. A final, empty tag set, ``{}``, means "read from any member that matches the mode, ignoring tags." ReplicaSetConnection tries each set of tags in turn until it finds a set of tags with at least one matching member. - `secondary_acceptable_latency_ms`: Any replica-set member whose ping time is within secondary_acceptable_latency_ms of the nearest member may accept reads. Default 15 milliseconds. - `**kwargs` (optional): additional keyword arguments will be added to the command document before it is sent .. versionchanged:: 2.3 Added `tag_sets` and `secondary_acceptable_latency_ms` options. .. versionchanged:: 2.2 Added support for `as_class` - the class you want to use for the resulting documents .. versionchanged:: 1.6 Added the `value` argument for string commands, and keyword arguments for additional command options. .. versionchanged:: 1.5 `command` can be a string in addition to a full document. .. versionadded:: 1.4 .. mongodoc:: commands """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop("_use_master", False) if command_name not in rp.secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == "mapreduce": out = command.get("out") or kwargs.get("out") if not isinstance(out, dict) or not out.get("inline"): must_use_master = True extra_opts = { "as_class": kwargs.pop("as_class", None), "slave_okay": kwargs.pop("slave_okay", self.slave_okay), "_must_use_master": must_use_master, "_uuid_subtype": uuid_subtype, } extra_opts["read_preference"] = kwargs.pop("read_preference", self.read_preference) extra_opts["tag_sets"] = kwargs.pop("tag_sets", self.tag_sets) extra_opts["secondary_acceptable_latency_ms"] = kwargs.pop( "secondary_acceptable_latency_ms", self.secondary_acceptable_latency_ms ) fields = kwargs.get("fields") if fields is not None and not isinstance(fields, dict): kwargs["fields"] = helpers._fields_list_to_dict(fields) command.update(kwargs) result = self["$cmd"].find_one(command, **extra_opts) if check: msg = "command %s failed: %%s" % repr(command).replace("%", "%%") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result
def _command(self, command, value=1, check=True, allowable_errors=None, uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, **kwargs): """Internal command helper. """ if isinstance(command, str): command = SON([(command, value)]) command_name = list(command.keys())[0].lower() must_use_master = kwargs.pop('_use_master', False) if command_name not in secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == 'mapreduce': out = command.get('out') or kwargs.get('out') if not isinstance(out, dict) or not out.get('inline'): must_use_master = True # Special-case: aggregate with $out cannot go to secondaries. if command_name == 'aggregate': for stage in kwargs.get('pipeline', []): if '$out' in stage: must_use_master = True break extra_opts = { 'as_class': kwargs.pop('as_class', None), 'slave_okay': kwargs.pop('slave_okay', self.slave_okay), '_must_use_master': must_use_master, '_uuid_subtype': uuid_subtype } extra_opts['read_preference'] = kwargs.pop( 'read_preference', self.read_preference) extra_opts['tag_sets'] = kwargs.pop( 'tag_sets', self.tag_sets) extra_opts['secondary_acceptable_latency_ms'] = kwargs.pop( 'secondary_acceptable_latency_ms', self.secondary_acceptable_latency_ms) extra_opts['compile_re'] = compile_re fields = kwargs.get('fields') if fields is not None and not isinstance(fields, dict): kwargs['fields'] = helpers._fields_list_to_dict(fields) command.update(kwargs) # Warn if must_use_master will override read_preference. if (extra_opts['read_preference'] != ReadPreference.PRIMARY and extra_opts['_must_use_master']): warnings.warn("%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, modes[extra_opts['read_preference']]), UserWarning, stacklevel=3) cursor = self["$cmd"].find(command, **extra_opts).limit(-1) for doc in cursor: result = doc if check: msg = "command %s failed: %%s" % repr(command).replace("%", "%%") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result, cursor.conn_id
def command(self, command, value=1, check=True, allowable_errors=[], uuid_subtype=OLD_UUID_SUBTYPE, **kwargs): """Issue a MongoDB command. Send command `command` to the database and return the response. If `command` is an instance of :class:`basestring` (:class:`str` in python 3) then the command {`command`: `value`} will be sent. Otherwise, `command` must be an instance of :class:`dict` and will be sent as is. Any additional keyword arguments will be added to the final command document before it is sent. For example, a command like ``{buildinfo: 1}`` can be sent using: >>> db.command("buildinfo") For a command where the value matters, like ``{collstats: collection_name}`` we can do: >>> db.command("collstats", collection_name) For commands that take additional arguments we can use kwargs. So ``{filemd5: object_id, root: file_root}`` becomes: >>> db.command("filemd5", object_id, root=file_root) :Parameters: - `command`: document representing the command to be issued, or the name of the command (for simple commands only). .. note:: the order of keys in the `command` document is significant (the "verb" must come first), so commands which require multiple keys (e.g. `findandmodify`) should use an instance of :class:`~bson.son.SON` or a string and kwargs instead of a Python `dict`. - `value` (optional): value to use for the command verb when `command` is passed as a string - `check` (optional): check the response for errors, raising :class:`~pymongo.errors.OperationFailure` if there are any - `allowable_errors`: if `check` is ``True``, error messages in this list will be ignored by error-checking - `uuid_subtype` (optional): The BSON binary subtype to use for a UUID used in this command. - `read_preference`: The read preference for this connection. See :class:`~pymongo.read_preferences.ReadPreference` for available options. - `tag_sets`: Read from replica-set members with these tags. To specify a priority-order for tag sets, provide a list of tag sets: ``[{'dc': 'ny'}, {'dc': 'la'}, {}]``. A final, empty tag set, ``{}``, means "read from any member that matches the mode, ignoring tags." ReplicaSetConnection tries each set of tags in turn until it finds a set of tags with at least one matching member. - `secondary_acceptable_latency_ms`: Any replica-set member whose ping time is within secondary_acceptable_latency_ms of the nearest member may accept reads. Default 15 milliseconds. **Ignored by mongos** and must be configured on the command line. See the localThreshold_ option for more information. - `**kwargs` (optional): additional keyword arguments will be added to the command document before it is sent .. note:: ``command`` ignores the ``network_timeout`` parameter. .. versionchanged:: 2.3 Added `tag_sets` and `secondary_acceptable_latency_ms` options. .. versionchanged:: 2.2 Added support for `as_class` - the class you want to use for the resulting documents .. versionchanged:: 1.6 Added the `value` argument for string commands, and keyword arguments for additional command options. .. versionchanged:: 1.5 `command` can be a string in addition to a full document. .. versionadded:: 1.4 .. mongodoc:: commands .. _localThreshold: http://docs.mongodb.org/manual/reference/mongos/#cmdoption-mongos--localThreshold """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop('_use_master', False) if command_name not in rp.secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == 'mapreduce': out = command.get('out') or kwargs.get('out') if not isinstance(out, dict) or not out.get('inline'): must_use_master = True extra_opts = { 'as_class': kwargs.pop('as_class', None), 'slave_okay': kwargs.pop('slave_okay', self.slave_okay), '_must_use_master': must_use_master, '_uuid_subtype': uuid_subtype } extra_opts['read_preference'] = kwargs.pop('read_preference', self.read_preference) extra_opts['tag_sets'] = kwargs.pop('tag_sets', self.tag_sets) extra_opts['secondary_acceptable_latency_ms'] = kwargs.pop( 'secondary_acceptable_latency_ms', self.secondary_acceptable_latency_ms) fields = kwargs.get('fields') if fields is not None and not isinstance(fields, dict): kwargs['fields'] = helpers._fields_list_to_dict(fields) command.update(kwargs) result = self["$cmd"].find_one(command, **extra_opts) if check: msg = "command %s failed: %%s" % repr(command).replace("%", "%%") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result
def _command(self, command, value=1, check=True, allowable_errors=None, uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, read_preference=None, codec_options=None, **kwargs): """Internal command helper. """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop('_use_master', False) if command_name not in secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == 'mapreduce': out = command.get('out') or kwargs.get('out') if not isinstance(out, dict) or not out.get('inline'): must_use_master = True # Special-case: aggregate with $out cannot go to secondaries. if command_name == 'aggregate': for stage in kwargs.get('pipeline', []): if '$out' in stage: must_use_master = True break if codec_options is None or 'as_class' in kwargs: opts = {} if 'as_class' in kwargs: opts['document_class'] = kwargs.pop('as_class') # 'as_class' must be in kwargs so don't use document_class if codec_options: opts['tz_aware'] = codec_options.tz_aware opts['uuid_representation'] = codec_options.uuid_representation else: opts['uuid_representation'] = uuid_subtype codec_options = _CodecOptions(**opts) extra_opts = { 'slave_okay': kwargs.pop('slave_okay', self.slave_okay), '_codec_options': codec_options, '_must_use_master': must_use_master, } if isinstance(read_preference, _ServerMode): extra_opts['read_preference'] = read_preference.mode extra_opts['tag_sets'] = read_preference.tag_sets else: if read_preference is None: read_preference = self.read_preference extra_opts['read_preference'] = read_preference extra_opts['tag_sets'] = kwargs.pop( 'tag_sets', self.tag_sets) extra_opts['secondary_acceptable_latency_ms'] = kwargs.pop( 'secondary_acceptable_latency_ms', self.secondary_acceptable_latency_ms) extra_opts['compile_re'] = compile_re fields = kwargs.get('fields') if fields is not None and not isinstance(fields, dict): kwargs['fields'] = helpers._fields_list_to_dict(fields) command.update(kwargs) # Warn if must_use_master will override read_preference. if (extra_opts['read_preference'] != ReadPreference.PRIMARY and extra_opts['_must_use_master'] and self.connection._rs_client): warnings.warn("%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, modes[extra_opts['read_preference']]), UserWarning, stacklevel=3) cursor = self["$cmd"].find(command, **extra_opts).limit(-1) for doc in cursor: result = doc if check: helpers._check_command_response( result, self.connection._disconnect, None, allowable_errors) return result, cursor.conn_id
def _command(self, command, value=1, check=True, allowable_errors=None, uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, **kwargs): """Internal command helper. """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop('_use_master', False) if command_name not in secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == 'mapreduce': out = command.get('out') or kwargs.get('out') if not isinstance(out, dict) or not out.get('inline'): must_use_master = True # Special-case: aggregate with $out cannot go to secondaries. if command_name == 'aggregate': for stage in kwargs.get('pipeline', []): if '$out' in stage: must_use_master = True break extra_opts = { 'as_class': kwargs.pop('as_class', None), 'slave_okay': kwargs.pop('slave_okay', self.slave_okay), '_must_use_master': must_use_master, '_uuid_subtype': uuid_subtype } extra_opts['read_preference'] = kwargs.pop('read_preference', self.read_preference) extra_opts['tag_sets'] = kwargs.pop('tag_sets', self.tag_sets) extra_opts['secondary_acceptable_latency_ms'] = kwargs.pop( 'secondary_acceptable_latency_ms', self.secondary_acceptable_latency_ms) extra_opts['compile_re'] = compile_re fields = kwargs.get('fields') if fields is not None and not isinstance(fields, dict): kwargs['fields'] = helpers._fields_list_to_dict(fields) command.update(kwargs) # Warn if must_use_master will override read_preference. if (extra_opts['read_preference'] != ReadPreference.PRIMARY and extra_opts['_must_use_master']): warnings.warn("%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, modes[extra_opts['read_preference']]), UserWarning, stacklevel=3) cursor = self["$cmd"].find(command, **extra_opts).limit(-1) for doc in cursor: result = doc if check: msg = "command %s failed: %%s" % repr(command).replace("%", "%%") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result, cursor.conn_id
def command(self, command, value=1, check=True, allowable_errors=[], uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, **kwargs): """Issue a MongoDB command. Send command `command` to the database and return the response. If `command` is an instance of :class:`basestring` (:class:`str` in python 3) then the command {`command`: `value`} will be sent. Otherwise, `command` must be an instance of :class:`dict` and will be sent as is. Any additional keyword arguments will be added to the final command document before it is sent. For example, a command like ``{buildinfo: 1}`` can be sent using: >>> db.command("buildinfo") For a command where the value matters, like ``{collstats: collection_name}`` we can do: >>> db.command("collstats", collection_name) For commands that take additional arguments we can use kwargs. So ``{filemd5: object_id, root: file_root}`` becomes: >>> db.command("filemd5", object_id, root=file_root) :Parameters: - `command`: document representing the command to be issued, or the name of the command (for simple commands only). .. note:: the order of keys in the `command` document is significant (the "verb" must come first), so commands which require multiple keys (e.g. `findandmodify`) should use an instance of :class:`~bson.son.SON` or a string and kwargs instead of a Python `dict`. - `value` (optional): value to use for the command verb when `command` is passed as a string - `check` (optional): check the response for errors, raising :class:`~pymongo.errors.OperationFailure` if there are any - `allowable_errors`: if `check` is ``True``, error messages in this list will be ignored by error-checking - `uuid_subtype` (optional): The BSON binary subtype to use for a UUID used in this command. - `compile_re` (optional): if ``False``, don't attempt to compile BSON regular expressions into Python regular expressions. Return instances of :class:`~bson.regex.Regex` instead. Can avoid :exc:`~bson.errors.InvalidBSON` errors when receiving Python-incompatible regular expressions, for example from ``currentOp`` - `read_preference`: The read preference for this connection. See :class:`~pymongo.read_preferences.ReadPreference` for available options. - `tag_sets`: Read from replica-set members with these tags. To specify a priority-order for tag sets, provide a list of tag sets: ``[{'dc': 'ny'}, {'dc': 'la'}, {}]``. A final, empty tag set, ``{}``, means "read from any member that matches the mode, ignoring tags." ReplicaSetConnection tries each set of tags in turn until it finds a set of tags with at least one matching member. - `secondary_acceptable_latency_ms`: Any replica-set member whose ping time is within secondary_acceptable_latency_ms of the nearest member may accept reads. Default 15 milliseconds. **Ignored by mongos** and must be configured on the command line. See the localThreshold_ option for more information. - `**kwargs` (optional): additional keyword arguments will be added to the command document before it is sent .. note:: ``command`` ignores the ``network_timeout`` parameter. .. versionchanged:: 2.7 Added ``compile_re`` option. .. versionchanged:: 2.3 Added `tag_sets` and `secondary_acceptable_latency_ms` options. .. versionchanged:: 2.2 Added support for `as_class` - the class you want to use for the resulting documents .. versionchanged:: 1.6 Added the `value` argument for string commands, and keyword arguments for additional command options. .. versionchanged:: 1.5 `command` can be a string in addition to a full document. .. versionadded:: 1.4 .. mongodoc:: commands .. _localThreshold: http://docs.mongodb.org/manual/reference/mongos/#cmdoption-mongos--localThreshold """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop('_use_master', False) if command_name not in rp.secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == 'mapreduce': out = command.get('out') or kwargs.get('out') if not isinstance(out, dict) or not out.get('inline'): must_use_master = True # Special-case: aggregate with $out cannot go to secondaries. if command_name == 'aggregate': for stage in kwargs.get('pipeline', []): if '$out' in stage: must_use_master = True break extra_opts = { 'as_class': kwargs.pop('as_class', None), 'slave_okay': kwargs.pop('slave_okay', self.slave_okay), '_must_use_master': must_use_master, '_uuid_subtype': uuid_subtype } extra_opts['read_preference'] = kwargs.pop( 'read_preference', self.read_preference) extra_opts['tag_sets'] = kwargs.pop( 'tag_sets', self.tag_sets) extra_opts['secondary_acceptable_latency_ms'] = kwargs.pop( 'secondary_acceptable_latency_ms', self.secondary_acceptable_latency_ms) extra_opts['compile_re'] = compile_re fields = kwargs.get('fields') if fields is not None and not isinstance(fields, dict): kwargs['fields'] = helpers._fields_list_to_dict(fields) command.update(kwargs) result = self["$cmd"].find_one(command, **extra_opts) if check: msg = "command %s failed: %%s" % repr(command).replace("%", "%%") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result
# Python Dictionaries. Key-Value pairs. Keys are unordered. # This data structure in the mongo shell is a JSON document. They keys are ordered. In python this is a dictionary. x = {"b": -1, "a": 1} print(type(x)) print(x) # Mongo provides a utility to solve this called SON, for Serialized Ocument Notation. # Apparent Etymology: An "O"rdered "D"ictionary Notation. # The Dictionary of keys passed to $sort is maintained when using SON as shown below. # What you see is what you get. from bson.son import SON x = SON([("b", -1), ("a", -1)]) print(type(x)) print(x) print(x.keys) for key in x.keys(): print(key) # Mongo provides a utility to solve this called SON, for Serialized Ocument Notation. # Apparent Etymology: An "O"rdered "D"ictionary Notation. # The Dictionary of keys passed to $sort is maintained when using SON as shown below. # What you see is what you get. from bson.son import SON x = SON([("a", -1), ("b", -1)]) print(type(x)) print(x) print(x.keys) for key in x.keys(): print(key) # Create a pipeline to sum population by State, City and sort by State, City
def _command( self, command, value=1, check=True, allowable_errors=None, uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, read_preference=None, codec_options=None, **kwargs ): """Internal command helper. """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop("_use_master", False) if command_name not in secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == "mapreduce": out = command.get("out") or kwargs.get("out") if not isinstance(out, dict) or not out.get("inline"): must_use_master = True # Special-case: aggregate with $out cannot go to secondaries. if command_name == "aggregate": for stage in kwargs.get("pipeline", []): if "$out" in stage: must_use_master = True break if codec_options is None or "as_class" in kwargs: opts = {} if "as_class" in kwargs: opts["document_class"] = kwargs.pop("as_class") # 'as_class' must be in kwargs so don't use document_class if codec_options: opts["tz_aware"] = codec_options.tz_aware opts["uuid_representation"] = codec_options.uuid_representation else: opts["uuid_representation"] = uuid_subtype codec_options = _CodecOptions(**opts) extra_opts = { "slave_okay": kwargs.pop("slave_okay", self.slave_okay), "_codec_options": codec_options, "_must_use_master": must_use_master, } if isinstance(read_preference, _ServerMode): extra_opts["read_preference"] = read_preference.mode extra_opts["tag_sets"] = read_preference.tag_sets else: if read_preference is None: read_preference = self.read_preference extra_opts["read_preference"] = read_preference extra_opts["tag_sets"] = kwargs.pop("tag_sets", self.tag_sets) extra_opts["secondary_acceptable_latency_ms"] = kwargs.pop( "secondary_acceptable_latency_ms", self.secondary_acceptable_latency_ms ) extra_opts["compile_re"] = compile_re fields = kwargs.get("fields") if fields is not None and not isinstance(fields, dict): kwargs["fields"] = helpers._fields_list_to_dict(fields) command.update(kwargs) # Warn if must_use_master will override read_preference. if ( extra_opts["read_preference"] != ReadPreference.PRIMARY and extra_opts["_must_use_master"] and self.connection._rs_client ): warnings.warn( "%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, modes[extra_opts["read_preference"]]), UserWarning, stacklevel=3, ) cursor = self["$cmd"].find(command, **extra_opts).limit(-1) for doc in cursor: result = doc if check: msg = "command %s on namespace %s failed: %%s" % (repr(command).replace("%", "%%"), self.name + ".$cmd") helpers._check_command_response(result, self.connection.disconnect, msg, allowable_errors) return result, cursor.conn_id
def _command(self, command, value=1, check=True, allowable_errors=None, uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True, read_preference=None, codec_options=None, **kwargs): """Internal command helper. """ if isinstance(command, basestring): command = SON([(command, value)]) command_name = command.keys()[0].lower() must_use_master = kwargs.pop('_use_master', False) if command_name not in secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline if command_name == 'mapreduce': out = command.get('out') or kwargs.get('out') if not isinstance(out, dict) or not out.get('inline'): must_use_master = True # Special-case: aggregate with $out cannot go to secondaries. if command_name == 'aggregate': for stage in kwargs.get('pipeline', []): if '$out' in stage: must_use_master = True break if codec_options is None or 'as_class' in kwargs: opts = {} if 'as_class' in kwargs: opts['document_class'] = kwargs.pop('as_class') # 'as_class' must be in kwargs so don't use document_class if codec_options: opts['tz_aware'] = codec_options.tz_aware opts['uuid_representation'] = codec_options.uuid_representation else: opts['uuid_representation'] = uuid_subtype codec_options = _CodecOptions(**opts) extra_opts = { 'slave_okay': kwargs.pop('slave_okay', self.slave_okay), '_codec_options': codec_options, '_must_use_master': must_use_master, } if isinstance(read_preference, _ServerMode): extra_opts['read_preference'] = read_preference.mode extra_opts['tag_sets'] = read_preference.tag_sets else: if read_preference is None: read_preference = self.read_preference extra_opts['read_preference'] = read_preference extra_opts['tag_sets'] = kwargs.pop('tag_sets', self.tag_sets) extra_opts['secondary_acceptable_latency_ms'] = kwargs.pop( 'secondary_acceptable_latency_ms', self.secondary_acceptable_latency_ms) extra_opts['compile_re'] = compile_re fields = kwargs.get('fields') if fields is not None and not isinstance(fields, dict): kwargs['fields'] = helpers._fields_list_to_dict(fields) command.update(kwargs) # Warn if must_use_master will override read_preference. if (extra_opts['read_preference'] != ReadPreference.PRIMARY and extra_opts['_must_use_master'] and self.connection._rs_client): warnings.warn("%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, modes[extra_opts['read_preference']]), UserWarning, stacklevel=3) cursor = self["$cmd"].find(command, **extra_opts).limit(-1) for doc in cursor: result = doc if check: helpers._check_command_response(result, self.connection._disconnect, None, allowable_errors) return result, cursor.conn_id