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 _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)
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)
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)
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))
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)
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)
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)
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 _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)
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)
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)