Example #1
0
    def url_id(cls):
        """The URL id"""
        if cls.__uuid_primary_key__:

            def url_id_func(self):
                """The URL id, UUID primary key rendered as a hex string"""
                return self.id.hex

            def url_id_is(cls):
                return SqlHexUuidComparator(cls.id)

            url_id_func.__name__ = 'url_id'
            url_id_property = hybrid_property(url_id_func)
            url_id_property = url_id_property.comparator(url_id_is)
            return url_id_property
        else:

            def url_id_func(self):
                """The URL id, integer primary key rendered as a string"""
                return six.text_type(self.id)

            def url_id_expression(cls):
                """The URL id, integer primary key"""
                return cls.id

            url_id_func.__name__ = 'url_id'
            url_id_property = hybrid_property(url_id_func)
            url_id_property = url_id_property.expression(url_id_expression)
            return url_id_property
Example #2
0
    def url_id(cls):
        """The URL id"""
        if cls.__uuid_primary_key__:
            def url_id_func(self):
                """The URL id, UUID primary key rendered as a hex string"""
                return self.id.hex

            def url_id_is(cls):
                return SqlHexUuidComparator(cls.id)

            url_id_func.__name__ = 'url_id'
            url_id_property = hybrid_property(url_id_func)
            url_id_property = url_id_property.comparator(url_id_is)
            return url_id_property
        else:
            def url_id_func(self):
                """The URL id, integer primary key rendered as a string"""
                return six.text_type(self.id)

            def url_id_expression(cls):
                """The URL id, integer primary key"""
                return cls.id

            url_id_func.__name__ = 'url_id'
            url_id_property = hybrid_property(url_id_func)
            url_id_property = url_id_property.expression(url_id_expression)
            return url_id_property
Example #3
0
        class SomeMixin(object):
            @hybrid.hybrid_property
            def same_name(self):
                return self.id

            def name1(self):
                return self.id

            different_name = hybrid.hybrid_property(name1)

            no_name = hybrid.hybrid_property(lambda self: self.name)
Example #4
0
        class A(Base):
            __tablename__ = "a"
            id = Column(Integer, primary_key=True)
            name = Column(String(50))

            @hybrid.hybrid_property
            def same_name(self):
                return self.id

            def name1(self):
                return self.id

            different_name = hybrid.hybrid_property(name1)

            no_name = hybrid.hybrid_property(lambda self: self.name)
Example #5
0
 def createSignature(cls):
     '''
     Create the signature name link, only one can be created.
     '''
     
     def fget(self):
         if self.signature: return self.signature.name
     
     def fset(self, name):
         assert isinstance(name, str), 'Invalid signature name %s' % name
         name = name.strip()
         assert name, 'Empty string is not a valid signature name'
         
         session = openSession()
         try: signatureId, = session.query(Signature.id).filter(Signature.name == name).one()
         except NoResultFound:
             signature = Signature()
             signature.name = name
             session.add(signature)
             session.flush((signature,))
             signatureId = signature.id
         self.signatureId = signatureId
     
     validation = validate(Mandatory, lambda prop: MaxLen(prop, columnFor(Signature.name).type.length))
     return validation(hybrid_property(fget, fset, expr=joinedExpr(Signature, 'name')))
Example #6
0
 def decorator(func):
     if not info.get('filterable', True):
         ret = property(func)
     else:
         ret = hybrid_property(func)
     ret.fget.info = info
     return ret
Example #7
0
    def get_property(self, registry, namespace, fieldname, properties):
        """Return the property of the field

        .. warning::

            In the case of the get is called in classattribute,
            SQLAlchemy wrap for each call the column, the id of the wrapper
            is not the same

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """
        fget = self.wrap_getter_column(fieldname)
        fset = self.wrap_setter_column(fieldname)
        fexp = self.wrap_expr_column(fieldname)

        for func in (fget, fset, fexp):
            func.__name__ = fieldname

        hybrid = hybrid_property(fget)
        hybrid = hybrid.setter(fset)
        hybrid = hybrid.expression(fexp)
        return hybrid
Example #8
0
    def test_attrs_props_prop_added_after_configure(self):
        class AnonClass(object):
            pass

        from sqlalchemy.orm import mapper, column_property
        from sqlalchemy.ext.hybrid import hybrid_property
        m = mapper(AnonClass, self.tables.users)

        eq_(
            set(inspect(AnonClass).attrs.keys()),
            set(['id', 'name']))
        eq_(
            set(inspect(AnonClass).all_orm_descriptors.keys()),
            set(['id', 'name']))

        m.add_property('q', column_property(self.tables.users.c.name))

        def desc(self):
            return self.name
        AnonClass.foob = hybrid_property(desc)

        eq_(
            set(inspect(AnonClass).attrs.keys()),
            set(['id', 'name', 'q']))
        eq_(
            set(inspect(AnonClass).all_orm_descriptors.keys()),
            set(['id', 'name', 'q', 'foob']))
Example #9
0
def mapped_to_slot_property(col, slot_name, slot_transform=lambda x: x):
    """Assume the attribute in the class as the same name as the table column with "_" prepended"""
    col_name = "_{}".format(col.name)

    def fget(self):
        return getattr(self, col_name)

    def fset(self, value):
        v = slot_transform(value)
        if v is None:
            if slot_name in self:
                del self[slot_name]
        else:
            self[slot_name] = v

        setattr(self, col_name, value)

    def expr(cls):
        return col

    return hybrid_property(
        fget=fget,
        fset=fset,
        expr=expr,
    )
Example #10
0
def pure_slot_property(slot_name, slot_transform=lambda x: x):
    """
    Create a property (class must have slots) that maps to a slot

    :param slot_name: name of the slot
    :param slot_transform: transformation to operate before assigning value
    :return:
    """
    def fget(self):
        # return None if the slot does not exist. alternative could be to raise an exception
        try:
            return self[slot_name].value
        except KeyError:
            return None

    def fset(self, value):
        v = slot_transform(value)
        if v is None:
            if slot_name in self:
                del self[slot_name]
        else:
            self[slot_name] = v

    return hybrid_property(
        fget=fget,
        fset=fset,
    )
Example #11
0
    def decorate(func):

        name = func.__name__

        @wraps(func)
        def fget(self):
            obj = getattr(self, relation)
            if not obj:
                return default
            else:
                return getattr(obj.name)

        hybrid = hybrid_property(fget)

        if class_:
            def fset(self, value):
                obj = getattr(self, relation)
                if not obj:
                    obj = class_(**class_kwargs)
                    setattr(self, relation, obj)
                setattr(obj, name, value)
            hybrid.setter(fset)

        if expression:
            def expr(cls):
                return expression
            hybrid.expression(expr)

        return hybrid
Example #12
0
def DateTimeAtColumn(prefix: str) -> hybrid_property:
    datetime_key = f'{prefix}_datetime'
    timezone_key = f'{prefix}_timezone'

    def getter(self) -> Optional[datetime.datetime]:
        dt: Optional[datetime.datetime] = getattr(self, datetime_key)
        tz: Optional[datetime.tzinfo] = getattr(self, timezone_key)
        if dt and tz:
            return dt.replace(tzinfo=UTC).astimezone(tz)
        if dt:
            return dt.replace(tzinfo=None)
        return dt

    def setter(self, dt: datetime.datetime):
        setattr(self, timezone_key, dt.tzinfo)
        setattr(self, datetime_key, dt.astimezone(UTC))

    def custom_comparator(cls):
        return DateTimeAtComparator(
            getattr(cls, datetime_key), getattr(cls, timezone_key),
        )

    return hybrid_property(
        fget=getter, fset=setter, custom_comparator=custom_comparator,
    )
Example #13
0
def relationshipModel(mappedId, *spec):
    '''
    Creates a relationship with the model, this should only be used in case the mapped model database id is different from the
    actual model id.
    
    @param mappedId: InstrumentedAttribute
        The mapped model id to create the relation with.
    @param spec: arguments containing
        column: string
            The column name containing the foreign key relation, attention if target is provided then
            also column needs to be provided, if None provided it will create one automatically.
        target: string
            The SQL alchemy relationship target name, if None provided it will create one automatically.
    '''
    assert isinstance(mappedId,
                      InstrumentedAttribute), 'Invalid mapped id %s' % mappedId
    register = callerLocals()
    assert '__module__' in register, 'This function should only be used inside meta class definitions'
    rtype = typeFor(mappedId.class_)
    assert isinstance(rtype, TypeModel), 'Invalid class %s' % mappedId.class_
    assert isinstance(rtype.propertyId,
                      TypeProperty), 'No property id for %s' % rtype
    assert rtype.propertyId.name != mappedId.property.key, 'Same database id with the model id \'%s\' for %s' % mappedId.class_

    column = target = None
    if spec:
        column, *spec = spec
        assert isinstance(column, str), 'Invalid column %s' % column
        if spec:
            target, = spec
            assert isinstance(target,
                              str) and target, 'Invalid target %s' % target

    if target is None:
        target = modifyFirst(rtype.name, False)
        if column is None:
            column = '%sId' % target
            register[column] = Column('fk_%s_id' % toUnderscore(target),
                                      ForeignKey(mappedId, ondelete='CASCADE'),
                                      nullable=False)
        register[target] = relationship(mappedId.class_,
                                        uselist=False,
                                        lazy='joined',
                                        viewonly=True)

    def fget(self):
        rel = getattr(self, target)
        if rel: return getattr(rel, rtype.propertyId.name)

    columnId = columnFor(getattr(mappedId.class_, rtype.propertyId.name))

    def fset(self, value):
        setattr(self, column, select([mappedId], columnId == value))

    validation = validate(Mandatory, Relation)
    return validation(
        hybrid_property(fget,
                        fset,
                        expr=joinedExpr(mappedId.class_,
                                        rtype.propertyId.name)))
Example #14
0
def summarized_property(name):
    """ Adds an attribute as hybrid_property which returns the sum of the
    underlying results if called.

    Requires the class to define two aggregation functions.

    Usage::

        class Model():
            votes = summarized_property('votes')

            results = relationship('Result', ...)

            def aggregate_results(self, attribute):
                return sum(getattr(res, attribute) for res in self.results)

            @staticmethod
            def aggregate_results_expression(cls, attribute):
                expr = select([func.sum(getattr(Result, attribute))])
                expr = expr.where(Result.xxx_id == cls.id)
                expr = expr.label(attribute)
                return expr

    """

    def getter(self):
        return self.aggregate_results(name)

    def expression(cls):
        return cls.aggregate_results_expression(cls, name)

    return hybrid_property(getter, expr=expression)
Example #15
0
    def closure(cls):
        class_name = cls.__name__ + 'Localized'
        tablename = plural_name(underscorize(class_name))
        if db.metadata.tables.get(tablename) is not None:
            return
        # TODO: pass language from the babel detection
        lang = u'en'
        cls_columns = cls.__table__.get_children()
        columns = dict([(c.name, c.copy()) for c in cls_columns if isinstance(c.type, (db.Unicode, db.UnicodeText))])
        localized_names = columns.keys()
        columns.update({
            'parent_id': db.Column(db.Integer, db.ForeignKey(cls.__tablename__ + '.id'), nullable=False),
            'parent': db.relationship(cls, backref='localized_ref'),
            'locale': db.Column(db.Unicode(255), default=lang, index=True)
        })

        cls_localized = type(class_name, (db.Model, CRUDMixin), columns)

        for field in localized_names:

            def getter(self):
                localized = cls_localized.query.filter_by(parent_id=self.id, locale=lang).first()
                return getattr(localized, field) or None

            def setter(self, value):
                localized = cls_localized.query.filter_by(parent_id=self.id, locale=lang).first() or cls_localized(parent=self, locale=lang)
                setattr(localized, field, value)
                localized.save()

            def expression(self):
                return db.Query(columns[field]).filter(cls_localized.parent_id == self.id, cls_localized.locale == lang).as_scalar()

            setattr(cls, field, hybrid_property(getter, setter, expr=expression))

        closure(cls)
Example #16
0
    def test_attrs_props_prop_added_after_configure(self):
        class AnonClass(object):
            pass

        from sqlalchemy.orm import mapper, column_property
        from sqlalchemy.ext.hybrid import hybrid_property

        m = mapper(AnonClass, self.tables.users)

        eq_(set(inspect(AnonClass).attrs.keys()), set(["id", "name"]))
        eq_(
            set(inspect(AnonClass).all_orm_descriptors.keys()),
            set(["id", "name"]),
        )

        m.add_property("q", column_property(self.tables.users.c.name))

        def desc(self):
            return self.name

        AnonClass.foob = hybrid_property(desc)

        eq_(set(inspect(AnonClass).attrs.keys()), set(["id", "name", "q"]))
        eq_(
            set(inspect(AnonClass).all_orm_descriptors.keys()),
            set(["id", "name", "q", "foob"]),
        )
Example #17
0
def override_attr(attr_name, parent_name, fget=None):
    """Create property that overrides an attribute coming from parent.

    In order to ensure setter functionality at creation time, ``parent`` must be
    initialized before the overriden attribute.

    :param attr_name: The name of the attribute to be overriden.
    :param parent_name: The name of the attribute from which to override the attribute.
    :param fget: Getter for own property
    """

    own_attr_name = '_' + attr_name

    def _get(self):
        parent = getattr(self, parent_name)
        attr = getattr(self, own_attr_name)
        fget_ = (lambda self, __: attr) if fget is None else fget
        return fget_(
            self,
            own_attr_name) if attr is not None or not parent else getattr(
                parent, attr_name)

    def _set(self, value):
        parent = getattr(self, parent_name)
        own_value = getattr(self, own_attr_name)
        if not parent or own_value is not None or value != getattr(
                parent, attr_name):
            setattr(self, own_attr_name, value)

    def _expr(cls):
        return getattr(cls, own_attr_name)

    return hybrid_property(_get, _set, expr=_expr)
Example #18
0
def pure_slot_property(slot_name, slot_transform=lambda x: x):
    """
    Create a property (class must have slots) that maps to a slot

    :param slot_name: name of the slot
    :param slot_transform: transformation to operate before assigning value
    :return:
    """
    def fget(self):
        # return None if the slot does not exist. alternative could be to raise an exception
        try:
            return self[slot_name].value
        except KeyError:
            return None

    def fset(self, value):
        v = slot_transform(value)
        if v is None:
            if slot_name in self:
                del self[slot_name]
        else:
            self[slot_name] = v

    return hybrid_property(
        fget=fget,
        fset=fset,
    )
Example #19
0
def override_attr(attr_name, parent_name, fget=None):
    """Create property that overrides an attribute coming from parent.

    In order to ensure setter functionality at creation time, ``parent`` must be
    initialized before the overriden attribute.

    :param attr_name: The name of the attribute to be overriden.
    :param parent_name: The name of the attribute from which to override the attribute.
    :param fget: Getter for own property
    """

    own_attr_name = '_' + attr_name

    def _get(self):
        parent = getattr(self, parent_name)
        attr = getattr(self, own_attr_name)
        fget_ = (lambda self, __: attr) if fget is None else fget
        return fget_(self, own_attr_name) if attr is not None or not parent else getattr(parent, attr_name)

    def _set(self, value):
        parent = getattr(self, parent_name)
        own_value = getattr(self, own_attr_name)
        if not parent or own_value is not None or value != getattr(parent, attr_name):
            setattr(self, own_attr_name, value)

    def _expr(cls):
        return getattr(cls, own_attr_name)

    return hybrid_property(_get, _set, expr=_expr)
Example #20
0
    def test_attrs_props_prop_added_after_configure(self):
        class Thing(InspectionAttr):
            pass

        class AnonClass(object):
            __foo__ = "bar"
            __bat__ = Thing()

        from sqlalchemy.orm import column_property
        from sqlalchemy.ext.hybrid import hybrid_property

        m = self.mapper_registry.map_imperatively(AnonClass, self.tables.users)

        eq_(set(inspect(AnonClass).attrs.keys()), set(["id", "name"]))
        eq_(
            set(inspect(AnonClass).all_orm_descriptors.keys()),
            set(["id", "name"]),
        )

        m.add_property("q", column_property(self.tables.users.c.name))

        def desc(self):
            return self.name

        AnonClass.foob = hybrid_property(desc)

        eq_(set(inspect(AnonClass).attrs.keys()), set(["id", "name", "q"]))
        eq_(
            set(inspect(AnonClass).all_orm_descriptors.keys()),
            set(["id", "name", "q", "foob"]),
        )
Example #21
0
def DateTimeAtColumn(prefix: str) -> hybrid_property:
    datetime_key = f"{prefix}_datetime"
    timezone_key = f"{prefix}_timezone"

    def getter(self) -> datetime.datetime | None:
        dt: datetime.datetime | None = getattr(self, datetime_key)
        tz: datetime.tzinfo | None = getattr(self, timezone_key)
        if dt and tz:
            return dt.astimezone(tz)
        return dt

    def setter(self, dt: datetime.datetime):
        setattr(self, timezone_key, dt.tzinfo)
        setattr(self, datetime_key, dt.astimezone(UTC))

    def custom_comparator(cls):
        return DateTimeAtComparator(
            getattr(cls, datetime_key),
            getattr(cls, timezone_key),
        )

    return hybrid_property(
        fget=getter,
        fset=setter,
        custom_comparator=custom_comparator,
    )
Example #22
0
    def get_sqlalchemy_mapping(self, registry, namespace, fieldname,
                               properties):
        """Return the property of the field

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """

        def wrap(method):
            m = self.kwargs.get(method)
            if m is None:
                return None

            def function_method(model_self, *args, **kwargs):
                if method == 'fget':
                    cls = registry.get(model_self.__registry_name__)
                    if model_self is cls:
                        return hasattr(model_self, m)

                return getattr(model_self, m)(*args, **kwargs)

            return function_method

        fget = wrap('fget')
        fset = wrap('fset')
        fdel = wrap('fdel')
        fexpr = wrap('fexpr')

        self.format_label(fieldname)
        properties['loaded_fields'][fieldname] = self.label
        return hybrid_property(fget, fset, fdel=fdel, expr=fexpr)
Example #23
0
    def get_sqlalchemy_mapping(self, registry, namespace, fieldname,
                               properties):
        """Return the property of the field

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """
        self.fieldname = fieldname
        self.format_label(fieldname)
        properties['loaded_fields'][fieldname] = self.label

        fget = self.get_fget()
        fset = self.get_fset()
        fdel = self.get_fdel()
        fexpr = self.get_fexpr()
        fcomparator = self.get_fcomparator()

        for funct in (fget, fset, fdel, fexpr, fcomparator):
            funct.__name__ = fieldname

        hybrid = hybrid_property(fget)
        hybrid = hybrid.setter(fset)
        hybrid = hybrid.deleter(fdel)
        if isinstance(self.field, Many2One):
            hybrid = hybrid.comparator(fcomparator)
        else:
            hybrid = hybrid.expression(fexpr)

        return hybrid
Example #24
0
 def decorator(func):
     if not info.get('filterable', True):
         ret = property(func)
     else:
         ret = hybrid_property(func)
     ret.fget.info = info
     return ret
Example #25
0
def insert_datetime_field(name, locals_, nullable=True):
    datetime_key = f'{name}_datetime'
    timezone_key = f'{name}_timezone'
    locals_[datetime_key] = Column(
        DateTime(timezone=False),
        nullable=nullable,
    )
    locals_[timezone_key] = Column(TimezoneType())

    def getter(self):
        if getattr(self, timezone_key):
            return getattr(self,
                           timezone_key).localize(getattr(self, datetime_key))
        else:
            return getattr(self, datetime_key)

    def setter(self, dt: datetime.datetime):
        if dt.tzinfo is pytz.UTC:
            d = datetime.datetime.fromtimestamp(calendar.timegm(
                dt.timetuple()))
            setattr(self, datetime_key,
                    d - tzlocal.get_localzone().utcoffset(d))
            setattr(self, timezone_key, pytz.UTC)
        else:
            setattr(self, timezone_key, dt.tzinfo)
            setattr(self, datetime_key, dt.replace(tzinfo=None))

    locals_[f'{name}_at'] = hybrid_property(fget=getter, fset=setter)
Example #26
0
    def iri_class_decorator(klass):
        iri_hpropname = '_'+iri_propname
        setattr(klass, iri_hpropname,
                column_property(id_to_iri(getattr(klass, iri_id_colname))))

        def iri_accessor(self):
            return getattr(self, iri_hpropname)

        def iri_expression(klass):
            return id_to_iri(getattr(klass, iri_id_colname))

        def iri_setter(self, val):
            setattr(self, iri_hpropname, val)
            setattr(self, iri_id_colname, iri_to_id(val))

        def iri_deleter(self):
            setattr(self, iri_id_colname, None)

        col = getattr(klass, iri_id_colname)
        if not col.property.columns[0].nullable:
            iri_deleter = None
        prop = hybrid_property(
            iri_accessor, iri_setter, iri_deleter, iri_expression)
        setattr(klass, iri_propname, prop)
        return klass
Example #27
0
def make_lr_attr(actor: str) -> hybrid_property:
    """Create local role hybrid_property attributes."""
    def getter(self):
        """Return the list of user_ids with a local role."""
        return principals_by_role(self, actor)

    def setter(self, values):
        """Update local role collection."""
        set_local_roles_by_role_name(self, actor, values)

    def expression(cls: ClassItemType):
        """Expression that return principal ids from database."""
        return get_lr_expression(cls, actor)

    def comparator(cls: ClassItemType):
        """Return the custom local roles comparator."""
        return LocalRolesComparator(cls, actor)

    lr_attr = hybrid_property(
        fget=getter,
        fset=setter,
        expr=expression,
        custom_comparator=comparator
    )
    return lr_attr
Example #28
0
def setup_hybrids(cls,
                  name,
                  translation_cls,
                  current_locale=get_current_locale,
                  default=None):

    # The "relationship to aliased class" pattern is in use, and this aliased
    # object was private to the setup_relationships() function, so pull it out
    # here so we can use it in a query
    # See: https://docs.sqlalchemy.org/en/14/orm/join_conditions.html#relationship-to-aliased-class

    partition_alias = cls.current_translation.entity.entity

    def _fget(self):
        return getattr(self.current_translation, name, default)

    def _fset(self, value):
        locale_name = current_locale()

        trans = self.translations.setdefault(
            locale_name, translation_cls(language_id=locale_name))

        setattr(trans, name, value)

    def _expr(_cls):
        return getattr(cls._current_translation_partition.c, name)
        #return getattr(partition_alias, name)

    log.info('Adding hybrid attribute: %s.%s', cls, name)

    prop = hybrid_property(fget=_fget, fset=_fset, expr=_expr)

    setattr(cls, name, prop)
Example #29
0
def mapped_to_slot_property(col, slot_name, slot_transform=lambda x: x):
    """Assume the attribute in the class as the same name as the table column with "_" prepended"""
    col_name = "_{}".format(col.name)

    def fget(self):
        return getattr(self, col_name)

    def fset(self, value):
        v = slot_transform(value)
        if v is None:
            if slot_name in self:
                del self[slot_name]
        else:
            self[slot_name] = v

        setattr(self, col_name, value)

    def expr(cls):
        return col

    return hybrid_property(
        fget=fget,
        fset=fset,
        expr=expr,
    )
Example #30
0
    def iri_class_decorator(klass):
        iri_hpropname = '_' + iri_propname
        setattr(klass, iri_hpropname,
                column_property(id_to_iri(getattr(klass, iri_id_colname))))

        def iri_accessor(self):
            return getattr(self, iri_hpropname)

        def iri_expression(klass):
            return id_to_iri(getattr(klass, iri_id_colname))

        def iri_setter(self, val):
            setattr(self, iri_hpropname, val)
            setattr(self, iri_id_colname, iri_to_id(val))

        def iri_deleter(self):
            setattr(self, iri_id_colname, None)

        col = getattr(klass, iri_id_colname)
        if not col.property.columns[0].nullable:
            iri_deleter = None
        prop = hybrid_property(iri_accessor, iri_setter, iri_deleter,
                               iri_expression)
        setattr(klass, iri_propname, prop)
        return klass
Example #31
0
def ignore_case_property(text_attr):
    def getter(self):
        return CaseInsensitiveWord(getattr(self, text_attr))

    def setter(self, value):
        setattr(self, text_attr, value)

    return hybrid_property(getter, setter)
Example #32
0
def ignore_case_property(text_attr):
    def getter(self):
        return CaseInsensitiveWord(getattr(self, text_attr))

    def setter(self, value):
        setattr(self, text_attr, value)

    return hybrid_property(getter, setter)
Example #33
0
def synonym(name):
    """
    Utility function mimicking the behavior of the old SA synonym function
    with the new hybrid property semantics.
    """
    return hybrid_property(lambda inst: getattr(inst, name),
                           lambda inst, value: setattr(inst, name, value),
                           expr=lambda cls: getattr(cls, name))
Example #34
0
    def create_hybrid_property(cls, attr_name):
        """Create a hybrid property that does the rendering of the column.

        :param attr_name: a name for the attribute the unprocessed value can be
                          accessed through (e.g. `_description`).
        """
        return hybrid_property(cls._render_getter(attr_name), fset=cls._render_setter(attr_name),
                               expr=cls._render_expression(attr_name))
Example #35
0
    def create_hybrid_property(cls, attr_name):
        """Create a hybrid property that does the rendering of the column.

        :param attr_name: a name for the attribute the unprocessed value can be
                          accessed through (e.g. `_description`).
        """
        return hybrid_property(cls._render_getter(attr_name), fset=cls._render_setter(attr_name),
                               expr=cls._render_expression(attr_name))
Example #36
0
def hybrid_property_gncnumeric(num_col, denom_col):
    """Return an hybrid_property handling a Decimal represented by a numerator and a
    denominator column.
    It assumes the python field related to the sqlcolumn is named as _sqlcolumn.

    :type num_col: sqlalchemy.sql.schema.Column
    :type denom_col: sqlalchemy.sql.schema.Column
    :return: sqlalchemy.ext.hybrid.hybrid_property
    """
    num_name, denom_name = "_{}".format(num_col.name), "_{}".format(denom_col.name)
    name = num_col.name.split("_")[0]

    def fset(self, d):
        if d is None:
            num, denom = None, None
        else:
            if isinstance(d, tuple):
                d = Decimal(d[0]) / d[1]
            elif isinstance(d, (int, int, str)):
                d = Decimal(d)
            elif isinstance(d, float):
                raise TypeError(("Received a floating-point number {} where a decimal is expected. " +
                                 "Use a Decimal, str, or int instead").format(d))
            elif not isinstance(d, Decimal):
                raise TypeError(("Received an unknown type {} where a decimal is expected. " +
                                 "Use a Decimal, str, or int instead").format(type(d).__name__))

            sign, digits, exp = d.as_tuple()
            denom = 10 ** max(-exp, 0)

            denom_basis = getattr(self, "{}_basis".format(denom_name), None)
            if denom_basis is not None:
                denom = denom_basis

            num = int(d * denom)
            if not ((-MAX_NUMBER < num < MAX_NUMBER) and (-MAX_NUMBER < denom < MAX_NUMBER)):
                raise ValueError(("The amount '{}' cannot be represented in GnuCash. " +
                                  "Either it is too large or it has too many decimals").format(d))

        setattr(self, num_name, num)
        setattr(self, denom_name, denom)

    def fget(self):
        num, denom = getattr(self, num_name), getattr(self, denom_name)
        if num is None:
            return
        else:
            return Decimal(num) / denom

    def expr(cls):
        # todo: cast into Decimal for postgres and for sqlite (for the latter, use sqlite3.register_converter ?)
        return (cast(num_col, Float) / denom_col).label(name)

    return hybrid_property(
        fget=fget,
        fset=fset,
        expr=expr,
    )
Example #37
0
def hybrid_property_gncnumeric(num_col, denom_col):
    """Return an hybrid_property handling a Decimal represented by a numerator and a denominator column.
    It assumes the python field related to the sqlcolumn is named as _sqlcolumn.

    :type num_col: sqlalchemy.sql.schema.Column
    :type denom_col: sqlalchemy.sql.schema.Column
    :return: sqlalchemy.ext.hybrid.hybrid_property
    """
    num_name, denom_name = "_{}".format(num_col.name), "_{}".format(
        denom_col.name)
    name = num_col.name.split("_")[0]

    def fset(self, d):
        if d is None:
            num, denom = None, None
        else:
            if isinstance(d, tuple):
                d = Decimal(d[0]) / d[1]
            elif isinstance(d, (int, long, str)):
                d = Decimal(d)
            elif isinstance(d, float):
                raise TypeError((
                    "Received a floating-point number {} where a decimal is expected. "
                    + "Use a Decimal, str, or int instead").format(d))
            elif not isinstance(d, Decimal):
                raise TypeError((
                    "Received an unknown type {} where a decimal is expected. "
                    + "Use a Decimal, str, or int instead").format(
                        type(d).__name__))

            sign, digits, exp = d.as_tuple()
            denom = 10**max(-exp, 0)

            denom_basis = getattr(self, "{}_basis".format(denom_name), None)
            if denom_basis is not None:
                denom = denom_basis

            num = int(d * denom)

        setattr(self, num_name, num)
        setattr(self, denom_name, denom)

    def fget(self):
        num, denom = getattr(self, num_name), getattr(self, denom_name)
        if num is None:
            return
        else:
            return Decimal(num) / denom

    def expr(cls):
        # todo: cast into Decimal for postgres and for sqlite (for the latter, use sqlite3.register_converter ?)
        return (cast(num_col, Float) / denom_col).label(name)

    return hybrid_property(
        fget=fget,
        fset=fset,
        expr=expr,
    )
Example #38
0
def year_property(date_attr):
    def getter(self):
        date = getattr(self, date_attr)
        return date and date.year

    def expr(cls):
        return extract('year', getattr(cls, date_attr))

    return hybrid_property(getter, expr=expr)
Example #39
0
def year_property(date_attr):
    def getter(self):
        date = getattr(self, date_attr)
        return date and date.year

    def expr(cls):
        return extract('year', getattr(cls, date_attr))

    return hybrid_property(getter, expr=expr)
Example #40
0
 def assign_attr_getter_setters(self, attr):
     setattr(
         self.model,
         attr,
         hybrid_property(
             fget=translation_getter_factory(attr),
             fset=translation_setter_factory(attr),
             expr=lambda cls: getattr(cls.__translatable__['class'], attr)
         )
     )
Example #41
0
def synonym(name):
    """
    Utility function mimicking the behavior of the old SA synonym function
    with the new hybrid property semantics.
    """
    return hybrid_property(
        lambda inst: getattr(inst, name),
        lambda inst, value: setattr(inst, name, value),
        expr=lambda cls: getattr(cls, name),
    )
Example #42
0
    def get_property(self, registry, namespace, fieldname, properties):
        """Return the property of the field

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """
        return hybrid_property(
            self.wrap_getter_column(fieldname),
            self.wrap_setter_column(fieldname),
            expr=self.wrap_expr_column(fieldname))
Example #43
0
def quality_requirement_property(text_attr):
    def getter(self):
        return qualities.Requirements(getattr(self, text_attr))

    def setter(self, value):
        if isinstance(value, basestring):
            setattr(self, text_attr, value)
        else:
            setattr(self, text_attr, value.text)

    prop = hybrid_property(getter, setter)
    return prop
Example #44
0
def quality_requirement_property(text_attr):
    def getter(self):
        return qualities.Requirements(getattr(self, text_attr))

    def setter(self, value):
        if isinstance(value, str):
            setattr(self, text_attr, value)
        else:
            setattr(self, text_attr, value.text)

    prop = hybrid_property(getter, setter)
    return prop
Example #45
0
def hybrid_property_gncnumeric(num_col, denom_col):
    """Return an hybrid_property handling a Decimal represented by a numerator and a denominator column.
    It assumes the python field related to the sqlcolumn is named as _sqlcolumn.

    :type num_col: sqlalchemy.sql.schema.Column
    :type denom_col: sqlalchemy.sql.schema.Column
    :return: sqlalchemy.ext.hybrid.hybrid_property
    """
    num_name, denom_name = "_{}".format(num_col.name), "_{}".format(
        denom_col.name)
    name = num_col.name.split("_")[0]

    def fset(self, d):
        if d is None:
            num, denom = None, None
        else:
            if isinstance(d, tuple):
                d = Decimal(d[0]) / d[1]
            elif isinstance(d, (float, int, long, str)):
                d = Decimal(d)
            assert isinstance(d, Decimal)

            sign, digits, exp = d.as_tuple()
            denom = 10**max(-exp, 0)

            # print num_name, denom,
            denom_basis = getattr(self, "{}_basis".format(denom_name), None)
            if denom_basis is not None:
                # print "got a basis for ", self, denom_basis
                denom = denom_basis
            # print denom
            num = int(d * denom)

        setattr(self, num_name, num)
        setattr(self, denom_name, denom)

    def fget(self):
        num, denom = getattr(self, num_name), getattr(self, denom_name)
        if num is None:
            return
        else:
            return Decimal(num) / denom

    def expr(cls):
        # todo: cast into Decimal for postgres and for sqlite (for the latter, use sqlite3.register_converter ?)
        return (cast(num_col, Float) / denom_col).label(name)

    return hybrid_property(
        fget=fget,
        fset=fset,
        expr=expr,
    )
Example #46
0
def hybrid_property_gncnumeric(num_col, denom_col):
    """Return an hybrid_property handling a Decimal represented by a numerator and a denominator column.
    It assumes the python field related to the sqlcolumn is named as _sqlcolumn.

    :type num_col: sqlalchemy.sql.schema.Column
    :type denom_col: sqlalchemy.sql.schema.Column
    :return: sqlalchemy.ext.hybrid.hybrid_property
    """
    num_name, denom_name = "_{}".format(num_col.name), "_{}".format(denom_col.name)
    name = num_col.name.split("_")[0]

    def fset(self, d):
        if d is None:
            num, denom = None, None
        else:
            if isinstance(d, tuple):
                d = Decimal(d[0]) / d[1]
            elif isinstance(d, (float, int, long, str)):
                d = Decimal(d)
            assert isinstance(d, Decimal)

            sign, digits, exp = d.as_tuple()
            denom = 10 ** max(-exp, 0)

            # print num_name, denom,
            denom_basis = getattr(self, "{}_basis".format(denom_name), None)
            if denom_basis is not None:
                # print "got a basis for ", self, denom_basis
                denom = denom_basis
            # print denom
            num = int(d * denom)

        setattr(self, num_name, num)
        setattr(self, denom_name, denom)


    def fget(self):
        num, denom = getattr(self, num_name), getattr(self, denom_name)
        if num is None:
            return
        else:
            return Decimal(num) / denom

    def expr(cls):
        # todo: cast into Decimal for postgres and for sqlite (for the latter, use sqlite3.register_converter ?)
        return (cast(num_col, Float) / denom_col).label(name)

    return hybrid_property(
        fget=fget,
        fset=fset,
        expr=expr,
    )
Example #47
0
def mapper(class_, local_table=None, id_attribute='id', slug_expression=None,
           *args, **kwargs):
    """
    Convenience wrapper around the SA mapper which will set up the hybrid
    "id" and "slug" attributes required by everest after calling the SA
    mapper.
    
    If you (e.g., for testing purposes) want to clear mappers created with
    this function, use the :func:`clear_mappers` function in this module.
    
    :param str id_attribute: the name of the column in the table to use as
      ID column (will be aliased to a new "id" attribute in the mapped class)
    :param slug_expression: function to generate a slug SQL expression given
      the mapped class as argument.
    """
    mpr = sa_mapper(class_, local_table=local_table, *args, **kwargs)
    # Set up the ID attribute as a hybrid property, if necessary.
    if id_attribute != 'id':
        # Make sure we are not overwriting an already mapped or customized
        # 'id' attribute.
        if 'id' in mpr.columns:
            mpr.dispose()
            raise ValueError('Attempting to overwrite the mapped "id" '
                             'attribute.')
        elif isdatadescriptor(getattr(class_, 'id', None)):
            mpr.dispose()
            raise ValueError('Attempting to overwrite the custom data '
                             'descriptor defined for the "id" attribute.')
        fget = lambda obj: getattr(obj, id_attribute)
        fset = lambda self, value: setattr(self, id_attribute, value)
        class_.id = hybrid_property(fget, fset=fset, expr=fget)
    # Set up the slug attribute as a hybrid property.
    if slug_expression is None:
        cls_expr = lambda cls: cast(getattr(cls, 'id'), String)
    else:
        cls_expr = slug_expression
    # If this is a polymorphic class, a base class may already have a
    # hybrid descriptor set as slug attribute.
    slug_descr = None
    for base_cls in class_.__mro__:
        try:
            slug_descr = object.__getattribute__(base_cls, 'slug')
        except AttributeError:
            pass
        else:
            break
    if isinstance(slug_descr, hybrid_descriptor):
        descr = slug_descr.descriptor
    else:
        descr = slug_descr
    class_.slug = hybrid_descriptor(descr, expr=cls_expr)
    return mpr
Example #48
0
def sub_table_addon(master_cls, slave_cls, hoist=True):
    """Slave a sub table to the master table.

    Example:
        Among other things hoist all columns from economy into county.

    class County:
        @property
        def produced_grain(self):
            return self.economy.produced_grain

        @produced_grain.setter
        def produced_grain(self, value):
            self.economy.produced_grain = value

    @hybrid_property
    def {col}(self):
        return self.{sub_table}.{col}

    f = hybrid_property(
        lambda self: getattr(getattr(self, 'economy'), 'grain_produced'))
    setattr(County, 'grain_produced', f)
    """
    master_table_name = master_cls.__table__.name
    sub_table_name = slave_cls.__table__.name

    if hoist:
        cols_to_hoist = set([
            strip_leading_underscore(c.name) for c in slave_cls.__table__.c
        ]) - set(
            [strip_leading_underscore(c.name) for c in master_cls.__table__.c])

        for name in cols_to_hoist:
            func = hybrid_property(lambda self, name=name: getattr(
                getattr(self, sub_table_name), name))
            setattr(master_cls, name, func)
            setattr(
                master_cls, name,
                func.setter(lambda self, value, name=name: setattr(
                    getattr(self, sub_table_name), name, value)))

    # add relationships linking county and slave table
    slave_cls.county_id = db.Column(db.Integer,
                                    db.ForeignKey(f'{master_table_name}.id'),
                                    nullable=False)
    slave_cls.county = db.relationship(master_cls.__name__,
                                       backref=db.backref(sub_table_name,
                                                          uselist=False))

    # add sub table object to county init
    compose_into_init(master_cls, slave_cls, sub_table_name)
    def test_inspect(self, db):
        # attach a fake method to Segment where the type is unknown:
        defval = 'a'
        Segment._fake_method = \
            hybrid_property(lambda self: defval,
                            expr=lambda cls: func.substr(cls.download_code, 1, 1))

        insp = Inspector(Segment)
        attnames = list(insp.attnames(Inspector.PKEY))
        assert attnames == ['id']
        attnames = list(insp.attnames(Inspector.FKEY, sort=True))
        assert 'event_id' in attnames and 'id' not in attnames \
            and 'classes' not in attnames and '_fake_method' not in attnames
        attnames2 = list(insp.attnames(Inspector.FKEY, sort=False))
        # sort=False MIGHT return the same attributes order as sorted=True
        # thus perform a check only if they differ:
        if attnames != attnames:
            assert sorted(attnames) == sorted(attnames2)
        attnames = list(insp.attnames(Inspector.QATT))
        assert '_fake_method' in attnames and not 'id' in attnames and \
            not 'event_id' in attnames
        attnames = list(insp.attnames(Inspector.REL, sort=True))
        assert 'classes' in attnames and 'id' not in attnames \
            and 'event_id' not in attnames and '_fake_method' not in attnames
        attnames2 = list(insp.attnames(Inspector.REL, sort=False))
        # sort=False MIGHT return the same attributes order as sorted=True
        # thus perform a check only if they differ:
        if attnames != attnames:
            assert sorted(attnames) == sorted(attnames2)

        attnames = insp.attnames(deep=True)
        for attname in attnames:
            attval = insp.attval(attname)
            assert isinstance(attval, QueryableAttribute)
            if attname == '_fake_method':
                assert insp.atttype(attname) is None
            else:
                assert insp.atttype(attname) is not None

        seg = db.session.query(Segment).first()
        insp = Inspector(seg)
        attnames = insp.attnames(deep=True)
        for attname in attnames:
            val = insp.attval(attname)
            if attname == '_fake_method':
                assert val == defval
            if attname.startswith('classes.'):
                assert isinstance(val, list)
            else:
                assert not isinstance(val, (dict, list, set))
Example #50
0
    def get_sqlalchemy_mapping(self, registry, namespace, fieldname,
                               properties):
        """Return the property of the field

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """
        self.format_label(fieldname)
        properties['loaded_fields'][fieldname] = self.label
        return hybrid_property(self.get_fget(),
                               self.get_fset(),
                               fdel=self.get_fdel(),
                               expr=self.get_fexpr())
Example #51
0
def quality_property(text_attr):

    def getter(self):
        return qualities.get(getattr(self, text_attr))

    def setter(self, value):
        if isinstance(value, basestring):
            setattr(self, text_attr, value)
        else:
            setattr(self, text_attr, value.name)

    def comparator(self):
        return QualityComparator(getattr(self, text_attr))

    prop = hybrid_property(getter, setter)
    prop.comparator(comparator)
    return prop
Example #52
0
def relationshipModel(mappedId, *spec):
    '''
    Creates a relationship with the model, this should only be used in case the mapped model database id is different from the
    actual model id.
    
    @param mappedId: InstrumentedAttribute
        The mapped model id to create the relation with.
    @param spec: arguments containing
        column: string
            The column name containing the foreign key relation, attention if target is provided then
            also column needs to be provided, if None provided it will create one automatically.
        target: string
            The SQL alchemy relationship target name, if None provided it will create one automatically.
    '''
    assert isinstance(mappedId, InstrumentedAttribute), 'Invalid mapped id %s' % mappedId
    register = callerLocals()
    assert '__module__' in register, 'This function should only be used inside meta class definitions'
    rtype = typeFor(mappedId.class_)
    assert isinstance(rtype, TypeModel), 'Invalid class %s' % mappedId.class_
    assert isinstance(rtype.propertyId, TypeProperty), 'No property id for %s' % rtype
    assert rtype.propertyId.name != mappedId.property.key, 'Same database id with the model id \'%s\' for %s' % mappedId.class_
    
    column = target = None
    if spec:
        column, *spec = spec
        assert isinstance(column, str), 'Invalid column %s' % column
        if spec:
            target, = spec
            assert isinstance(target, str) and target, 'Invalid target %s' % target
    
    if target is None:
        target = modifyFirst(rtype.name, False)
        if column is None:
            column = '%sId' % target
            register[column] = Column('fk_%s_id' % toUnderscore(target), ForeignKey(mappedId, ondelete='CASCADE'), nullable=False)
        register[target] = relationship(mappedId.class_, uselist=False, lazy='joined', viewonly=True)
    
    def fget(self):
        rel = getattr(self, target)
        if rel: return getattr(rel, rtype.propertyId.name)
    
    columnId = columnFor(getattr(mappedId.class_, rtype.propertyId.name))
    def fset(self, value): setattr(self, column, select([mappedId], columnId == value))
    
    validation = validate(Mandatory, Relation)
    return validation(hybrid_property(fget, fset, expr=joinedExpr(mappedId.class_, rtype.propertyId.name)))
Example #53
0
    def get_sqlalchemy_mapping(self, registry, namespace, fieldname,
                               properties):
        """Return the property of the field

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """
        self.format_label(fieldname)
        properties['loaded_fields'][fieldname] = self.label
        return hybrid_property(
            self.get_fget(),
            self.get_fset(),
            fdel=self.get_fdel(),
            expr=self.get_fexpr()
        )
Example #54
0
    def create_column(self, cname, remote_type, foreign_key, properties):

        def wrapper(cls):
            return SA_Column(
                cname.attribute_name,
                remote_type,
                nullable=self.nullable,
                unique=self.unique,
                info=dict(label=self.label, foreign_key=foreign_key))

        properties[(anyblok_column_prefix +
                    cname.attribute_name)] = declared_attr(wrapper)
        properties['loaded_columns'].append(cname.attribute_name)
        properties['hybrid_property_columns'].append(cname.attribute_name)
        properties[cname.attribute_name] = hybrid_property(
            self.wrap_getter_column(cname.attribute_name),
            super(Many2One, self).wrap_setter_column(cname.attribute_name),
            expr=self.wrap_expr_column(cname.attribute_name))
Example #55
0
    def get_property(self, registry, namespace, fieldname, properties):
        """Return the property of the field

        .. warning::

            In the case of the get is called in classattribute,
            SQLAlchemy wrap for each call the column, the id of the wrapper
            is not the same

        :param registry: current registry
        :param namespace: name of the model
        :param fieldname: name of the field
        :param properties: properties known to the model
        """
        return hybrid_property(
            self.wrap_getter_column(fieldname),
            self.wrap_setter_column(fieldname),
            expr=self.wrap_expr_column(fieldname))
Example #56
0
    def generate_hybrid(self, property_name):
        """
        Generate a SQLAlchemy hybrid property for given translation model
        property.

        :param property_name:
            Name of the translation model property to generate hybrid property
            for.
        """
        setattr(
            self.model,
            property_name,
            hybrid_property(
                fget=self.getter_factory(property_name),
                fset=self.setter_factory(property_name),
                expr=lambda cls: getattr(
                    cls.__translatable__['class'], property_name
                )
            )
        )
Example #57
0
    def __new__(mcs, name, bases, attrs):
        for n, v in attrs.items():
            attrName = n[1:]
            if isinstance(v, Column) and n.startswith('_') and not attrs.has_key(attrName):
                v.key  = attrName
                v.name = attrName

                # Add dynamic property
                setter = ModelPropertySetter(n)

                attrs[attrName] = hybrid_property(
                    ModelPropertyGetter(n), setter, None, ModelPropertyExpression(n) )

                # Add external-key property
                info = getattr(v, 'info')
                if info and 'model' in info:
                    columnName = info['column'] if 'column' in info else 'i'
                    attrs[info['get']] = property(
                        ExternalKeyProperty(attrName, info['model'], columnName) )

        return DeclarativeMeta.__new__(mcs, name, bases, attrs)
Example #58
0
    def create_property(cls, localized, columns, field):

        def getter(self):
            instance = localized.query.filter_by(id=self.id,
                                                 locale=lang).first()
            return instance and getattr(instance, field) or None

        def setter(self, value):
            from_db = localized.query.filter_by(id=self.id,
                                                locale=lang).first()

            instance = from_db or localized(parent=self, locale=lang)
            setattr(instance, field, value)
            instance.save()

        def expression(self):
            return db.Query(columns[field]) \
                .filter(localized.parent_id == self.id,
                        localized.locale == lang).as_scalar()

        setattr(cls, field, hybrid_property(getter, setter, expr=expression))