Exemple #1
0
 def instrument_collection_class(self, class_, key, collection_class):
     global collections
     if collections is None:
         from sqlalchemy.orm import collections
     return collections.prepare_instrumentation(collection_class)
Exemple #2
0
 def instrument_collection_class(self, key, collection_class):
     return collections.prepare_instrumentation(collection_class)
 def instrument_collection_class(self, key, collection_class):
     return collections.prepare_instrumentation(collection_class)
Exemple #4
0
def from_collection(from_,
                    to_,
                    excludes=None,
                    format=None,
                    collection_handling="replace"):
    """Recursively apply data in a Python collection to SQLAlchemy declarative model objects.

    This function takes a `from_` and an `to_` and sets the attributes on the
    SQLAlchemy declarative model instance using the key-value pairs from the
    collection **inplace**.

    If `excludes` is provided, it works similarily as `to_collection`.

    If `format` is the string `json`, the mapping returned will be a JSON
    string, otherwise the mapped model(s) will be returned.

    If `collection_handling` is `replace`, which is the default, all the
    supplied relationship mappings will be converted to the correct subclass
    instances and replace the entire relationship collection on the parent
    objects. If the value is `append`, the mapped model instance will be
    appended to the relationship collection instead.

    If a key from the mapping is not found as a column on a model instance, it
    will simply be skipped and not set on the instance.

    The values supplied is converted according to the similiar rules as
    `to_collection()`:

    ============== ============================================
    column type    mapping value format
    ============== ============================================
    datetime       {"datetime": "ISO-8601"}
    time           {"time": "ISO-8601"}
    date           {"date": "ISO-8601"}
    timedelta      {"interval": seconds}
    WKTElement     GeoJSON
    ============== ============================================

    **Security Notice:** This function currently does not yet have integration
    support for data validation. If you are using this function to directly
    mass-assign user supplied data to your model instances, make sure you have
    validated the data first. In a future version of blueberrypy, integration
    with a form validation library will be provided to ease this process.
    """
    if format == "json":
        from_ = json.loads(from_)

    if collection_handling not in ["replace", "append"]:
        raise ValueError("collection_handling must be 'replace' or 'append'.")

    excludes = _ensure_is_dict(to_.__class__, excludes)

    if isinstance(from_, dict):
        if isinstance(to_, dict):
            for k in to_.viewkeys():
                if k in from_:
                    to_[k] = from_collection(from_[k],
                                             to_[k],
                                             excludes=excludes)
        elif hasattr(to_, "__mapper__"):

            if not sqlalchemy_support:
                raise ImportError(
                    textwrap.dedent("""SQLAlchemy not installed.

                Please use install it first before proceding:

                $ pip install sqlalchemy
                """))

            props = _get_model_properties(to_, excludes, recursive=True)
            attrs = set(props.viewkeys())
            if excludes and to_.__class__ in excludes:
                attrs -= excludes[to_.__class__]

            for attr in attrs:
                if attr in from_:
                    prop = props[attr]
                    from_val = from_[attr]
                    if isinstance(prop, RelationshipProperty):
                        if not isinstance(from_val, list) and not isinstance(
                                from_val, dict):
                            raise ValueError(
                                "%r must be either a list or a dict" % attr)

                        if prop.uselist is None or prop.uselist:

                            if collection_handling == "replace":
                                col = collections.prepare_instrumentation(
                                    prop.collection_class or list)()
                            elif collection_handling == "append":
                                col = getattr(to_, attr)

                            appender = col._sa_appender

                            from_iterator = (iter(from_val) if isinstance(
                                from_val, list) else from_val.viewvalues())

                            for v in from_iterator:
                                prop_inst = _get_property_instance(
                                    Session.object_session(to_), v, prop)
                                appender(
                                    from_collection(v,
                                                    prop_inst,
                                                    excludes=excludes))

                            if collection_handling == "replace":
                                setattr(to_, attr, col)
                        else:
                            prop_inst = _get_property_instance(
                                Session.object_session(to_), from_val, prop)
                            setattr(
                                to_, attr,
                                from_collection(from_val,
                                                prop_inst,
                                                excludes=excludes))
                    else:
                        setattr(
                            to_, attr,
                            from_collection(from_val, None, excludes=excludes))
        else:
            if "date" in from_:
                to_ = parse_date(from_["date"]).date()
            elif "time" in from_:
                to_ = parse_date(from_["time"]).time()
            elif "datetime" in from_:
                to_ = parse_date(from_["datetime"])
            elif "interval" in from_:
                to_ = timedelta(seconds=from_["interval"])
            elif geos_support and "type" in from_:
                to_ = from_shape(as_shape(from_))

    elif iterable(from_) and not isinstance(from_,
                                            (basestring, bytes, bytearray)):

        if not iterable(to_) or isinstance(to_,
                                           (basestring, bytes, bytearray)):
            raise TypeError(
                "to_ must be an non-scalar sequence because from_ is.")

        elif len(from_) != len(to_):
            raise ValueError("length of to_ must match length of from_.")

        to_ = [
            from_collection(f, t, excludes=excludes)
            for f, t in zip(from_, to_)
        ]

    else:
        to_ = from_

    return to_
Exemple #5
0
def from_collection(from_, to_, excludes=None, format=None, collection_handling="replace"):
    """Recursively apply data in a Python collection to SQLAlchemy declarative model objects.

    This function takes a `from_` and an `to_` and sets the attributes on the
    SQLAlchemy declarative model instance using the key-value pairs from the
    collection **inplace**.

    If `excludes` is provided, it works similarily as `to_collection`.

    If `format` is the string `json`, the mapping returned will be a JSON
    string, otherwise the mapped model(s) will be returned.

    If `collection_handling` is `replace`, which is the default, all the
    supplied relationship mappings will be converted to the correct subclass
    instances and replace the entire relationship collection on the parent
    objects. If the value is `append`, the mapped model instance will be
    appended to the relationship collection instead.

    If a key from the mapping is not found as a column on a model instance, it
    will simply be skipped and not set on the instance.

    The values supplied is converted according to the similiar rules as
    `to_collection()`:

    ============== ============================================
    column type    mapping value format
    ============== ============================================
    datetime       {"datetime": "ISO-8601"}
    time           {"time": "ISO-8601"}
    date           {"date": "ISO-8601"}
    timedelta      {"interval": seconds}
    WKTElement     GeoJSON
    ============== ============================================

    **Security Notice:** This function currently does not yet have integration
    support for data validation. If you are using this function to directly
    mass-assign user supplied data to your model instances, make sure you have
    validated the data first. In a future version of blueberrypy, integration
    with a form validation library will be provided to ease this process.
    """
    if format == "json":
        from_ = json.loads(from_)

    if collection_handling not in ["replace", "append"]:
        raise ValueError("collection_handling must be 'replace' or 'append'.")

    excludes = _ensure_is_dict(to_.__class__, excludes)

    if isinstance(from_, dict):
        if isinstance(to_, dict):
            for k in to_.viewkeys():
                if k in from_:
                    to_[k] = from_collection(from_[k], to_[k], excludes=excludes)
        elif hasattr(to_, "__mapper__"):

            if not sqlalchemy_support:
                raise ImportError(
                    textwrap.dedent(
                        """SQLAlchemy not installed.

                Please use install it first before proceding:

                $ pip install sqlalchemy
                """
                    )
                )

            props = _get_model_properties(to_, excludes, recursive=True)
            attrs = set(props.viewkeys())
            if excludes and to_.__class__ in excludes:
                attrs -= excludes[to_.__class__]

            for attr in attrs:
                if attr in from_:
                    prop = props[attr]
                    from_val = from_[attr]
                    if isinstance(prop, RelationshipProperty):
                        if not isinstance(from_val, list) and not isinstance(from_val, dict):
                            raise ValueError("%r must be either a list or a dict" % attr)

                        if prop.uselist is None or prop.uselist:

                            if collection_handling == "replace":
                                col = collections.prepare_instrumentation(prop.collection_class or list)()
                            elif collection_handling == "append":
                                col = getattr(to_, attr)

                            appender = col._sa_appender

                            from_iterator = iter(from_val) if isinstance(from_val, list) else from_val.viewvalues()

                            for v in from_iterator:
                                prop_inst = _get_property_instance(Session.object_session(to_), v, prop)
                                appender(from_collection(v, prop_inst, excludes=excludes))

                            if collection_handling == "replace":
                                setattr(to_, attr, col)
                        else:
                            prop_inst = _get_property_instance(Session.object_session(to_), from_val, prop)
                            setattr(to_, attr, from_collection(from_val, prop_inst, excludes=excludes))
                    else:
                        setattr(to_, attr, from_collection(from_val, None, excludes=excludes))
        else:
            if "date" in from_:
                to_ = parse_date(from_["date"]).date()
            elif "time" in from_:
                to_ = parse_date(from_["time"]).time()
            elif "datetime" in from_:
                to_ = parse_date(from_["datetime"])
            elif "interval" in from_:
                to_ = timedelta(seconds=from_["interval"])
            elif geos_support and "type" in from_:
                to_ = from_shape(as_shape(from_))

    elif iterable(from_) and not isinstance(from_, (basestring, bytes, bytearray)):

        if not iterable(to_) or isinstance(to_, (basestring, bytes, bytearray)):
            raise TypeError("to_ must be an non-scalar sequence because from_ is.")

        elif len(from_) != len(to_):
            raise ValueError("length of to_ must match length of from_.")

        to_ = [from_collection(f, t, excludes=excludes) for f, t in zip(from_, to_)]

    else:
        to_ = from_

    return to_