postgres syntax error in associative proxy

Issue #1290 resolved
Former user created an issue

On a site using psycopg2 and SQLAlchemy 0.5.0 I just got this traceback in the logs:

Module tostyle4you.controllers.retailer:367 in edit
<<                    for img_id in self.form_result.get("deleteImage", [])](]))

            for image in article.images:
                if image.id in toDelete:
                    meta.Session.delete(image)
>>  for image in article.images:
Module sqlalchemy.orm.attributes:160 in __get__
<<          if instance is None:
                return self
            return self.impl.get(instance_state(instance))

    class _ProxyImpl(object):
>>  return self.impl.get(instance_state(instance))
Module sqlalchemy.orm.attributes:366 in get
<<                      if passive is not PASSIVE_OFF:
                            return PASSIVE_NORESULT
                        value = callable_()
                        if value is not ATTR_WAS_SET:
                            return self.set_committed_value(state, value)
>>  value = callable_()
Module sqlalchemy.orm.strategies:557 in __call__
<<          q = q.filter(strategy.lazy_clause(state))

            result = q.all()
            if strategy.uselist:
                return result
>>  result = q.all()
Module sqlalchemy.orm.query:1018 in all
<<          """
            return list(self)

        @_generative(__no_clauseelement_condition)
>>  return list(self)
Module sqlalchemy.orm.query:1111 in __iter__
<<          context.statement.use_labels = True
            if self._autoflush and not self._populate_existing:
                self.session._autoflush()
            return self._execute_and_instances(context)
>>  self.session._autoflush()
Module sqlalchemy.orm.session:904 in _autoflush
<<      def _autoflush(self):
            if self.autoflush and not self._flushing:
                self.flush()

        def _finalize_loaded(self, states):
>>  self.flush()
Module sqlalchemy.orm.session:1349 in flush
<<          try:
                self._flushing = True
                self._flush(objects)
            finally:
                self._flushing = False
>>  self._flush(objects)
Module sqlalchemy.orm.session:1419 in _flush
<<              subtransactions=True)
            try:
                flush_context.execute()

                for ext in self.extensions:
>>  flush_context.execute()
Module sqlalchemy.orm.unitofwork:260 in execute
<<          if self._should_log_info:
                self.logger.info("Task dump:\n" + self._dump(tasks))
            UOWExecutor().execute(self, tasks)
            if self._should_log_info:
                self.logger.info("Execute Complete")
>>  UOWExecutor().execute(self, tasks)
Module sqlalchemy.orm.unitofwork:723 in execute
<<          if isdelete is not True:
                for task in tasks:
                    self.execute_save_steps(trans, task)
            if isdelete is not False:
                for task in reversed(tasks):
>>  self.execute_save_steps(trans, task)
Module sqlalchemy.orm.unitofwork:738 in execute_save_steps
<<      def execute_save_steps(self, trans, task):
            self.save_objects(trans, task)
            self.execute_cyclical_dependencies(trans, task, False)
            self.execute_dependencies(trans, task)
>>  self.save_objects(trans, task)
Module sqlalchemy.orm.unitofwork:729 in save_objects
<<      def save_objects(self, trans, task):
            task.mapper._save_obj(task.polymorphic_tosave_objects, trans)

        def delete_objects(self, trans, task):
>>  task.mapper._save_obj(task.polymorphic_tosave_objects, trans)
Module sqlalchemy.orm.mapper:1358 in _save_obj
<<                  rows = 0
                    for state, params, mapper, connection, value_params in update:
                        c = connection.execute(statement.values(value_params), params)
                        mapper._postfetch(uowtransaction, connection, table, state, c, c.last_updated_params(), value_params)
>>  c = connection.execute(statement.values(value_params), params)
Module sqlalchemy.engine.base:824 in execute
<<          for c in type(object).__mro__:
                if c in Connection.executors:
                    return Connection.executors[c](c)(self, object, multiparams, params)
            else:
                raise exc.InvalidRequestError("Unexecutable object type: " + str(type(object)))
>>  return Connection.executors[c](c)(self, object, multiparams, params)
Module sqlalchemy.engine.base:874 in _execute_clauseelement
<<                          parameters=params
                        )
            return self.__execute_context(context)

        def _execute_compiled(self, compiled, multiparams, params):
>>  return self.__execute_context(context)
Module sqlalchemy.engine.base:896 in __execute_context
<<              self._cursor_executemany(context.cursor, context.statement, context.parameters, context=context)
            else:
                self._cursor_execute(context.cursor, context.statement, context.parameters[0](0), context=context)
            if context.compiled:
                context.post_exec()
>>  self._cursor_execute(context.cursor, context.statement, context.parameters[0](0), context=context)
Module sqlalchemy.engine.base:950 in _cursor_execute
<<              self.dialect.do_execute(cursor, statement, parameters, context=context)
            except Exception, e:
                self._handle_dbapi_exception(e, statement, parameters, cursor, context)
                raise
>>  self._handle_dbapi_exception(e, statement, parameters, cursor, context)
Module sqlalchemy.engine.base:931 in _handle_dbapi_exception
<<                  if self.__close_with_result:
                        self.close()
                raise exc.DBAPIError.instance(statement, parameters, e, connection_invalidated=is_disconnect)
            finally:
                del self._reentrant_error
>>  raise exc.DBAPIError.instance(statement, parameters, e, connection_invalidated=is_disconnect)
ProgrammingError: (ProgrammingError) syntax error at or near "WHERE" LINE 1: UPDATE clothing_size SET WHERE clothing_size.article_id = 7... ^ 'UPDATE clothing_size SET WHERE clothing_size.article_id = %(clothing_size_article_id)s AND clothing_size.size = %(clothing_size_size)s' {'clothing_size_article_id': 73830, 'clothing_size_size': u'14'}

the relevant models look this this:

class ArticleSize(BaseObject):
    __tablename__ = "clothing_size"

    article_id = schema.Column(types.Integer(),
            schema.ForeignKey("clothing_article.id", onupdate="CASCADE", ondelete="CASCADE"),
            primary_key=True, index=True)
    size = schema.Column(types.String(8), primary_key=True)

    def __init__(self, size, article_id=None):
        self.size=size
        if article_id is not None:
            self.article_id=article_id

class ClothingArticle(BaseObject):
    """An article of clothing
    """

    __tablename__ = "clothing_article"

    id = schema.Column(types.Integer(), primary_key=True, autoincrement=True)
    _sizes = orm.relation(ArticleSize, lazy=True, collection_class=set,
            cascade="all, delete, delete-orphan")
    sizes = association_proxy("_sizes", "size")

Comments (3)

  1. Former user Account Deleted

    In 0.5.1 the problem manifests itself in a different way, which makes me suspect the problem might be in my code:

    Module tostyle4you.controllers.retailer:343 in edit
    <<          article.brand=self.form_result["brand"]("brand")
                article.currency=self.form_result["currency"]("currency")
                article.sizes=self.form_result["sizes"]("sizes")
                article.price=self.form_result["price"]("price")
                article.sale=self.form_result["sale"]("sale")
    >>  article.sizes=self.form_result["sizes"]("sizes")
    Module sqlalchemy.ext.associationproxy:207 in __set__
    <<              if proxy is not values:
                        proxy.clear()
                        self._set(proxy, values)
    
            def __delete__(self, obj):
    >>  self._set(proxy, values)
    Module sqlalchemy.ext.associationproxy:263 in _set
    <<              proxy.update(values)
                elif self.collection_class is set:
                    proxy.update(values)
                else:
                    raise exceptions.ArgumentError(
    >>  proxy.update(values)
    Module sqlalchemy.ext.associationproxy:766 in update
    <<      def update(self, other):
                for value in other:
                    self.add(value)
    >>  for value in other:
    TypeError: 'NoneType' object is not iterable
    
  2. Former user Account Deleted

    And indeed it turns out I was assigning None to the proxy instance. After fixing that things are working as expected.

  3. Log in to comment