Hi all,

I have a rather simple tool that loads data from YAML and put it in the
database, using the ORM layer. It designed so that it basically perform what's
called an "UPSERT", so I can load the same YAML multiple times with no
additional updates.

A few days ago I got a TypeError exception deep inside the ORM layer:

    Traceback (most recent call last):
      File "p.py", line 59, in <module>
        session.commit()
      File ".../python3.4/site-packages/sqlalchemy/orm/session.py", line 790, 
in commit
        self.transaction.commit()
      File ".../python3.4/site-packages/sqlalchemy/orm/session.py", line 392, 
in commit
        self._prepare_impl()
      File ".../python3.4/site-packages/sqlalchemy/orm/session.py", line 372, 
in _prepare_impl
        self.session.flush()
      File ".../python3.4/site-packages/sqlalchemy/orm/session.py", line 2004, 
in flush
        self._flush(objects)
      File ".../python3.4/site-packages/sqlalchemy/orm/session.py", line 2122, 
in _flush
        transaction.rollback(_capture_exception=True)
      File ".../python3.4/site-packages/sqlalchemy/util/langhelpers.py", line 
60, in __exit__
        compat.reraise(exc_type, exc_value, exc_tb)
      File ".../python3.4/site-packages/sqlalchemy/util/compat.py", line 182, 
in reraise
        raise value
      File ".../python3.4/site-packages/sqlalchemy/orm/session.py", line 2086, 
in _flush
        flush_context.execute()
      File ".../python3.4/site-packages/sqlalchemy/orm/unitofwork.py", line 
373, in execute
        rec.execute(self)
      File ".../python3.4/site-packages/sqlalchemy/orm/unitofwork.py", line 
532, in execute
        uow
      File ".../python3.4/site-packages/sqlalchemy/orm/persistence.py", line 
170, in save_obj
        mapper, table, update)
      File ".../python3.4/site-packages/sqlalchemy/orm/persistence.py", line 
692, in _emit_update_statements
        rows += c.rowcount
    TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'

This morning I investigated a bit and the following script exhibits the problem:

    import sqlalchemy as sa
    import sqlalchemy.orm as orm

    engine = sa.create_engine('mysql+cymysql://localhost/raccoon', echo=True)
    md = sa.MetaData(bind=engine)

    test_t = sa.Table(
        'test1', md,
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('zip', sa.String(5)),
        sa.Column('description', sa.String(20)),
    )

    class Test(object):
        pass

    orm.mapper(Test, test_t)

    md.create_all()

    smaker = orm.sessionmaker(autoflush=False, autocommit=False, bind=engine)
    session = smaker()

    first = session.query(Test).get(1)
    if first is None:
        first = Test()
        first.id = 1
        first.zip = "2512"
        first.description = 'Test'
        session.add(first)

    second = session.query(Test).get(2)
    if second is None:
        second = Test()
        second.id = 2
        second.zip = "2512"
        second.description = 'Test'
        session.add(second)

    session.commit()

    session = smaker()

    first = session.query(Test).get(1)
    first.zip = 2512
    first.description = 'Test'

    second = session.query(Test).get(2)
    second.zip = 2512
    second.description = 'Test'

    session.commit()

Note that I'm assigning an *integer* value to the `zip` column, equivalent to
the *string* value stored in the database: it seems that SA is "fooled" by
that, and it emits the UPDATE statement (slightly edited log):

    09:38:29,819 INFO sql...Engine SELECT test1.id AS test1_id,
                                          test1.zip AS test1_zip,
                                          test1.description AS 
test1_description 
                                   FROM test1 
                                   WHERE test1.id = %s
    09:38:29,819 INFO sql...Engine (2,)
    09:38:29,820 INFO sql...Engine UPDATE test1 SET zip=%s WHERE test1.id = %s
    09:38:29,820 INFO sql...Engine ((2512, 1), (2512, 2))

and the database accepts it (MySQL is silly, we all know!) but (I guess)
recognizes that nothing changed and does not return a `rowcount`.

So, it is evident that I shall fix those YAML files, but I wonder if the
problem could/should be catched anyway, either by fixing the driver (cymysql)
or SA itself.

Thank you,
ciao, lele.
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
[email protected]  |                 -- Fortunato Depero, 1929.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to