Example #1
0
 def test_join_cond_no_such_unrelated_column(self):
     m = MetaData()
     t1 = Table('t1', m, Column('x', Integer, ForeignKey('t2.id')),
                         Column('y', Integer, ForeignKey('t3.q')))
     t2 = Table('t2', m, Column('id', Integer))
     t3 = Table('t3', m, Column('id', Integer))
     assert sql_util.join_condition(t1, t2).compare(t1.c.x==t2.c.id)
     assert sql_util.join_condition(t2, t1).compare(t1.c.x==t2.c.id)
 def test_join_cond_no_such_unrelated_column(self):
     m = MetaData()
     t1 = Table('t1', m, Column('x', Integer, ForeignKey('t2.id')), 
                         Column('y', Integer, ForeignKey('t3.q')))
     t2 = Table('t2', m, Column('id', Integer))
     t3 = Table('t3', m, Column('id', Integer))
     assert sql_util.join_condition(t1, t2).compare(t1.c.x==t2.c.id)
     assert sql_util.join_condition(t2, t1).compare(t1.c.x==t2.c.id)
Example #3
0
 def _search_for_join(mapper, table):
     # find a join between the given mapper's mapped table and the given table.
     # will try the mapper's local table first for more specificity, then if not
     # found will try the more general mapped table, which in the case of inheritance
     # is a join.
     try:
         return join_condition(mapper.local_table, table)
     except sa_exc.ArgumentError, e:
         return join_condition(mapper.mapped_table, table)
Example #4
0
 def _search_for_join(mapper, table):
     # find a join between the given mapper's mapped table and the given table.
     # will try the mapper's local table first for more specificity, then if not
     # found will try the more general mapped table, which in the case of inheritance
     # is a join.
     try:
         return join_condition(mapper.local_table, table)
     except sa_exc.ArgumentError, e:
         return join_condition(mapper.mapped_table, table)
 def test_join_cond_no_such_unrelated_table(self):
     m = MetaData()
     # bounding the "good" column with two "bad" ones is so to 
     # try to get coverage to get the "continue" statements
     # in the loop...
     t1 = Table('t1', m, 
                         Column('y', Integer, ForeignKey('t22.id')),
                         Column('x', Integer, ForeignKey('t2.id')), 
                         Column('q', Integer, ForeignKey('t22.id')), 
                         )
     t2 = Table('t2', m, Column('id', Integer))
     assert sql_util.join_condition(t1, t2).compare(t1.c.x==t2.c.id)
     assert sql_util.join_condition(t2, t1).compare(t1.c.x==t2.c.id)
Example #6
0
 def test_join_cond_no_such_unrelated_table(self):
     m = MetaData()
     # bounding the "good" column with two "bad" ones is so to
     # try to get coverage to get the "continue" statements
     # in the loop...
     t1 = Table('t1', m,
                         Column('y', Integer, ForeignKey('t22.id')),
                         Column('x', Integer, ForeignKey('t2.id')),
                         Column('q', Integer, ForeignKey('t22.id')),
                         )
     t2 = Table('t2', m, Column('id', Integer))
     assert sql_util.join_condition(t1, t2).compare(t1.c.x==t2.c.id)
     assert sql_util.join_condition(t2, t1).compare(t1.c.x==t2.c.id)
Example #7
0
    def test_join_condition_ignore_nonexistent_tables(self):
        m = MetaData()
        t1 = Table("t1", m, Column("id", Integer))
        t2 = Table("t2", m, Column("id", Integer),
                   Column("t1id", ForeignKey("t1.id")))
        with testing.expect_deprecated(
                "The join_condition.ignore_nonexistent_tables "
                "parameter is deprecated"):
            join_cond = sql_util.join_condition(t1,
                                                t2,
                                                ignore_nonexistent_tables=True)

        t1t2 = t1.join(t2)

        assert t1t2.onclause.compare(join_cond)
Example #8
0
    def test_join_condition_ignore_nonexistent_tables(self):
        m = MetaData()
        t1 = Table("t1", m, Column("id", Integer))
        t2 = Table(
            "t2", m, Column("id", Integer), Column("t1id", ForeignKey("t1.id"))
        )
        with testing.expect_deprecated(
            "The join_condition.ignore_nonexistent_tables "
            "parameter is deprecated"
        ):
            join_cond = sql_util.join_condition(
                t1, t2, ignore_nonexistent_tables=True
            )

        t1t2 = t1.join(t2)

        assert t1t2.onclause.compare(join_cond)
Example #9
0
    def __init__(cls, classname, bases, dict_):
        if '_decl_class_registry' in cls.__dict__:
            return type.__init__(cls, classname, bases, dict_)

        cls._decl_class_registry[classname] = cls
        our_stuff = util.OrderedDict()
        for k in dict_:
            value = dict_[k]
            if (isinstance(value, tuple) and len(value) == 1 and
                isinstance(value[0], (Column, MapperProperty))):
                util.warn("Ignoring declarative-like tuple value of attribute "
                          "%s: possibly a copy-and-paste error with a comma "
                          "left at the end of the line?" % k)
                continue
            if not isinstance(value, (Column, MapperProperty)):
                continue
            prop = _deferred_relation(cls, value)
            our_stuff[k] = prop

        # set up attributes in the order they were created 
        our_stuff.sort(lambda x, y: cmp(our_stuff[x]._creation_order, our_stuff[y]._creation_order))

        table = None
        if '__table__' not in cls.__dict__:
            if '__tablename__' in cls.__dict__:
                tablename = cls.__tablename__
                autoload = cls.__dict__.get('__autoload__')
                if autoload:
                    table_kw = {'autoload': True}
                else:
                    table_kw = {}
                cols = []
                for key, c in our_stuff.iteritems():
                    if isinstance(c, ColumnProperty):
                        for col in c.columns:
                            if isinstance(col, Column) and col.table is None:
                                _undefer_column_name(key, col)
                                cols.append(col)
                    elif isinstance(c, Column):
                        _undefer_column_name(key, c)
                        cols.append(c)
                cls.__table__ = table = Table(tablename, cls.metadata,
                                              *cols, **table_kw)
        else:
            table = cls.__table__

        mapper_args = getattr(cls, '__mapper_args__', {})
        if 'inherits' not in mapper_args:
            inherits = cls.__mro__[1]
            inherits = cls._decl_class_registry.get(inherits.__name__, None)
            if inherits:
                mapper_args['inherits'] = inherits
                if not mapper_args.get('concrete', False) and table:
                    # figure out the inherit condition with relaxed rules about nonexistent tables,
                    # to allow for ForeignKeys to not-yet-defined tables (since we know for sure that our parent
                    # table is defined within the same MetaData)
                    mapper_args['inherit_condition'] = sql_util.join_condition(inherits.__table__, table, ignore_nonexistent_tables=True)
        
        if hasattr(cls, '__mapper_cls__'):
            mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
        else:
            mapper_cls = mapper
        cls.__mapper__ = mapper_cls(cls, table, properties=our_stuff, **mapper_args)
        return type.__init__(cls, classname, bases, dict_)
Example #10
0
    def test_join_condition(self):
        m = MetaData()
        t1 = Table('t1', m, Column('id', Integer))
        t2 = Table('t2', m, Column('id', Integer), Column('t1id',
                   ForeignKey('t1.id')))
        t3 = Table('t3', m, Column('id', Integer), Column('t1id',
                   ForeignKey('t1.id')), Column('t2id',
                   ForeignKey('t2.id')))
        t4 = Table('t4', m, Column('id', Integer), Column('t2id',
                   ForeignKey('t2.id')))
        t1t2 = t1.join(t2)
        t2t3 = t2.join(t3)
        for (left, right, a_subset, expected) in [
            (t1, t2, None, t1.c.id == t2.c.t1id),
            (t1t2, t3, t2, t1t2.c.t2_id == t3.c.t2id),
            (t2t3, t1, t3, t1.c.id == t3.c.t1id),
            (t2t3, t4, None, t2t3.c.t2_id == t4.c.t2id),
            (t2t3, t4, t3, t2t3.c.t2_id == t4.c.t2id),
            (t2t3.join(t1), t4, None, t2t3.c.t2_id == t4.c.t2id),
            (t2t3.join(t1), t4, t1, t2t3.c.t2_id == t4.c.t2id),
            (t1t2, t2t3, t2, t1t2.c.t2_id == t2t3.c.t3_t2id),
            ]:
            assert expected.compare(sql_util.join_condition(left,
                                    right, a_subset=a_subset))

        # these are ambiguous, or have no joins
        for left, right, a_subset in [
            (t1t2, t3, None),
            (t2t3, t1, None),
            (t1, t4, None),
            (t1t2, t2t3, None),
        ]:
            assert_raises(
                exc.ArgumentError,
                sql_util.join_condition,
                left, right, a_subset=a_subset
            )

        als = t2t3.alias()
        # test join's behavior, including natural
        for left, right, expected in [
            (t1, t2, t1.c.id==t2.c.t1id),
            (t1t2, t3, t1t2.c.t2_id==t3.c.t2id),
            (t2t3, t1, t1.c.id==t3.c.t1id),
            (t2t3, t4, t2t3.c.t2_id==t4.c.t2id),
            (t2t3, t4, t2t3.c.t2_id==t4.c.t2id),
            (t2t3.join(t1), t4, t2t3.c.t2_id==t4.c.t2id),
            (t2t3.join(t1), t4, t2t3.c.t2_id==t4.c.t2id),
            (t1t2, als, t1t2.c.t2_id==als.c.t3_t2id)
        ]:
            assert expected.compare(
                left.join(right).onclause
            )



        # TODO: this raises due to right side being "grouped", and no
        # longer has FKs.  Did we want to make _FromGrouping friendlier
        # ?

        assert_raises_message(exc.ArgumentError,
                              "Perhaps you meant to convert the right "
                              "side to a subquery using alias\(\)\?",
                              t1t2.join, t2t3)
        assert_raises_message(exc.ArgumentError,
                              "Perhaps you meant to convert the right "
                              "side to a subquery using alias\(\)\?",
                              t1t2.join, t2t3.select(use_labels=True))
Example #11
0
def _as_declarative(cls, classname, dict_):
    cls._decl_class_registry[classname] = cls
    our_stuff = util.OrderedDict()
    for k in dict_:
        value = dict_[k]
        if (isinstance(value, tuple) and len(value) == 1 and
            isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relation(cls, value)
        our_stuff[k] = prop

    # set up attributes in the order they were created
    our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)

    # extract columns from the class dict
    cols = []
    for key, c in our_stuff.iteritems():
        if isinstance(c, ColumnProperty):
            for col in c.columns:
                if isinstance(col, Column) and col.table is None:
                    _undefer_column_name(key, col)
                    cols.append(col)
        elif isinstance(c, Column):
            _undefer_column_name(key, c)
            cols.append(c)
            # if the column is the same name as the key,
            # remove it from the explicit properties dict.
            # the normal rules for assigning column-based properties
            # will take over, including precedence of columns
            # in multi-column ColumnProperties.
            if key == c.key:
                del our_stuff[key]

    table = None
    if '__table__' not in cls.__dict__:
        if '__tablename__' in cls.__dict__:
            tablename = cls.__tablename__

            table_args = cls.__dict__.get('__table_args__')
            if isinstance(table_args, dict):
                args, table_kw = (), table_args
            elif isinstance(table_args, tuple):
                args = table_args[0:-1]
                table_kw = table_args[-1]
            else:
                args, table_kw = (), {}

            autoload = cls.__dict__.get('__autoload__')
            if autoload:
                table_kw['autoload'] = True

            cls.__table__ = table = Table(tablename, cls.metadata,
                                          *(tuple(cols) + tuple(args)), **table_kw)
    else:
        table = cls.__table__
        if cols:
            for c in cols:
                if not table.c.contains_column(c):
                    raise exceptions.ArgumentError("Can't add additional column %r when specifying __table__" % key)

    mapper_args = getattr(cls, '__mapper_args__', {})
    if 'inherits' not in mapper_args:
        for c in cls.__bases__:
            if _is_mapped_class(c):
                mapper_args['inherits'] = cls._decl_class_registry.get(c.__name__, None)
                break

    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    if not table and 'inherits' not in mapper_args:
        raise exceptions.InvalidRequestError("Class %r does not have a __table__ or __tablename__ "
                    "specified and does not inherit from an existing table-mapped class." % cls)

    elif 'inherits' in mapper_args and not mapper_args.get('concrete', False):
        inherited_mapper = class_mapper(mapper_args['inherits'], compile=False)
        inherited_table = inherited_mapper.local_table
        if 'inherit_condition' not in mapper_args and table:
            # figure out the inherit condition with relaxed rules
            # about nonexistent tables, to allow for ForeignKeys to
            # not-yet-defined tables (since we know for sure that our
            # parent table is defined within the same MetaData)
            mapper_args['inherit_condition'] = sql_util.join_condition(
                mapper_args['inherits'].__table__, table,
                ignore_nonexistent_tables=True)

        if not table:
            # single table inheritance.
            # ensure no table args
            table_args = cls.__dict__.get('__table_args__')
            if table_args is not None:
                raise exceptions.ArgumentError("Can't place __table_args__ on an inherited class with no table.")

            # add any columns declared here to the inherited table.
            for c in cols:
                if c.primary_key:
                    raise exceptions.ArgumentError("Can't place primary key columns on an inherited class with no table.")
                inherited_table.append_column(c)

        # single or joined inheritance
        # exclude any cols on the inherited table which are not mapped on the parent class, to avoid
        # mapping columns specific to sibling/nephew classes
        inherited_mapper = class_mapper(mapper_args['inherits'], compile=False)
        inherited_table = inherited_mapper.local_table

        if 'exclude_properties' not in mapper_args:
            mapper_args['exclude_properties'] = exclude_properties = \
                set([c.key for c in inherited_table.c if c not in inherited_mapper._columntoproperty])
            exclude_properties.difference_update([c.key for c in cols])

    cls.__mapper__ = mapper_cls(cls, table, properties=our_stuff, **mapper_args)
Example #12
0
def _as_declarative(cls, classname, dict_):

    # dict_ will be a dictproxy, which we can't write to, and we need to!
    dict_ = dict(dict_)

    column_copies = {}
    potential_columns = {}
    
    mapper_args = {}
    table_args = inherited_table_args = None
    tablename = None
    parent_columns = ()
    
    for base in cls.__mro__:
        if _is_mapped_class(base):
            parent_columns = base.__table__.c.keys()
        else:
            for name,obj in vars(base).items():
                if name == '__mapper_args__':
                    if not mapper_args:
                        mapper_args = cls.__mapper_args__
                elif name == '__tablename__':
                    if not tablename:
                        tablename = cls.__tablename__
                elif name == '__table_args__':
                    if not table_args:                        
                        table_args = cls.__table_args__
                        if base is not cls:
                            inherited_table_args = True
                elif base is not cls:
                    # we're a mixin.
                    
                    if isinstance(obj, Column):
                        if obj.foreign_keys:
                            raise exceptions.InvalidRequestError(
                            "Columns with foreign keys to other columns "
                            "must be declared as @classproperty callables "
                            "on declarative mixin classes. ")
                        if name not in dict_ and not (
                                '__table__' in dict_ and 
                                name in dict_['__table__'].c
                                ):
                            potential_columns[name] = \
                                    column_copies[obj] = \
                                    obj.copy()
                            column_copies[obj]._creation_order = \
                                    obj._creation_order
                    elif isinstance(obj, MapperProperty):
                        raise exceptions.InvalidRequestError(
                            "Mapper properties (i.e. deferred,"
                            "column_property(), relationship(), etc.) must "
                            "be declared as @classproperty callables "
                            "on declarative mixin classes.")
                    elif isinstance(obj, util.classproperty):
                        dict_[name] = ret = \
                                column_copies[obj] = getattr(cls, name)
                        if isinstance(ret, (Column, MapperProperty)) and \
                            ret.doc is None:
                            ret.doc = obj.__doc__

    # apply inherited columns as we should
    for k, v in potential_columns.items():
        if tablename or k not in parent_columns:
            dict_[k] = v
            
    if inherited_table_args and not tablename:
        table_args = None

    # make sure that column copies are used rather 
    # than the original columns from any mixins
    for k, v in mapper_args.iteritems():
        mapper_args[k] = column_copies.get(v,v)
    
    cls._decl_class_registry[classname] = cls
    our_stuff = util.OrderedDict()

    for k in dict_:
        value = dict_[k]
        if isinstance(value, util.classproperty):
            value = getattr(cls, k)
            
        if (isinstance(value, tuple) and len(value) == 1 and
            isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relationship(cls, value)
        our_stuff[k] = prop

    # set up attributes in the order they were created
    our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)

    # extract columns from the class dict
    cols = []
    for key, c in our_stuff.iteritems():
        if isinstance(c, ColumnProperty):
            for col in c.columns:
                if isinstance(col, Column) and col.table is None:
                    _undefer_column_name(key, col)
                    cols.append(col)
        elif isinstance(c, Column):
            _undefer_column_name(key, c)
            cols.append(c)
            # if the column is the same name as the key, 
            # remove it from the explicit properties dict.
            # the normal rules for assigning column-based properties
            # will take over, including precedence of columns
            # in multi-column ColumnProperties.
            if key == c.key:
                del our_stuff[key]

    table = None
    if '__table__' not in dict_:
        if tablename is not None:
            
            if isinstance(table_args, dict):
                args, table_kw = (), table_args
            elif isinstance(table_args, tuple):
                args = table_args[0:-1]
                table_kw = table_args[-1]
                if len(table_args) < 2 or not isinstance(table_kw, dict):
                    raise exceptions.ArgumentError(
                        "Tuple form of __table_args__ is "
                        "(arg1, arg2, arg3, ..., {'kw1':val1, "
                        "'kw2':val2, ...})"
                    )
            else:
                args, table_kw = (), {}

            autoload = dict_.get('__autoload__')
            if autoload:
                table_kw['autoload'] = True

            cls.__table__ = table = Table(tablename, cls.metadata,
                                          *(tuple(cols) + tuple(args)),
                                           **table_kw)
    else:
        table = cls.__table__
        if cols:
            for c in cols:
                if not table.c.contains_column(c):
                    raise exceptions.ArgumentError(
                        "Can't add additional column %r when "
                        "specifying __table__" % c.key
                    )
    
    if 'inherits' not in mapper_args:
        for c in cls.__bases__:
            if _is_mapped_class(c):
                mapper_args['inherits'] = cls._decl_class_registry.get(
                                                            c.__name__, None)
                break

    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    if table is None and 'inherits' not in mapper_args:
        raise exceptions.InvalidRequestError(
            "Class %r does not have a __table__ or __tablename__ "
            "specified and does not inherit from an existing "
            "table-mapped class." % cls
            )

    elif 'inherits' in mapper_args and not mapper_args.get('concrete', False):
        inherited_mapper = class_mapper(mapper_args['inherits'],
                                            compile=False)
        inherited_table = inherited_mapper.local_table
        if 'inherit_condition' not in mapper_args and table is not None:
            # figure out the inherit condition with relaxed rules
            # about nonexistent tables, to allow for ForeignKeys to
            # not-yet-defined tables (since we know for sure that our
            # parent table is defined within the same MetaData)
            mapper_args['inherit_condition'] = sql_util.join_condition(
                mapper_args['inherits'].__table__, table,
                ignore_nonexistent_tables=True)

        if table is None:
            # single table inheritance.
            # ensure no table args
            if table_args:
                raise exceptions.ArgumentError(
                    "Can't place __table_args__ on an inherited class "
                    "with no table."
                    )
        
            # add any columns declared here to the inherited table.
            for c in cols:
                if c.primary_key:
                    raise exceptions.ArgumentError(
                        "Can't place primary key columns on an inherited "
                        "class with no table."
                        )
                if c.name in inherited_table.c:
                    raise exceptions.ArgumentError(
                        "Column '%s' on class %s conflicts with "
                        "existing column '%s'" % 
                        (c, cls, inherited_table.c[c.name])
                    )
                inherited_table.append_column(c)
    
        # single or joined inheritance
        # exclude any cols on the inherited table which are not mapped on the
        # parent class, to avoid
        # mapping columns specific to sibling/nephew classes
        inherited_mapper = class_mapper(mapper_args['inherits'],
                                            compile=False)
        inherited_table = inherited_mapper.local_table
        
        if 'exclude_properties' not in mapper_args:
            mapper_args['exclude_properties'] = exclude_properties = \
                set([c.key for c in inherited_table.c
                     if c not in inherited_mapper._columntoproperty])
            exclude_properties.difference_update([c.key for c in cols])
    
    cls.__mapper__ = mapper_cls(cls, 
                                table, 
                                properties=our_stuff, 
                                **mapper_args)
Example #13
0
def _as_declarative(cls, classname, dict_):
    cls._decl_class_registry[classname] = cls
    our_stuff = util.OrderedDict()
    for k in dict_:
        value = dict_[k]
        if (isinstance(value, tuple) and len(value) == 1
                and isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relation(cls, value)
        our_stuff[k] = prop

    # set up attributes in the order they were created
    our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)

    table = None
    if '__table__' not in cls.__dict__:
        if '__tablename__' in cls.__dict__:
            tablename = cls.__tablename__

            table_args = cls.__dict__.get('__table_args__')
            if isinstance(table_args, dict):
                args, table_kw = (), table_args
            elif isinstance(table_args, tuple):
                args = table_args[0:-1]
                table_kw = table_args[-1]
            else:
                args, table_kw = (), {}

            autoload = cls.__dict__.get('__autoload__')
            if autoload:
                table_kw['autoload'] = True

            cols = []
            for key, c in our_stuff.iteritems():
                if isinstance(c, ColumnProperty):
                    for col in c.columns:
                        if isinstance(col, Column) and col.table is None:
                            _undefer_column_name(key, col)
                            cols.append(col)
                elif isinstance(c, Column):
                    _undefer_column_name(key, c)
                    cols.append(c)
                    # if the column is the same name as the key,
                    # remove it from the explicit properties dict.
                    # the normal rules for assigning column-based properties
                    # will take over, including precedence of columns
                    # in multi-column ColumnProperties.
                    if key == c.key:
                        del our_stuff[key]
            cls.__table__ = table = Table(tablename, cls.metadata,
                                          *(tuple(cols) + tuple(args)),
                                          **table_kw)
    else:
        table = cls.__table__

    mapper_args = getattr(cls, '__mapper_args__', {})
    if 'inherits' not in mapper_args:
        inherits = cls.__mro__[1]
        inherits = cls._decl_class_registry.get(inherits.__name__, None)
        if inherits:
            mapper_args['inherits'] = inherits
            if not mapper_args.get(
                    'concrete', False
            ) and table and 'inherit_condition' not in mapper_args:
                # figure out the inherit condition with relaxed rules
                # about nonexistent tables, to allow for ForeignKeys to
                # not-yet-defined tables (since we know for sure that our
                # parent table is defined within the same MetaData)
                mapper_args['inherit_condition'] = sql_util.join_condition(
                    inherits.__table__, table, ignore_nonexistent_tables=True)

    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    cls.__mapper__ = mapper_cls(cls,
                                table,
                                properties=our_stuff,
                                **mapper_args)
Example #14
0
    def __init__(cls, classname, bases, dict_):
        if '_decl_class_registry' in cls.__dict__:
            return type.__init__(cls, classname, bases, dict_)

        cls._decl_class_registry[classname] = cls
        our_stuff = util.OrderedDict()
        for k in dict_:
            value = dict_[k]
            if (isinstance(value, tuple) and len(value) == 1
                    and isinstance(value[0], (Column, MapperProperty))):
                util.warn("Ignoring declarative-like tuple value of attribute "
                          "%s: possibly a copy-and-paste error with a comma "
                          "left at the end of the line?" % k)
                continue
            if not isinstance(value, (Column, MapperProperty)):
                continue
            prop = _deferred_relation(cls, value)
            our_stuff[k] = prop

        # set up attributes in the order they were created
        our_stuff.sort(lambda x, y: cmp(our_stuff[x]._creation_order,
                                        our_stuff[y]._creation_order))

        table = None
        if '__table__' not in cls.__dict__:
            if '__tablename__' in cls.__dict__:
                tablename = cls.__tablename__
                autoload = cls.__dict__.get('__autoload__')
                if autoload:
                    table_kw = {'autoload': True}
                else:
                    table_kw = {}
                cols = []
                for key, c in our_stuff.iteritems():
                    if isinstance(c, ColumnProperty):
                        for col in c.columns:
                            if isinstance(col, Column) and col.table is None:
                                _undefer_column_name(key, col)
                                cols.append(col)
                    elif isinstance(c, Column):
                        _undefer_column_name(key, c)
                        cols.append(c)
                cls.__table__ = table = Table(tablename, cls.metadata, *cols,
                                              **table_kw)
        else:
            table = cls.__table__

        mapper_args = getattr(cls, '__mapper_args__', {})
        if 'inherits' not in mapper_args:
            inherits = cls.__mro__[1]
            inherits = cls._decl_class_registry.get(inherits.__name__, None)
            if inherits:
                mapper_args['inherits'] = inherits
                if not mapper_args.get('concrete', False) and table:
                    # figure out the inherit condition with relaxed rules about nonexistent tables,
                    # to allow for ForeignKeys to not-yet-defined tables (since we know for sure that our parent
                    # table is defined within the same MetaData)
                    mapper_args['inherit_condition'] = sql_util.join_condition(
                        inherits.__table__,
                        table,
                        ignore_nonexistent_tables=True)

        if hasattr(cls, '__mapper_cls__'):
            mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
        else:
            mapper_cls = mapper
        cls.__mapper__ = mapper_cls(cls,
                                    table,
                                    properties=our_stuff,
                                    **mapper_args)
        return type.__init__(cls, classname, bases, dict_)
    def test_join_condition(self):
        m = MetaData()
        t1 = Table('t1', m, Column('id', Integer))
        t2 = Table('t2', m, Column('id', Integer), Column('t1id',
                   ForeignKey('t1.id')))
        t3 = Table('t3', m, Column('id', Integer), Column('t1id',
                   ForeignKey('t1.id')), Column('t2id',
                   ForeignKey('t2.id')))
        t4 = Table('t4', m, Column('id', Integer), Column('t2id',
                   ForeignKey('t2.id')))
        t1t2 = t1.join(t2)
        t2t3 = t2.join(t3)
        for (left, right, a_subset, expected) in [
            (t1, t2, None, t1.c.id == t2.c.t1id),
            (t1t2, t3, t2, t1t2.c.t2_id == t3.c.t2id),
            (t2t3, t1, t3, t1.c.id == t3.c.t1id),
            (t2t3, t4, None, t2t3.c.t2_id == t4.c.t2id),
            (t2t3, t4, t3, t2t3.c.t2_id == t4.c.t2id),
            (t2t3.join(t1), t4, None, t2t3.c.t2_id == t4.c.t2id),
            (t2t3.join(t1), t4, t1, t2t3.c.t2_id == t4.c.t2id),
            (t1t2, t2t3, t2, t1t2.c.t2_id == t2t3.c.t3_t2id),
            ]:
            assert expected.compare(sql_util.join_condition(left,
                                    right, a_subset=a_subset))

        # these are ambiguous, or have no joins
        for left, right, a_subset in [
            (t1t2, t3, None),
            (t2t3, t1, None),
            (t1, t4, None),
            (t1t2, t2t3, None),
        ]:
            assert_raises(
                exc.ArgumentError,
                sql_util.join_condition,
                left, right, a_subset=a_subset
            )

        als = t2t3.alias()
        # test join's behavior, including natural
        for left, right, expected in [
            (t1, t2, t1.c.id==t2.c.t1id),
            (t1t2, t3, t1t2.c.t2_id==t3.c.t2id),
            (t2t3, t1, t1.c.id==t3.c.t1id),
            (t2t3, t4, t2t3.c.t2_id==t4.c.t2id),
            (t2t3, t4, t2t3.c.t2_id==t4.c.t2id),
            (t2t3.join(t1), t4, t2t3.c.t2_id==t4.c.t2id),
            (t2t3.join(t1), t4, t2t3.c.t2_id==t4.c.t2id),
            (t1t2, als, t1t2.c.t2_id==als.c.t3_t2id)
        ]:
            assert expected.compare(
                left.join(right).onclause
            )



        # TODO: this raises due to right side being "grouped", and no
        # longer has FKs.  Did we want to make _FromGrouping friendlier
        # ?

        assert_raises_message(exc.ArgumentError,
                              "Perhaps you meant to convert the right "
                              "side to a subquery using alias\(\)\?",
                              t1t2.join, t2t3)
        assert_raises_message(exc.ArgumentError,
                              "Perhaps you meant to convert the right "
                              "side to a subquery using alias\(\)\?",
                              t1t2.join, t2t3.select(use_labels=True))
Example #16
0
def _as_declarative(cls, classname, dict_):
    cls._decl_class_registry[classname] = cls

    # this sets up our_stuff which reads in the attributes and converts
    # them to SA columns, etc...
    our_stuff = util.OrderedDict()

    # just here to handle SA declarative, not needed for Django
    for k in dict_:
        value = dict_[k]
        if (isinstance(value, tuple) and len(value) == 1 and
            isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relation(cls, value)
        our_stuff[k] = prop

    # Django will *always* have set the pk before we get here. Check if
    # it is a Django AutoField so we can override it with our own. This
    # will allow for a custom primary key to just work.
    if isinstance(cls._meta.pk, AutoField):
        # we need to add in the django-sqlalchemy version of the AutoField
        # because the one that Django adds will not work for our purposes.
        auto_field = DSAutoField(verbose_name='ID', primary_key=True, auto_created=True)
        # this might seem redundant but without it the name is not set 
        # for SA
        auto_field.name = "id"
        # Call set_attributes_from_name as it normally only gets called
        # during Django's metaclass.
        auto_field.set_attributes_from_name(auto_field.name)
        # HACK: we need to force the use of our AutoField over Django's
        # AutoField.
        cls._meta.pk = auto_field
        for i, field in enumerate(cls._meta.fields):
            if isinstance(field, AutoField):
                cls._meta.fields[i] = auto_field
    for field in cls._meta.fields + cls._meta.many_to_many:
        sa_field = field.create_column()
        # A ManyToManyField will return None for the column as it does
        # not need a column.
        if sa_field is not None:
            # this allows us to build up more complex structures
            if isinstance(sa_field, dict):
                our_stuff.update(sa_field)
            else:
                our_stuff[sa_field.name] = sa_field

    # set up attributes in the order they were created
    our_stuff.sort(lambda x, y: cmp(our_stuff[x]._creation_order,
                                    our_stuff[y]._creation_order))

    table = None
    tablename = cls._meta.db_table

    # this is to support SA's declarative to support declaring a Table
    if '__table__' not in cls.__dict__:
        # this is just to support SA's declarative of allowing the
        # specification of the table name using this syntax
        if '__tablename__' in cls.__dict__:
            tablename = cls.__tablename__

        # SA supports autoloading the model from database, but that will
        # not work for Django. We're leaving this here just for future
        # consideration.
        autoload = cls.__dict__.get('__autoload__')
        if autoload:
            table_kw = {'autoload': True}
        else:
            table_kw = {}

        # this allows us to pick up only the Column types for our table
        # definition.
        cols = []
        for key, c in our_stuff.iteritems():
            if isinstance(c, ColumnProperty):
                for col in c.columns:
                    if isinstance(col, Column) and col.table is None:
                        _undefer_column_name(key, col)
                        cols.append(col)
            elif isinstance(c, Column):
                _undefer_column_name(key, c)
                cols.append(c)
        cls.__table__ = table = Table(tablename, cls.metadata,
                                      *cols, **table_kw)
    else:
        table = cls.__table__

    mapper_args = getattr(cls, '__mapper_args__', {})
    if 'inherits' not in mapper_args:
        inherits = cls.__mro__[1]
        inherits = cls._decl_class_registry.get(inherits.__name__, None)
        if inherits:
            mapper_args['inherits'] = inherits
            if not mapper_args.get('concrete', False) and table:
                # figure out the inherit condition with relaxed rules
                # about nonexistent tables, to allow for ForeignKeys to
                # not-yet-defined tables (since we know for sure that our
                # parent table is defined within the same MetaData)
                mapper_args['inherit_condition'] = sql_util.join_condition(
                    inherits.__table__, table,
                    ignore_nonexistent_tables=True)

    # declarative allows you to specify a mapper as well
    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    cls.__mapper__ = mapper_cls(cls, table, properties=our_stuff,
                                **mapper_args)
    cls.query = session.query_property()
def _as_declarative(cls, classname, dict_):
    cls._decl_class_registry[classname] = cls
    our_stuff = util.OrderedDict()
    for k in dict_:
        value = dict_[k]
        if (isinstance(value, tuple) and len(value) == 1
                and isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relation(cls, value)
        our_stuff[k] = prop

    # set up attributes in the order they were created
    our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)

    # extract columns from the class dict
    cols = []
    for key, c in our_stuff.iteritems():
        if isinstance(c, ColumnProperty):
            for col in c.columns:
                if isinstance(col, Column) and col.table is None:
                    _undefer_column_name(key, col)
                    cols.append(col)
        elif isinstance(c, Column):
            _undefer_column_name(key, c)
            cols.append(c)
            # if the column is the same name as the key,
            # remove it from the explicit properties dict.
            # the normal rules for assigning column-based properties
            # will take over, including precedence of columns
            # in multi-column ColumnProperties.
            if key == c.key:
                del our_stuff[key]

    table = None
    if '__table__' not in cls.__dict__:
        if '__tablename__' in cls.__dict__:
            tablename = cls.__tablename__

            table_args = cls.__dict__.get('__table_args__')
            if isinstance(table_args, dict):
                args, table_kw = (), table_args
            elif isinstance(table_args, tuple):
                args = table_args[0:-1]
                table_kw = table_args[-1]
                if len(table_args) < 2 or not isinstance(table_kw, dict):
                    raise exceptions.ArgumentError(
                        "Tuple form of __table_args__ is "
                        "(arg1, arg2, arg3, ..., {'kw1':val1, 'kw2':val2, ...})"
                    )
            else:
                args, table_kw = (), {}

            autoload = cls.__dict__.get('__autoload__')
            if autoload:
                table_kw['autoload'] = True

            cls.__table__ = table = Table(tablename, cls.metadata,
                                          *(tuple(cols) + tuple(args)),
                                          **table_kw)
    else:
        table = cls.__table__
        if cols:
            for c in cols:
                if not table.c.contains_column(c):
                    raise exceptions.ArgumentError(
                        "Can't add additional column %r when specifying __table__"
                        % key)

    mapper_args = getattr(cls, '__mapper_args__', {})
    if 'inherits' not in mapper_args:
        for c in cls.__bases__:
            if _is_mapped_class(c):
                mapper_args['inherits'] = cls._decl_class_registry.get(
                    c.__name__, None)
                break

    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    if not table and 'inherits' not in mapper_args:
        raise exceptions.InvalidRequestError(
            "Class %r does not have a __table__ or __tablename__ "
            "specified and does not inherit from an existing table-mapped class."
            % cls)

    elif 'inherits' in mapper_args and not mapper_args.get('concrete', False):
        inherited_mapper = class_mapper(mapper_args['inherits'], compile=False)
        inherited_table = inherited_mapper.local_table
        if 'inherit_condition' not in mapper_args and table:
            # figure out the inherit condition with relaxed rules
            # about nonexistent tables, to allow for ForeignKeys to
            # not-yet-defined tables (since we know for sure that our
            # parent table is defined within the same MetaData)
            mapper_args['inherit_condition'] = sql_util.join_condition(
                mapper_args['inherits'].__table__,
                table,
                ignore_nonexistent_tables=True)

        if not table:
            # single table inheritance.
            # ensure no table args
            table_args = cls.__dict__.get('__table_args__')
            if table_args is not None:
                raise exceptions.ArgumentError(
                    "Can't place __table_args__ on an inherited class with no table."
                )

            # add any columns declared here to the inherited table.
            for c in cols:
                if c.primary_key:
                    raise exceptions.ArgumentError(
                        "Can't place primary key columns on an inherited class with no table."
                    )
                inherited_table.append_column(c)

        # single or joined inheritance
        # exclude any cols on the inherited table which are not mapped on the parent class, to avoid
        # mapping columns specific to sibling/nephew classes
        inherited_mapper = class_mapper(mapper_args['inherits'], compile=False)
        inherited_table = inherited_mapper.local_table

        if 'exclude_properties' not in mapper_args:
            mapper_args['exclude_properties'] = exclude_properties = \
                set([c.key for c in inherited_table.c if c not in inherited_mapper._columntoproperty])
            exclude_properties.difference_update([c.key for c in cols])

    cls.__mapper__ = mapper_cls(cls,
                                table,
                                properties=our_stuff,
                                **mapper_args)
Example #18
0
def _as_declarative(cls, classname, dict_):

    # doing it this way enables these attributes to be descriptors,
    # see below...
    get_mapper_args = '__mapper_args__' in dict_
    get_table_args = '__table_args__' in dict_
    
    # dict_ will be a dictproxy, which we can't write to, and we need to!
    dict_ = dict(dict_)

    column_copies = dict()

    for base in cls.__bases__:
        names = dir(base)
        if not _is_mapped_class(base):
            for name in names:
                obj = getattr(base,name)
                if isinstance(obj, Column):
                    dict_[name]=column_copies[obj]=obj.copy()
            get_mapper_args = get_mapper_args or getattr(base,'__mapper_args__',None)
            get_table_args = get_table_args or getattr(base,'__table_args__',None)
            tablename = getattr(base,'__tablename__',None)
            if tablename:
                # subtle: if tablename is a descriptor here, we actually
                # put the wrong value in, but it serves as a marker to get
                # the right value value...
                dict_['__tablename__']=tablename

    # now that we know whether or not to get these, get them from the class
    # if we should, enabling them to be decorators
    mapper_args = get_mapper_args and cls.__mapper_args__ or {}
    table_args = get_table_args and cls.__table_args__ or None
    
    # make sure that column copies are used rather than the original columns
    # from any mixins
    for k, v in mapper_args.iteritems():
        mapper_args[k] = column_copies.get(v,v)
    
    cls._decl_class_registry[classname] = cls
    our_stuff = util.OrderedDict()
    for k in dict_:
        value = dict_[k]
        if (isinstance(value, tuple) and len(value) == 1 and
            isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relation(cls, value)
        our_stuff[k] = prop

    # set up attributes in the order they were created
    our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)

    # extract columns from the class dict
    cols = []
    for key, c in our_stuff.iteritems():
        if isinstance(c, ColumnProperty):
            for col in c.columns:
                if isinstance(col, Column) and col.table is None:
                    _undefer_column_name(key, col)
                    cols.append(col)
        elif isinstance(c, Column):
            _undefer_column_name(key, c)
            cols.append(c)
            # if the column is the same name as the key, 
            # remove it from the explicit properties dict.
            # the normal rules for assigning column-based properties
            # will take over, including precedence of columns
            # in multi-column ColumnProperties.
            if key == c.key:
                del our_stuff[key]

    table = None
    if '__table__' not in dict_:
        if '__tablename__' in dict_:
            # see above: if __tablename__ is a descriptor, this
            # means we get the right value used!
            tablename = cls.__tablename__
            
            if isinstance(table_args, dict):
                args, table_kw = (), table_args
            elif isinstance(table_args, tuple):
                args = table_args[0:-1]
                table_kw = table_args[-1]
                if len(table_args) < 2 or not isinstance(table_kw, dict):
                    raise exceptions.ArgumentError(
                                "Tuple form of __table_args__ is "
                                "(arg1, arg2, arg3, ..., {'kw1':val1, 'kw2':val2, ...})"
                            )
            else:
                args, table_kw = (), {}

            autoload = dict_.get('__autoload__')
            if autoload:
                table_kw['autoload'] = True

            cls.__table__ = table = Table(tablename, cls.metadata,
                                          *(tuple(cols) + tuple(args)), **table_kw)
    else:
        table = cls.__table__
        if cols:
            for c in cols:
                if not table.c.contains_column(c):
                    raise exceptions.ArgumentError(
                        "Can't add additional column %r when specifying __table__" % key
                        )
    
    if 'inherits' not in mapper_args:
        for c in cls.__bases__:
            if _is_mapped_class(c):
                mapper_args['inherits'] = cls._decl_class_registry.get(c.__name__, None)
                break

    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    if table is None and 'inherits' not in mapper_args:
        raise exceptions.InvalidRequestError(
            "Class %r does not have a __table__ or __tablename__ "
            "specified and does not inherit from an existing table-mapped class." % cls
            )

    elif 'inherits' in mapper_args and not mapper_args.get('concrete', False):
        inherited_mapper = class_mapper(mapper_args['inherits'], compile=False)
        inherited_table = inherited_mapper.local_table
        if 'inherit_condition' not in mapper_args and table is not None:
            # figure out the inherit condition with relaxed rules
            # about nonexistent tables, to allow for ForeignKeys to
            # not-yet-defined tables (since we know for sure that our
            # parent table is defined within the same MetaData)
            mapper_args['inherit_condition'] = sql_util.join_condition(
                mapper_args['inherits'].__table__, table,
                ignore_nonexistent_tables=True)

        if table is None:
            # single table inheritance.
            # ensure no table args
            if table_args is not None:
                raise exceptions.ArgumentError(
                    "Can't place __table_args__ on an inherited class with no table."
                    )
        
            # add any columns declared here to the inherited table.
            for c in cols:
                if c.primary_key:
                    raise exceptions.ArgumentError(
                        "Can't place primary key columns on an inherited class with no table."
                        )
                inherited_table.append_column(c)
    
        # single or joined inheritance
        # exclude any cols on the inherited table which are not mapped on the
        # parent class, to avoid
        # mapping columns specific to sibling/nephew classes
        inherited_mapper = class_mapper(mapper_args['inherits'], compile=False)
        inherited_table = inherited_mapper.local_table
        
        if 'exclude_properties' not in mapper_args:
            mapper_args['exclude_properties'] = exclude_properties = \
                set([c.key for c in inherited_table.c
                     if c not in inherited_mapper._columntoproperty])
            exclude_properties.difference_update([c.key for c in cols])
    
    cls.__mapper__ = mapper_cls(cls, table, properties=our_stuff, **mapper_args)
Example #19
0
def _as_declarative(cls, classname, dict_):
    cls._decl_class_registry[classname] = cls
    our_stuff = util.OrderedDict()
    for k in dict_:
        value = dict_[k]
        if (isinstance(value, tuple) and len(value) == 1 and
            isinstance(value[0], (Column, MapperProperty))):
            util.warn("Ignoring declarative-like tuple value of attribute "
                      "%s: possibly a copy-and-paste error with a comma "
                      "left at the end of the line?" % k)
            continue
        if not isinstance(value, (Column, MapperProperty)):
            continue
        prop = _deferred_relation(cls, value)
        our_stuff[k] = prop

    # set up attributes in the order they were created
    our_stuff.sort(key=lambda key: our_stuff[key]._creation_order)

    table = None
    if '__table__' not in cls.__dict__:
        if '__tablename__' in cls.__dict__:
            tablename = cls.__tablename__
            
            table_args = cls.__dict__.get('__table_args__')
            if isinstance(table_args, dict):
                args, table_kw = (), table_args
            elif isinstance(table_args, tuple):
                args = table_args[0:-1]
                table_kw = table_args[-1]
            else:
                args, table_kw = (), {}

            autoload = cls.__dict__.get('__autoload__')
            if autoload:
                table_kw['autoload'] = True

            cols = []
            for key, c in our_stuff.iteritems():
                if isinstance(c, ColumnProperty):
                    for col in c.columns:
                        if isinstance(col, Column) and col.table is None:
                            _undefer_column_name(key, col)
                            cols.append(col)
                elif isinstance(c, Column):
                    _undefer_column_name(key, c)
                    cols.append(c)
                    # if the column is the same name as the key, 
                    # remove it from the explicit properties dict.
                    # the normal rules for assigning column-based properties
                    # will take over, including precedence of columns
                    # in multi-column ColumnProperties.
                    if key == c.key:
                        del our_stuff[key]
            cls.__table__ = table = Table(tablename, cls.metadata,
                                          *(tuple(cols) + tuple(args)), **table_kw)
    else:
        table = cls.__table__

    mapper_args = getattr(cls, '__mapper_args__', {})
    if 'inherits' not in mapper_args:
        inherits = cls.__mro__[1]
        inherits = cls._decl_class_registry.get(inherits.__name__, None)
        if inherits:
            mapper_args['inherits'] = inherits
            if not mapper_args.get('concrete', False) and table and 'inherit_condition' not in mapper_args:
                # figure out the inherit condition with relaxed rules
                # about nonexistent tables, to allow for ForeignKeys to
                # not-yet-defined tables (since we know for sure that our
                # parent table is defined within the same MetaData)
                mapper_args['inherit_condition'] = sql_util.join_condition(
                    inherits.__table__, table,
                    ignore_nonexistent_tables=True)

    if hasattr(cls, '__mapper_cls__'):
        mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__)
    else:
        mapper_cls = mapper

    cls.__mapper__ = mapper_cls(cls, table, properties=our_stuff,
                                **mapper_args)