misleads with incorrect information about
text() or literal(). [ticket:1863]
+ - Similarly, for relationship(), foreign_keys,
+ remote_side, order_by - all column-based
+ expressions are enforced - lists of strings
+ are explicitly disallowed since this is a
+ very common error
+
- Dynamic attributes don't support collection
population - added an assertion for when
set_committed_value() is called, as well as
from sqlalchemy.orm.util import _state_mapper
from sqlalchemy.orm.attributes import instance_state
- cols = [expression._only_column_elements(q) for q in util.to_list(mapping_spec)]
+ cols = [expression._only_column_elements(q, "mapping_spec")
+ for q in util.to_list(mapping_spec)]
if len(cols) == 1:
def keyfunc(value):
state = instance_state(value)
for attr in 'primaryjoin', 'secondaryjoin':
val = getattr(self, attr)
if val is not None:
- util.assert_arg_type(val, sql.ColumnElement, attr)
- setattr(self, attr, _orm_deannotate(val))
+ setattr(self, attr, _orm_deannotate(
+ expression._only_column_elements(val, attr))
+ )
if self.order_by is not False and self.order_by is not None:
- self.order_by = [expression._literal_as_column(x) for x in
+ self.order_by = [expression._only_column_elements(x, "order_by") for x in
util.to_list(self.order_by)]
self._user_defined_foreign_keys = \
- util.column_set(expression._literal_as_column(x) for x in
+ util.column_set(expression._only_column_elements(x, "foreign_keys") for x in
util.to_column_set(self._user_defined_foreign_keys))
self.remote_side = \
- util.column_set(expression._literal_as_column(x) for x in
+ util.column_set(expression._only_column_elements(x, "remote_side") for x in
util.to_column_set(self.remote_side))
if not self.parent.concrete:
for inheriting in self.parent.iterate_to_root():
else:
return element
-def _only_column_elements(element):
+def _only_column_elements(element, name):
if hasattr(element, '__clause_element__'):
element = element.__clause_element__()
if not isinstance(element, ColumnElement):
- raise exc.ArgumentError("Column-based expression object expected; "
- "got: %r" % element)
+ raise exc.ArgumentError("Column-based expression object expected for argument '%s'; "
+ "got: '%s', type %s" % (name, element, type(element)))
return element
def _corresponding_column_or_error(fromclause, column,
@testing.resolve_artifact_names
def test_column_mapped_assertions(self):
- assert_raises_message(
- sa_exc.ArgumentError,
- "Column-based expression object expected; got: 'a'",
- collections.column_mapped_collection, "a",
- )
- assert_raises_message(
- sa_exc.ArgumentError,
- "Column-based expression object expected; got",
- collections.column_mapped_collection, text("a"),
- )
- assert_raises_message(
- sa_exc.ArgumentError,
- "Column-based expression object expected; got",
- collections.column_mapped_collection, text("a"),
- )
+ assert_raises_message(sa_exc.ArgumentError,
+ "Column-based expression object expected "
+ "for argument 'mapping_spec'; got: 'a', "
+ "type <type 'str'>",
+ collections.column_mapped_collection, 'a')
+ assert_raises_message(sa_exc.ArgumentError,
+ "Column-based expression object expected "
+ "for argument 'mapping_spec'; got: 'a', "
+ "type <class 'sqlalchemy.sql.expression._"
+ "TextClause'>",
+ collections.column_mapped_collection,
+ text('a'))
@testing.resolve_artifact_names
mapper(C2, t2)
assert_raises(sa.exc.ArgumentError, compile_mappers)
+ def test_invalid_string_args(self):
+ from sqlalchemy.ext.declarative import declarative_base
+ from sqlalchemy import util
+
+ for argname, arg in [
+ ('remote_side', ['c1.id']),
+ ('remote_side', ['id']),
+ ('foreign_keys', ['c1id']),
+ ('foreign_keys', ['C2.c1id']),
+ ('order_by', ['id']),
+ ]:
+ clear_mappers()
+ kw = {argname:arg}
+ Base = declarative_base()
+ class C1(Base):
+ __tablename__ = 'c1'
+ id = Column('id', Integer, primary_key=True)
+
+ class C2(Base):
+ __tablename__ = 'c2'
+ id_ = Column('id', Integer, primary_key=True)
+ c1id = Column('c1id', Integer, ForeignKey('c1.id'))
+ c2 = relationship(C1, **kw)
+
+ assert_raises_message(
+ sa.exc.ArgumentError,
+ "Column-based expression object expected for argument '%s'; got: '%s', type %r" % (argname, arg[0], type(arg[0])),
+ compile_mappers)
+
+
def test_fk_error_raised(self):
m = MetaData()
t1 = Table('t1', m,