ProxyEngine seems to over-proxy types
With the table definition
users = Table('users', db_engine,
Column('user_id', Integer, primary_key = True),
Column('user_name', String(32), nullable = False),
Column('first_name', String(32), nullable = False),
Column('last_name', String(32), nullable = False),
Column('email_address', String(64), nullable = False),
Column('web_address', String(64), nullable = True),
Column('password', String(48), nullable = False)
)
where {{{db_engine}}} is an instance of {{{ProxyEngine}}}, the types are proxied ''twice''---i.e. the type of the first column is set to a {{{ProxyTypeEngine}}} whose typeobj is ''another'' {{{ProxyTypeEngine}}} which actually points at the correct type.
This breaks the schema generators, because they do tests like {{{isinstance(column.type, types.Integer)}}}, which fails because it sees a {{{ProxyTypeEngine}}} object rather than the actual type object. One obvious result of this is that the {{{create()}}} methods can't currently create {{{AUTO_INCREMENT}}} or {{{SERIAL}}} columns automatically for the primary keys of tables.
I'm currently investigating why this is happening and will post more information if/when I work it out.
-- alastair
Comments (5)
-
Account Deleted -
Account Deleted It looks to me as if the best fix would be to change the code in the database drivers so that it calls a function on the type object to determine whether the type object is of a particular kind. This should fix the problem, as the proxy can just pass it straight through to the underlying object, which will always return the right thing.
-
Account Deleted Having messed about a bit more with the Python code, I came up with the following fix:
Index: lib/sqlalchemy/ext/proxy.py =================================================================== --- lib/sqlalchemy/ext/proxy.py (revision 894) +++ lib/sqlalchemy/ext/proxy.py (working copy) @@ -100,8 +100,8 @@ engine = property(lambda self: self._engine.engine) -class ProxyTypeEngine(object): - """Proxy type engine; defers engine access to ProxyEngine +class ProxyTypeEngineProxy(object): + """Proxy type engine proxy object """ def __init__(self, engine, typeobj): self._engine = engine @@ -109,38 +109,26 @@ engine = property(lambda self: self._engine.engine) - def __getattr__(self, attr): - # NOTE: - # profiling so far indicates that caching the type_descriptor - # results is more trouble than it's worth - return getattr(self.engine.type_descriptor(self.typeobj), attr) + def __getattribute__(self, name): + if name.startswith('__') and name.endswith('__'): + return object.__getattribute__(self, name) + + engine = object.__getattribute__(self, '_engine').engine + typeobj = object.__getattribute__(self, 'typeobj') + return getattr(engine.type_descriptor(typeobj), name) + def __repr__(self): + return '<Proxy %s>' % (object.__getattribute__(self, 'typeobj')) - - - - - - - - - - - - - - - - - - - - - - - - - - - - +class ProxyTypeEngine(object): + """Proxy type engine; defers engine access to ProxyEngine + """ + def __new__(oldcls, engine, typeobj): + if isinstance(typeobj, TypeEngine): + thetype = typeobj.__class__ + else: + thetype = typeobj + + cls = type('_ProxyTypeEngineProxy_%s' % (thetype.__name__), + (ProxyTypeEngineProxy, thetype), {}) + return cls(engine, typeobj)
You may ask why I used {{{getattribute}}} rather than {{{getattr}}}; the reason is that because the new objects will have classes that derive from the base types (e.g. {{{types.Integer}}}), the {{{getattr}}} function won't get called for any of the functions that the base types implement by raising {{{NotImplementedError()}}}. If you wanted, you could use {{{getattr}}}, but then you'd have to re-implement all of those specific functions.
(I should say that I haven't been writing Python code for long, so it may be that there is a better way to do the same thing… if so, I defer to those with more experience.)
-
repo owner - assigned issue to
so is this one fixed ? feel free to close if so Jason (you should have perms for that, let me know otherwise)
-
repo owner - changed status to resolved
gonna marked this one closed in changeset:906...reopen if issues !
- Log in to comment
Interesting. I can't reproduce the double proxying (although it was definitely happening), but the actual problem is still there; because of the {{{ProxyTypeEngine}}}, {{{AUTO_INCREMENT}}} columns aren't being created.