Example #1
0
    def _deepcopy(self, x, memo=None):
        """Deepcopy helper for the data dictionary or list.

        Regular expressions cannot be deep copied but as they are immutable we
        don't have to copy them when cloning.
        """
        if not hasattr(x, 'items'):
            y, is_list, iterator = [], True, enumerate(x)
        else:
            y, is_list, iterator = {}, False, iteritems(x)

        if memo is None:
            memo = {}
        val_id = id(x)
        if val_id in memo:
            return memo.get(val_id)
        memo[val_id] = y

        for key, value in iterator:
            if isinstance(value, (dict, list)) and not isinstance(value, SON):
                value = self._deepcopy(value, memo)
            elif not isinstance(value, RE_TYPE):
                value = copy.deepcopy(value, memo)

            if is_list:
                y.append(value)
            else:
                if not isinstance(key, RE_TYPE):
                    key = copy.deepcopy(key, memo)
                y[key] = value
        return y
Example #2
0
 def __repr__(self):
     extra = "".join(
         [", %s=%r" % (k, v) for k, v in iteritems(self.__kwargs)])
     if self.database is None:
         return "DBRef(%r, %r%s)" % (self.collection, self.id, extra)
     return "DBRef(%r, %r, %r%s)" % (self.collection, self.id,
                                     self.database, extra)
Example #3
0
def _index_document(index_list):
    """Helper to generate an index specifying document.

    Takes a list of (key, direction) pairs.
    """
    if isinstance(index_list, collections.Mapping):
        raise TypeError("passing a dict to sort/create_index/hint is not "
                        "allowed - use a list of tuples instead. did you "
                        "mean %r?" % list(iteritems(index_list)))
    elif not isinstance(index_list, (list, tuple)):
        raise TypeError("must use a list of (key, direction) pairs, "
                        "not: " + repr(index_list))
    if not len(index_list):
        raise ValueError("key_or_list must not be the empty list")

    index = SON()
    for (key, value) in index_list:
        if not isinstance(key, string_type):
            raise TypeError("first item in each key pair must be a string")
        if not isinstance(value, (string_type, int, collections.Mapping)):
            raise TypeError("second item in each key pair must be 1, -1, "
                            "'2d', 'geoHaystack', or another valid MongoDB "
                            "index specifier.")
        index[key] = value
    return index
Example #4
0
 def transform_value(value):
     if isinstance(value, list):
         return [transform_value(v) for v in value]
     elif isinstance(value, collections.Mapping):
         return dict([(k, transform_value(v))
                      for k, v in iteritems(value)])
     else:
         return value
Example #5
0
    def validate_collection(self,
                            name_or_collection,
                            scandata=False,
                            full=False):
        """Validate a collection.

        Returns a dict of validation info. Raises CollectionInvalid if
        validation fails.

        :Parameters:
          - `name_or_collection`: A Collection object or the name of a
            collection to validate.
          - `scandata`: Do extra checks beyond checking the overall
            structure of the collection.
          - `full`: Have the server do a more thorough scan of the
            collection. Use with `scandata` for a thorough scan
            of the structure of the collection and the individual
            documents.
        """
        name = name_or_collection
        if isinstance(name, Collection):
            name = name.name

        if not isinstance(name, string_type):
            raise TypeError("name_or_collection must be an instance of "
                            "%s or Collection" % (string_type.__name__, ))

        result = self.command("validate",
                              _unicode(name),
                              scandata=scandata,
                              full=full)

        valid = True
        # Pre 1.9 results
        if "result" in result:
            info = result["result"]
            if info.find("exception") != -1 or info.find("corrupt") != -1:
                raise CollectionInvalid("%s invalid: %s" % (name, info))
        # Sharded results
        elif "raw" in result:
            for _, res in iteritems(result["raw"]):
                if "result" in res:
                    info = res["result"]
                    if (info.find("exception") != -1
                            or info.find("corrupt") != -1):
                        raise CollectionInvalid("%s invalid: "
                                                "%s" % (name, info))
                elif not res.get("valid", False):
                    valid = False
                    break
        # Post 1.9 non-sharded results.
        elif not result.get("valid", False):
            valid = False

        if not valid:
            raise CollectionInvalid("%s invalid: %r" % (name, result))

        return result
Example #6
0
def _encode_mapping(name, value, check_keys, opts):
    """Encode a mapping type."""
    if _raw_document_class(value):
        return b'\x03' + name + value.raw
    data = b"".join([
        _element_to_bson(key, val, check_keys, opts)
        for key, val in iteritems(value)
    ])
    return b"\x03" + name + _PACK_INT(len(data) + 5) + data + b"\x00"
Example #7
0
def _json_convert(obj, json_options=DEFAULT_JSON_OPTIONS):
    """Recursive helper method that converts BSON types so they can be
    converted into json.
    """
    if hasattr(obj, 'iteritems') or hasattr(obj, 'items'):  # PY3 support
        return SON(
            ((k, _json_convert(v, json_options)) for k, v in iteritems(obj)))
    elif hasattr(obj, '__iter__') and not isinstance(obj, (text_type, bytes)):
        return list((_json_convert(v, json_options) for v in obj))
    try:
        return default(obj, json_options)
    except TypeError:
        return obj
Example #8
0
 def _clone(self, deepcopy=True):
     """Internal clone helper."""
     clone = self._clone_base()
     values_to_clone = ("spec", "projection", "skip", "limit",
                        "max_time_ms", "max_await_time_ms", "comment",
                        "max", "min", "ordering", "explain", "hint",
                        "batch_size", "max_scan", "manipulate",
                        "query_flags", "modifiers", "collation")
     data = dict((k, v) for k, v in iteritems(self.__dict__)
                 if k.startswith('_Cursor__') and k[9:] in values_to_clone)
     if deepcopy:
         data = self._deepcopy(data)
     clone.__dict__.update(data)
     return clone
Example #9
0
def _encode_dbref(name, value, check_keys, opts):
    """Encode bson.dbref.DBRef."""
    buf = bytearray(b"\x03" + name + b"\x00\x00\x00\x00")
    begin = len(buf) - 4

    buf += _name_value_to_bson(b"$ref\x00", value.collection, check_keys, opts)
    buf += _name_value_to_bson(b"$id\x00", value.id, check_keys, opts)
    if value.database is not None:
        buf += _name_value_to_bson(b"$db\x00", value.database, check_keys,
                                   opts)
    for key, val in iteritems(value._DBRef__kwargs):
        buf += _element_to_bson(key, val, check_keys, opts)

    buf += b"\x00"
    buf[begin:begin + 4] = _PACK_INT(len(buf) - begin)
    return bytes(buf)
Example #10
0
def _dict_to_bson(doc, check_keys, opts, top_level=True):
    """Encode a document to BSON."""
    if _raw_document_class(doc):
        return doc.raw
    try:
        elements = []
        if top_level and "_id" in doc:
            elements.append(
                _name_value_to_bson(b"_id\x00", doc["_id"], check_keys, opts))
        for (key, value) in iteritems(doc):
            if not top_level or key != "_id":
                elements.append(_element_to_bson(key, value, check_keys, opts))
    except AttributeError:
        raise TypeError("encoder expected a mapping type but got: %r" %
                        (doc, ))

    encoded = b"".join(elements)
    return _PACK_INT(len(encoded) + 5) + encoded + b"\x00"
Example #11
0
def get_validated_options(options, warn=True):
    """Validate each entry in options and raise a warning if it is not valid.
    Returns a copy of options with invalid entries removed
    """
    validated_options = {}
    for opt, value in iteritems(options):
        lower = opt.lower()
        try:
            validator = URI_VALIDATORS.get(lower, raise_config_error)
            value = validator(opt, value)
        except (ValueError, ConfigurationError) as exc:
            if warn:
                warnings.warn(str(exc))
            else:
                raise
        else:
            validated_options[lower] = value
    return validated_options
Example #12
0
 def items(self):
     """Lazily decode and iterate elements in this document."""
     return iteritems(self.__inflated)
Example #13
0
    def authenticate(self,
                     name=None,
                     password=None,
                     source=None,
                     mechanism='DEFAULT',
                     **kwargs):
        """**DEPRECATED**: Authenticate to use this database.

        Authentication lasts for the life of the underlying client
        instance, or until :meth:`logout` is called.

        Raises :class:`TypeError` if (required) `name`, (optional) `password`,
        or (optional) `source` is not an instance of :class:`basestring`
        (:class:`str` in python 3).

        .. note::
          - This method authenticates the current connection, and
            will also cause all new :class:`~socket.socket` connections
            in the underlying client instance to be authenticated automatically.

          - Authenticating more than once on the same database with different
            credentials is not supported. You must call :meth:`logout` before
            authenticating with new credentials.

          - When sharing a client instance between multiple threads, all
            threads will share the authentication. If you need different
            authentication profiles for different purposes you must use
            distinct client instances.

        :Parameters:
          - `name`: the name of the user to authenticate. Optional when
            `mechanism` is MONGODB-X509 and the MongoDB server version is
            >= 3.4.
          - `password` (optional): the password of the user to authenticate.
            Not used with GSSAPI or MONGODB-X509 authentication.
          - `source` (optional): the database to authenticate on. If not
            specified the current database is used.
          - `mechanism` (optional): See
            :data:`~pymongo.auth.MECHANISMS` for options.
            By default, use SCRAM-SHA-1 with MongoDB 3.0 and later,
            MONGODB-CR (MongoDB Challenge Response protocol) for older servers.
          - `authMechanismProperties` (optional): Used to specify
            authentication mechanism specific options. To specify the service
            name for GSSAPI authentication pass
            authMechanismProperties='SERVICE_NAME:<service name>'

        .. versionchanged:: 3.5
           Deprecated. Authenticating multiple users conflicts with support for
           logical sessions in MongoDB 3.6. To authenticate as multiple users,
           create multiple instances of MongoClient.

        .. versionadded:: 2.8
           Use SCRAM-SHA-1 with MongoDB 3.0 and later.

        .. versionchanged:: 2.5
           Added the `source` and `mechanism` parameters. :meth:`authenticate`
           now raises a subclass of :class:`~pymongo.errors.PyMongoError` if
           authentication fails due to invalid credentials or configuration
           issues.

        .. mongodoc:: authenticate
        """
        if name is not None and not isinstance(name, string_type):
            raise TypeError("name must be an "
                            "instance of %s" % (string_type.__name__, ))
        if password is not None and not isinstance(password, string_type):
            raise TypeError("password must be an "
                            "instance of %s" % (string_type.__name__, ))
        if source is not None and not isinstance(source, string_type):
            raise TypeError("source must be an "
                            "instance of %s" % (string_type.__name__, ))
        common.validate_auth_mechanism('mechanism', mechanism)

        validated_options = {}
        for option, value in iteritems(kwargs):
            normalized, val = common.validate_auth_option(option, value)
            validated_options[normalized] = val

        credentials = auth._build_credentials_tuple(mechanism, source
                                                    or self.name, name,
                                                    password,
                                                    validated_options)

        self.client._cache_credentials(self.name, credentials, connect=True)

        return True