Re: [sqlalchemy] Error 1005 (errno 150) trying to create related tables using InnoDB

2013-08-22 Thread Gerald Thibault
I looked into the AddConstraint class, and added some debugging info and 
found it wasn't being hit, because the fk was part of a CREATE. So I'd need 
to use @compiles to override both of those to ensure both of them render 
the references correctly.

The single point where the magic happens is in compiler.py, in a function 
called 'define_constraint_remote_table'. Can I use @compiles to override 
that function?

Right now I have manually added the following to 
dialects.mysql.base.MySQLDDLCompiler:

def define_constraint_remote_table(self, constraint, table, preparer):
Format the remote table clause of a CREATE CONSTRAINT clause.
   If using InnoDB, tables without manually-provided schemas will
   be formatted using the default connection schema when rendered
   in foreign key statements. This is because InnoDB (or perhaps 
   mysql?) will interpret references without schemas as being in the
   same schema as the table being created/altered 
   
engine_key = '%s_engine' % self.dialect.name
is_innodb = engine_key in table.kwargs and \
table.kwargs[engine_key].lower() == 'innodb'

if is_innodb and table.schema is None:
default_schema = table.bind.url.database
constraint_schema = constraint.columns[0].table.schema
if constraint_schema not in (default_schema, None):
 if the constraint schema is not the default, we need to 
add a schema before formatting the table 
table.schema = default_schema
value = preparer.format_table(table)
table.schema = None
return value
return preparer.format_table(table)


This does exactly what I want it to, and ensures that in any cases where 
the referenced keys are in a different schema than the active table, the 
keys are prefixed by the schema.

Is there a way to 'inject' this into the MySQLDDLCompiler?

Would this version of the formatting function not be more appropriate than 
the current, as the current is unable to handle a simple 2 model relation 
when they are in different schemas?

On Wednesday, August 21, 2013 2:52:41 PM UTC-7, Michael Bayer wrote:


 On Aug 21, 2013, at 5:37 PM, Gerald Thibault 
 diesel...@gmail.comjavascript: 
 wrote:

 To make it sqlalchemy specific, how do i cause generated CREATE statements 
 to use absolute schema.table names for foreign key references?


 you either need to specify schema in your referenced Table def, or you'd 
 otherwise have to intercept the AddConstraint construct using @compiles to 
 inject the schema name that you'd want there.



 I realized the reason MyISAM had no issue with it was because it ignores 
 all those lines, so even if they were wrong (which they seem to be), it 
 wouldn't care.

 Here is the relevant output from SHOW ENGINE STATUS INNODB:

 
 LATEST FOREIGN KEY ERROR
 
 130821 13:22:18 Error in foreign key constraint of table 
 test2/registrations:
 FOREIGN KEY(user_id) REFERENCES user_vars (id)
 )ENGINE=InnoDB:
 Cannot resolve table name close to:
  (id)
 )ENGINE=InnoDB

 It seems the schema is mandatory when operating cross-schema.

 Is there a way to get this behavior from sqlalchemy?

 If MyISAM ignores the FK declarations, and InnoDB requires a schema in 
 order to have cross-schema fk references, it seems like using schema.table 
 format would fix this.

 On Wednesday, August 21, 2013 1:57:07 PM UTC-7, Michael Bayer wrote:

 you might try asking this as a generic MySQL question on stackoverflow, I 
 don't really know how MySQL does cross-schema work.  my rough understanding 
 was not much.




 On Aug 21, 2013, at 4:17 PM, Gerald Thibault diesel...@gmail.com wrote:

 I have a User class, and a Registration class with a FK to User.id.

 When I try to create these on a db using InnoDB as default, I get this 
 error:

 sqlalchemy.exc.OperationalError: (OperationalError) (1005, Can't create 
 table 'test2.registrations' (errno: 150)) '\nCREATE TABLE 
 test2.registrations (\n\tid INTEGER NOT NULL AUTO_INCREMENT, \n\tuser_id 
 INTEGER, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(user_id) REFERENCES 
 user_vars (id)\n)\n\n' ()

 If i copy this query and try it manually via MySQL Workbench, it still 
 fails. 

 If I prepend the default schema to the table (user_vars - 
 'test.user_vars'), the query succeeds.

 I'm not entirely sure what is happening here. In the absence of an 
 explicit schema, I thought mysql used the active schema to handle table 
 lookups, but it looks like this isn't the case. Is it 'switching' the 
 active schema to the one hosting the new table? Also, this works perfectly 
 with MyISAM tables, so I have even less to go on.

 Any ideas? Do I need explicit schema declarations for every fk declared?

 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To 

Re: [sqlalchemy] Error 1005 (errno 150) trying to create related tables using InnoDB

2013-08-22 Thread Michael Bayer

On Aug 22, 2013, at 6:08 AM, Gerald Thibault dieselmach...@gmail.com wrote:

 I looked into the AddConstraint class, and added some debugging info and 
 found it wasn't being hit, because the fk was part of a CREATE. So I'd need 
 to use @compiles to override both of those to ensure both of them render the 
 references correctly.
 
 The single point where the magic happens is in compiler.py, in a function 
 called 'define_constraint_remote_table'. Can I use @compiles to override that 
 function?
 
 Right now I have manually added the following to 
 dialects.mysql.base.MySQLDDLCompiler:
 
 def define_constraint_remote_table(self, constraint, table, preparer):
 Format the remote table clause of a CREATE CONSTRAINT clause.
If using InnoDB, tables without manually-provided schemas will
be formatted using the default connection schema when rendered
in foreign key statements. This is because InnoDB (or perhaps 
mysql?) will interpret references without schemas as being in the
same schema as the table being created/altered 

 engine_key = '%s_engine' % self.dialect.name
 is_innodb = engine_key in table.kwargs and \
 table.kwargs[engine_key].lower() == 'innodb'
 
 if is_innodb and table.schema is None:
 default_schema = table.bind.url.database
 constraint_schema = constraint.columns[0].table.schema
 if constraint_schema not in (default_schema, None):
  if the constraint schema is not the default, we need to 
 add a schema before formatting the table 
 table.schema = default_schema
 value = preparer.format_table(table)
 table.schema = None
 return value
 return preparer.format_table(table)
 
 
 This does exactly what I want it to, and ensures that in any cases where the 
 referenced keys are in a different schema than the active table, the keys are 
 prefixed by the schema.
 
 Is there a way to 'inject' this into the MySQLDDLCompiler?

if you specify a name and use_alter=True on your ForeignKey it should use 
the AddConstraint feature, which is easier to override.

 
 Would this version of the formatting function not be more appropriate than 
 the current, as the current is unable to handle a simple 2 model relation 
 when they are in different schemas?

first I'd want to fully understand and verify exactly what's going on with 
this, if you have some definitive documentation that refers to this it would be 
helpful.   from there I'd probably still prefer to make this a table-level flag 
(I considered a dialect-level flag, but this is really part of mysql_engine's 
behavior), particularly because we prefer CREATE TABLE statements to be correct 
for the target database even in the absence of a database connection.




signature.asc
Description: Message signed with OpenPGP using GPGMail


Re: [sqlalchemy] Creating Tables from a Schema defined in YAML

2013-08-22 Thread Kevin Horn
On Wed, Aug 21, 2013 at 11:26 PM, monosij.for...@gmail.com wrote:


 Hello - Wondering if someone could please help me with this:

 I have created a schema definition file in YAML which I read into a dict.

 I am used to statically creating a table in this form:
 tableName = Table (theTableName, Metadata,
 Column(column1, String),
 Column(column2, String),
 Column(coulumn3, String)
 ...
 )

 I am trying to see if there is a way to dynamically create a table using
 the column definition in the YAML file. So it would need to iterate over
 the column names and the types.

 I tried with creating the string = 'Column(column1,
 String), Column(column2, String), Column(coulumn3, String) ...'
 by iterating over the dict keys and then calling as above - but that did
 not work.

 Just wondering if there would be another way to do this.

 I looked at mapper as well but then that is for objects.

 Thanks.

 Mono


The answer to this probably depends on exactly what your schema looks like,
but based on what you've told us so far, I would probably try to create all
the columns first, get them into a list or tuple, and then use star args
to pass them into the Table constructor.  Something like this:

columns = [Column(name, type) for name, type in
some_kind_of_iterable_generated_from_your_yaml]

table = Table(theTableName, Metadata, *columns)

though obviously that's a very rough example

--
Kevin Horn

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Creating Tables from a Schema defined in YAML

2013-08-22 Thread Monosij Dutta-Roy
Hi Kevin -

Thanks for your help. I am, however, unable to call Column on the tuple
(attrname, 'String').

I tried like this:
columns = []
for attribute in attrList:
tup = attribute, 'String'
tupC = Column(tup)   // does not work
columns.append(tup)

So Columns (tup) did not work and I also tried calling Column on the tuples
list I created in the iterator.

So my call to create a table as in:
theTable = Table (tableName, Metadata, *columns) - does not work. I also
tried w/o the column call but did not expect it to work.

So sounds like would be a 'star args' for the Column call as well but am
unable to find it.

Please let me know if I am approaching this incorrectly (I assume I am).

Also, I could generate a SQL create statement from my YAML file.

Would there be a way to use the Table command to create a table from that -
but it would defeat the purpose as if go with a different DBMS I have to
make sure the SQL is addressed? Or does sqlalchemy take care of that as
well?

If there is some documentation you could refer me to in how this dynamic
generation is implemented will be great.

Also, since it is a tuple I assume I can put in PK / FK information as well.

And I can help create some of this documentation if it does not exist. Its
a great library, very helpful, just trying to find some flexibility.

Thank you for your help.

Mono





On Thu, Aug 22, 2013 at 11:18 AM, Kevin Horn kevin.h...@gmail.com wrote:

 On Wed, Aug 21, 2013 at 11:26 PM, monosij.for...@gmail.com wrote:


 Hello - Wondering if someone could please help me with this:

 I have created a schema definition file in YAML which I read into a dict.

 I am used to statically creating a table in this form:
 tableName = Table (theTableName, Metadata,
 Column(column1, String),
  Column(column2, String),
 Column(coulumn3, String)
 ...
 )

 I am trying to see if there is a way to dynamically create a table using
 the column definition in the YAML file. So it would need to iterate over
 the column names and the types.

 I tried with creating the string = 'Column(column1,
 String), Column(column2, String), Column(coulumn3, String) ...'
 by iterating over the dict keys and then calling as above - but that did
 not work.

 Just wondering if there would be another way to do this.

 I looked at mapper as well but then that is for objects.

 Thanks.

 Mono


 The answer to this probably depends on exactly what your schema looks
 like, but based on what you've told us so far, I would probably try to
 create all the columns first, get them into a list or tuple, and then use
 star args to pass them into the Table constructor.  Something like this:

 columns = [Column(name, type) for name, type in
 some_kind_of_iterable_generated_from_your_yaml]

 table = Table(theTableName, Metadata, *columns)

 though obviously that's a very rough example

 --
 Kevin Horn

 --
 You received this message because you are subscribed to a topic in the
 Google Groups sqlalchemy group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/sqlalchemy/2eY6URGd2mY/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 sqlalchemy+unsubscr...@googlegroups.com.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


[sqlalchemy] Feedback appreciated

2013-08-22 Thread Konsta Vesterinen


Hi all,


First I want to say how much I appreciate SQLAlchemy. I think it is by far 
the best ORM available for any language. Thank you Mike for this wonderful 
piece of software. I can’t imagine how many countless hours you’ve put into 
this.

From the day I started coding I’ve always been enthusiastic about 
databases. 2007 I created Doctrine, which is now the most popular ORM for 
PHP. Over the years I’ve switched to Python (I could’ve switched to Ruby, 
but didn’t like Rails’ ORM at all). Now I’m the CEO of a company called 
Fast Monkeys. We employ 15 people currently and develop solely with Python, 
SQLAlchemy and Flask. One of the key principles of our company is to 
contribute to our chosen open source technologies as much as possible. 
There are couple of interesting projects I would like to hear some feedback:


SQLAlchemy-Utils

https://github.com/kvesteri/sqlalchemy-utils 

Provides number of things for SQLAlchemy. Some highlights:

   - 
   
   Batch fetching utilities (experimental at the moment)
   - 
  
  We had a real life scenario were join loading, lazy loading and 
  subquery loading were all too slow. 
  - 
  
  I used this 
  https://groups.google.com/forum/#!topic/sqlalchemy/vHQlm0U5f2k as an 
  inspiration. I agree this is a bottomless hole but I’m nevertheless 
willing 
  to try to make something useful for SQLAlchemy users. :)
  - 
   
   Number of new datatypes
   


SQLAlchemy-Continuum

https://github.com/kvesteri/sqlalchemy-continuum

Hibernate Envers style versioning for SQLAlchemy declarative models.


WTForms-Alchemy

https://github.com/kvesteri/wtforms-alchemy

Easily create WTForms forms from SQLAlchemy declarative models.



The documentation is pretty poor on first two projects. I will add more 
docs in the following weeks.

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Modification tracking

2013-08-22 Thread Hans-Peter Jansen
Dear Michael,

thanks for the detailed response.

On Mittwoch, 21. August 2013 16:55:18 Michael Bayer wrote:
 On Aug 21, 2013, at 12:40 PM, Hans-Peter Jansen h...@urpla.net wrote:
  Hi,
  
  being new to SQLAlchemy, I try to get my way through it.
  
  In an application, I have rather elaborate needs to track changes.
  
  I've defined 3 classes with declarative, where the main class has
  relationships with two auxiliary classes, that refer to the main class
  with foreign references. All pretty basic stuff.
  
  Now I need to track all modifications to all fields, including the
  relationship list objects.
  
  What is the best way to accomplish this task with SQLAlchemy?
  
  Is there some boilerplate available to support this, or do I have to carry
  around two objects and compare them item by item?
 you can intercept changes on attributes using the attribute event system: 
 http://docs.sqlalchemy.org/en/rel_0_8/orm/events.html#attribute-events
 
 otherwise you can get at the changes on an attribute after the fact (but
 before a flush) using the history interface:
 http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html?highlight=history#sq
 lalchemy.orm.attributes.History

Hmm, it looks like that needs to be applied on every column attribute..

 you can get a list of all attributes mapped using mapper.attrs:
 http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=mapp
 er.attrs#sqlalchemy.orm.mapper.Mapper.attrs

from here. Since I need to track all 'net' changes, that's rather unpractical.

I've changed my code to cope with best practices hopefully (from what I can 
extract from the overwhelming docs).

That is: just change instance attributes in place, and check for dirtiness 
later on, with session.is_modified(obj, passive = True). I've chosen this 
interface, because the fact of *really* being modified is essential here.

This scheme would do just fine, but doesn't work as expected.

See attached code. Depending on modification state of parent (line 51), the 
modification state of the child is detected (parent changed) or not (parent 
unchanged).

In my real code, it's the other way around, modifications to relations are 
detected (as I iterate through all of them), but changes to the parent 
aren't, although the correct SQL UPDATE code is executed after commit(). Since 
it isn't detected correctly, my app falls flat on its nose..

Do you have any idea on this one?

Cheers,
Pete

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

ERR = 1

class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable = False, index = True)
children = relationship('Child', backref = 'parent',
single_parent = True, # lazy = 'joined',
cascade = 'all, delete-orphan')


def __repr__(self):
cl = [repr(c) for c in self.children]
return 'Parent(%r, children: %s)' % (self.name, ', '.join(cl))

class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable = False, index = True)
parent_id = Column(Integer, ForeignKey('parent.id'), nullable = False)

def __repr__(self):
return 'Child(%r)' % (self.name)

if __name__ == '__main__':
engine = create_engine('sqlite://', echo = True)
Base.metadata.create_all(engine)
session = sessionmaker(engine, expire_on_commit=False)()

def pr(obj, exp, msg):
res = session.is_modified(obj, passive = True)
print msg + ',', 'expected: %s,' % exp, 'outcome: %s,' % res, exp == res and 'okay' or 'FAILED'

p = Parent(name = 'pa')
c1 = Child(name = 'li')
p.children.append(c1)

print 'Starting with:', p

session.add(p)
session.commit()

pr(p, False, 'initial session committed')

if ERR:
pr(p, False, 'parent not renamed')
else:
p.name = 'po'
pr(p, True, 'parent renamed to po')

c1.name = 'lo'
pr(c1, True, 'child renamed to lo, testing child')
pr(p, True, 'child renamed to lo, testing parent')

session.commit()




Re: [sqlalchemy] Modification tracking

2013-08-22 Thread Hans-Peter Jansen
On Donnerstag, 22. August 2013 23:58:17 Hans-Peter Jansen wrote:
 Dear Michael,
 
Pardon, I'm using 0.8.2 ATM.
 
 Cheers,
 Pete

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Modification tracking

2013-08-22 Thread Michael Bayer

On Aug 22, 2013, at 5:58 PM, Hans-Peter Jansen h...@urpla.net wrote:

 Dear Michael,
 
 
 Hmm, it looks like that needs to be applied on every column attribute..

 
 you can get a list of all attributes mapped using mapper.attrs:
 http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=mapp
 er.attrs#sqlalchemy.orm.mapper.Mapper.attrs
 
 from here. Since I need to track all 'net' changes, that's rather unpractical.

if you're just looking for dirty you can look at session.dirty itself, such 
as in a before_flush() handlernot sure what the specific scenario is.


 That is: just change instance attributes in place, and check for dirtiness 
 later on, with session.is_modified(obj, passive = True). I've chosen this 
 interface, because the fact of *really* being modified is essential here.
 
 This scheme would do just fine, but doesn't work as expected.
 
 See attached code. Depending on modification state of parent (line 51), the 
 modification state of the child is detected (parent changed) or not (parent 
 unchanged).

it looks like this code makes a change to p.children[0].name, and then expects 
that session.is_modified(p) would be True.is_modified() is per-object, so 
modifying Child means that just Child is modified, Parent hasn't changed at 
all.   If you want to make an is_modified() that recurses through object 
graphs, you'd need to traverse down yourself through related attributes.   I 
can show you what that looks like if this is what you want.

 In my real code, it's the other way around, modifications to relations are 
 detected (as I iterate through all of them), but changes to the parent 
 aren't, although the correct SQL UPDATE code is executed after commit(). 
 Since 
 it isn't detected correctly, my app falls flat on its nose..

well if you change Child.name, the only UPDATE needed is on the child table.  
the parent table doesn't require an UPDATE in this case which is why 
session.is_modified() returns False.


signature.asc
Description: Message signed with OpenPGP using GPGMail


Re: [sqlalchemy] Feedback appreciated

2013-08-22 Thread Michael Bayer

On Aug 22, 2013, at 3:37 PM, Konsta Vesterinen konsta.vesteri...@gmail.com 
wrote:

 Hi all,
 
 First I want to say how much I appreciate SQLAlchemy. I think it is by far 
 the best ORM available for any language. Thank you Mike for this wonderful 
 piece of software. I can’t imagine how many countless hours you’ve put into 
 this.
 
 From the day I started coding I’ve always been enthusiastic about databases. 
 2007 I created Doctrine, which is now the most popular ORM for PHP.


wow that is quite a compliment, I of course have heard of Doctrine and met many 
PHP users who use it extensively.   This is really amazing that you're A. using 
Python now B. using SQLAlchemy and C. writing full blown software for it, wow !

  Over the years I’ve switched to Python (I could’ve switched to Ruby, but 
 didn’t like Rails’ ORM at all). Now I’m the CEO of a company called Fast 
 Monkeys. We employ 15 people currently and develop solely with Python, 
 SQLAlchemy and Flask. One of the key principles of our company is to 
 contribute to our chosen open source technologies as much as possible. There 
 are couple of interesting projects I would like to hear some feedback:
 
 
 SQLAlchemy-Utils
 https://github.com/kvesteri/sqlalchemy-utils 
 
 Provides number of things for SQLAlchemy. Some highlights:
 Batch fetching utilities (experimental at the moment)
 We had a real life scenario were join loading, lazy loading and subquery 
 loading were all too slow. 
 I used this https://groups.google.com/forum/#!topic/sqlalchemy/vHQlm0U5f2k as 
 an inspiration. I agree this is a bottomless hole but I’m nevertheless 
 willing to try to make something useful for SQLAlchemy users. :)
 Number of new datatypes
 
 
 SQLAlchemy-Continuum
 https://github.com/kvesteri/sqlalchemy-continuum
 
 Hibernate Envers style versioning for SQLAlchemy declarative models.
 
 
 WTForms-Alchemy
 https://github.com/kvesteri/wtforms-alchemy
 
 Easily create WTForms forms from SQLAlchemy declarative models.

These are all really interesting projects and I had a lot of thoughts looking 
at all of them just briefly.   I also wonder at what points within here 
should/can some of this be part of SQLA itself, or not.  Here's my notes:

wtforms:

1. in all cases, use inspect(cls) to get at a Mapper.  if on 0.7, use 
class_mapper(cls).   but it would be great if you could target 0.8 and up as a 
lot of functions were added for exactly these kinds of use cases (See 
http://docs.sqlalchemy.org/en/rel_0_8/faq.html#how-do-i-get-a-list-of-all-columns-relationships-mapped-attributes-etc-given-a-mapped-class)

2. ClassManager.values() is not terrible, but again isn't super public.  you 
can use mapper.attrs as well as mapper.column_attrs and others as of 0.8.

versioning:

1. wow this is really ambitious.

2. unit_of_work.py: you can tell if a statement is an INSERT/DELETE usually by 
looking at context.isinsert/context.isdelete, and also the table name 
you can get from context.statement.table (something like that).  Similar things 
can be done where I see you're regexping the DELETE
later on.   Digging into the string is fine but once you're targeting the broad 
spectrum of scenarios, like users that are adding SQL comments and such to 
their SQL, backends that don't actually use SQL, you want to stick with 
inspecting the expression trees as much as possible.

3. make schema object names configurable, i.e. transaction_id

4. This code looks great but I'd still be scared to use it, because versioning 
is such a particular thing, not to mention
interactions with other schema complexities.But I don't say that to be 
discouraging, just to state how non-trivial a problem 
this is.   When i do versioning for real, there's always weird quirks and 
things 
specific to the app, which are easier to hardcode in my versioning code rather 
than having to configure a 3rd party library to do it.
it's why i kept it as just an example in SQLA itself, it's a huge job...   
but if you can make this extension successful,
that'll be very impressive.   In the docs it would be nice if I could see 
immediately what happens to the SQL schema when I use this.

sqlalchemy_utils:

1. have coercion_listener configure itself?   coercion_listener.configure().  
since it's global usually,
and you could always pass a target base class to configure() as an option.

2. ScalarListType vs. Postgresql ARRAY ?   same/better?  should SLT use ARRAY 
on a PG backend ?

3. operators for types!   I see these are mostly string storage but you can 
start adding special operations as
needed using TypeEngine.Comparator: 
http://docs.sqlalchemy.org/en/rel_0_8/core/types.html#types-operators  e.g. 
look at all the operations that pg.ARRAY has (contains, indexed access, 
concatenation, etc.). then you can make all these types *really* slick.

4a. batch_fetch - h.  I see the idea is avoid JOIN by just 
feeding the keys into an IN (caveat there, IN works well for small lists, but 
less so for large