From: Jason Pellerin Date: Sun, 5 Feb 2006 14:43:10 +0000 (+0000) Subject: Provisional fix for #51, very slightly adapted from the patch posted in the ticket... X-Git-Tag: rel_0_1_0~61 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f11c56230784d523c8eb04632080c037ed0e5c1;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Provisional fix for #51, very slightly adapted from the patch posted in the ticket. Tests added to verify fix. --- diff --git a/lib/sqlalchemy/ext/proxy.py b/lib/sqlalchemy/ext/proxy.py index ae5f40cfa6..6139164bf1 100644 --- a/lib/sqlalchemy/ext/proxy.py +++ b/lib/sqlalchemy/ext/proxy.py @@ -57,7 +57,9 @@ class ProxyEngine(object): # something for oid column name, and the call happens too early # to proxy, so effecticely no oids are allowed when using # proxy engine - return None + if self.storage.engine is None: + return None + return self.get_engine().oid_column_name() def columnimpl(self, column): """Proxy point: return a ProxyColumnImpl @@ -100,47 +102,37 @@ class ProxyTableImpl(sql.TableImpl): engine = property(lambda self: self._engine.engine) -class ProxyTypeEngine(object): - """Proxy type engine; defers engine access to ProxyEngine +class ProxyType(object): + """ProxyType base class; used by ProxyTypeEngine to construct proxying + types """ def __init__(self, engine, typeobj): self._engine = engine self.typeobj = typeobj - - 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, attr): + if attr.startswith('__') and attr.endswith('__'): + return object.__getattribute__(self, attr) + + engine = object.__getattribute__(self, '_engine').engine + typeobj = object.__getattribute__(self, 'typeobj') + return getattr(engine.type_descriptor(typeobj), attr) + def __repr__(self): + return '' % (object.__getattribute__(self, 'typeobj')) + +class ProxyTypeEngine(object): + """Proxy type engine; creates dynamic proxy type subclass that is instance + of actual type, but proxies engine-dependant operations through the proxy + engine. + """ + def __new__(cls, engine, typeobj): + """Create a new subclass of ProxyType and typeobj + so that internal isinstance() calls will get the expected result. + """ + if isinstance(typeobj, type): + typeclass = typeobj + else: + typeclass = typeobj.__class__ + typed = type('ProxyTypeHelper', (ProxyType, typeclass), {}) + return typed(engine, typeobj) diff --git a/test/proxy_engine.py b/test/proxy_engine.py index 7d508481e5..150752f65b 100644 --- a/test/proxy_engine.py +++ b/test/proxy_engine.py @@ -27,7 +27,6 @@ class ProxyEngineTest(PersistTest): objectstore.clear() def test_engine_connect(self): - # connect to a real engine module_engine.connect(testbase.db_uri) users.create() @@ -110,7 +109,6 @@ class ProxyEngineTest(PersistTest): def test_table_singleton_a(self): """set up for table singleton check """ - # # For this 'test', create a proxy engine instance, connect it # to a real engine, and make it do some work @@ -131,7 +129,6 @@ class ProxyEngineTest(PersistTest): """check that a table on a 2nd proxy engine instance gets 2nd table instance """ - # # Now create a new proxy engine instance and attach the same # table as the first test. This should result in 2 table instances, @@ -163,7 +160,7 @@ class ProxyEngineTest(PersistTest): return 'a' def type_descriptor(self, typeobj): - if typeobj == type(1): + if typeobj == types.Integer: return TypeEngineX2() else: return TypeEngineSTR() @@ -193,19 +190,65 @@ class ProxyEngineTest(PersistTest): engine = ProxyEngine() engine.storage.engine = EngineA() - a = engine.type_descriptor(type(1)) + a = engine.type_descriptor(sqltypes.Integer) assert a.convert_bind_param(12, engine) == 24 assert a.convert_bind_param([1,2,3], engine) == [1, 2, 3, 1, 2, 3] - a2 = engine.type_descriptor(type('hi')) + a2 = engine.type_descriptor(sqltypes.String) assert a2.convert_bind_param(12, engine) == "'12'" assert a2.convert_bind_param([1,2,3], engine) == "'[1, 2, 3]'" engine.storage.engine = EngineB() - b = engine.type_descriptor(type(1)) + b = engine.type_descriptor(sqltypes.Integer) assert b.convert_bind_param(12, engine) == 'monkey' assert b.convert_bind_param([1,2,3], engine) == 'monkey' + + def test_type_engine_autoincrement(self): + engine = ProxyEngine() + dogs = Table('dogs', engine, + Column('dog_id', Integer, primary_key=True), + Column('breed', String), + Column('name', String)) + + class Dog(object): + pass + + assign_mapper(Dog, dogs) + + engine.connect(testbase.db_uri) + dogs.create() + + spot = Dog() + spot.breed = 'beagle' + spot.name = 'Spot' + + rover = Dog() + rover.breed = 'spaniel' + rover.name = 'Rover' + + objectstore.commit() + + assert spot.dog_id > 0, "Spot did not get an id" + assert rover.dog_id != spot.dog_id + + def test_type_proxy_schema_gen(self): + from sqlalchemy.databases.postgres import PGSchemaGenerator + + engine = ProxyEngine() + lizards = Table('lizards', engine, + Column('id', Integer, primary_key=True), + Column('name', String)) + + # this doesn't really CONNECT to pg, just establishes pg as the + # actual engine so that we can determine that it gets the right + # answer + engine.connect('postgres://database=test&port=5432&host=127.0.0.1&user=scott&password=tiger') + + sg = PGSchemaGenerator(engine.proxy()) + id_spec = sg.get_column_specification(lizards.c.id) + assert id_spec == 'id SERIAL NOT NULL PRIMARY KEY' + if __name__ == "__main__": testbase.main()