[Sqlalchemy-commits] [1287] sqlalchemy/branches/schema/test: reflection, some mapper fixes...
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-04-18 19:06:19
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1287] sqlalchemy/branches/schema/test: reflection, some mapper fixes...</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1287</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-18 14:06:04 -0500 (Tue, 18 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>reflection, some mapper fixes...</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasessqlitepy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyenginebasepy">sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemymappingobjectstorepy">sqlalchemy/branches/schema/lib/sqlalchemy/mapping/objectstore.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemymappingunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/mapping/unitofwork.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschematestreflectionpy">sqlalchemy/branches/schema/test/reflection.py</a></li> <li><a href="#sqlalchemybranchesschematestrelationshipspy">sqlalchemy/branches/schema/test/relationships.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasessqlitepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -154,8 +154,8 @@ </span><span class="cx"> def push_session(self): </span><span class="cx"> raise InvalidRequestError("SQLite doesn't support nested sessions") </span><span class="cx"> </span><del>- def reflecttable(self, table): - c = self.execute("PRAGMA table_info(" + table.name + ")", {}) </del><ins>+ def reflecttable(self, connection, table): + c = connection.execute("PRAGMA table_info(" + table.name + ")", {}) </ins><span class="cx"> while True: </span><span class="cx"> row = c.fetchone() </span><span class="cx"> if row is None: </span><span class="lines">@@ -174,7 +174,7 @@ </span><span class="cx"> #print "args! " +repr(args) </span><span class="cx"> coltype = coltype(*[int(a) for a in args]) </span><span class="cx"> table.append_item(schema.Column(name, coltype, primary_key = primary_key, nullable = nullable)) </span><del>- c = self.execute("PRAGMA foreign_key_list(" + table.name + ")", {}) </del><ins>+ c = connection.execute("PRAGMA foreign_key_list(" + table.name + ")", {}) </ins><span class="cx"> while True: </span><span class="cx"> row = c.fetchone() </span><span class="cx"> if row is None: </span><span class="lines">@@ -183,10 +183,10 @@ </span><span class="cx"> #print "row! " + repr(row) </span><span class="cx"> # look up the table based on the given table's engine, not 'self', </span><span class="cx"> # since it could be a ProxyEngine </span><del>- remotetable = Table(tablename, table.engine, autoload = True) </del><ins>+ remotetable = schema.Table(tablename, table.metadata, autoload=True, autoload_with=connection) </ins><span class="cx"> table.c[localcol].append_item(schema.ForeignKey(remotetable.c[remotecol])) </span><span class="cx"> # check for UNIQUE indexes </span><del>- c = self.execute("PRAGMA index_list(" + table.name + ")", {}) </del><ins>+ c = connection.execute("PRAGMA index_list(" + table.name + ")", {}) </ins><span class="cx"> unique_indexes = [] </span><span class="cx"> while True: </span><span class="cx"> row = c.fetchone() </span><span class="lines">@@ -196,7 +196,7 @@ </span><span class="cx"> unique_indexes.append(row[1]) </span><span class="cx"> # loop thru unique indexes for one that includes the primary key </span><span class="cx"> for idx in unique_indexes: </span><del>- c = self.execute("PRAGMA index_info(" + idx + ")", {}) </del><ins>+ c = connection.execute("PRAGMA index_info(" + idx + ")", {}) </ins><span class="cx"> cols = [] </span><span class="cx"> while True: </span><span class="cx"> row = c.fetchone() </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyenginebasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -72,8 +72,8 @@ </span><span class="cx"> </span><span class="cx"> compiler is called within the context of the compile() method.""" </span><span class="cx"> raise NotImplementedError() </span><del>- def reflecttable(self, engine, table): - """given an Engine and a Table object, reflects its columns and properties from the database.""" </del><ins>+ def reflecttable(self, connection, table): + """given an Connection and a Table object, reflects its columns and properties from the database.""" </ins><span class="cx"> raise NotImplementedError() </span><span class="cx"> def dbapi(self): </span><span class="cx"> """subclasses override this method to provide the DBAPI module used to establish </span><span class="lines">@@ -211,18 +211,24 @@ </span><span class="cx"> proxy(str(compiled), parameters) </span><span class="cx"> context.post_exec(self.engine, proxy, compiled, parameters, **kwargs) </span><span class="cx"> return ResultProxy(self.engine, self, cursor, context, typemap=compiled.typemap) </span><ins>+ + # poor man's multimethod/generic function thingy </ins><span class="cx"> executors = { </span><span class="cx"> sql.ClauseElement : execute_clauseelement, </span><span class="cx"> sql.Compiled : execute_compiled, </span><span class="cx"> schema.SchemaItem:execute_default, </span><span class="cx"> str.__mro__[-2] : execute_text </span><span class="cx"> } </span><ins>+ </ins><span class="cx"> def create(self, entity, **kwargs): </span><span class="cx"> """creates a table or index given an appropriate schema object.""" </span><span class="cx"> return self.engine.create(entity, connection=self, **kwargs) </span><span class="cx"> def drop(self, entity, **kwargs): </span><span class="cx"> """drops a table or index given an appropriate schema object.""" </span><span class="cx"> return self.engine.drop(entity, connection=self, **kwargs) </span><ins>+ def reflecttable(self, table, **kwargs): + """reflects the columns in the given table from the database.""" + return self.engine.reflecttable(table, connection=self, **kwargs) </ins><span class="cx"> </span><span class="cx"> def _execute_raw(self, statement, parameters=None, cursor=None, echo=None, context=None, **kwargs): </span><span class="cx"> if cursor is None: </span><span class="lines">@@ -360,9 +366,17 @@ </span><span class="cx"> def connect(self, **kwargs): </span><span class="cx"> return Connection(self, **kwargs) </span><span class="cx"> </span><del>- def reflecttable(self, table): </del><ins>+ def reflecttable(self, table, connection=None): </ins><span class="cx"> """given a Table object, reflects its columns and properties from the database.""" </span><del>- self.dialect.reflecttable(self, table) </del><ins>+ if connection is None: + conn = self.connect() + else: + conn = connection + try: + self.dialect.reflecttable(conn, table) + finally: + if connection is None: + conn.close() </ins><span class="cx"> </span><span class="cx"> def raw_connection(self): </span><span class="cx"> """returns a DBAPI connection.""" </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/mapping/objectstore.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/mapping/objectstore.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/lib/sqlalchemy/mapping/objectstore.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -185,8 +185,19 @@ </span><span class="cx"> for o in obj: </span><span class="cx"> self._bind_to(o) </span><span class="cx"> self.uow.register_clean(o) </span><del>- </del><ins>+ + def add(self, *obj): + """given some objects, if they have no identity they will be registered as new in this session. + if they have an identity, its verified that they are already part of this session.""" + for o in obj: + if hasattr(o, '_instance_key'): + if not self.uow.has_key(o._instance_key): + raise InvalidRequestError("Instance '%s' is not bound to this Session" % repr(o)) + else: + self.register_new(o) + </ins><span class="cx"> def register_new(self, *obj): </span><ins>+ """registers the given objects as "new" and binds them to this session.""" </ins><span class="cx"> for o in obj: </span><span class="cx"> self._bind_to(o) </span><span class="cx"> self.uow.register_new(o) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemymappingunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/mapping/unitofwork.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/mapping/unitofwork.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/lib/sqlalchemy/mapping/unitofwork.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -42,7 +42,12 @@ </span><span class="cx"> attributes.ListElement.__init__(self, obj, key, data=data, **kwargs) </span><span class="cx"> self.deleteremoved = deleteremoved </span><span class="cx"> def list_value_changed(self, obj, key, item, listval, isdelete): </span><del>- sess = get_session(obj) </del><ins>+ sess = get_session(obj, raiseerror=True) + if sess is None: + return + # add the child item to this session. if its already got an identity then its + # expected to be there already. + sess.add(item) </ins><span class="cx"> if not isdelete and sess.deleted.contains(item): </span><span class="cx"> #raise InvalidRequestError("re-inserting a deleted value into a list") </span><span class="cx"> del sess.deleted[item] </span><span class="lines">@@ -61,10 +66,12 @@ </span><span class="cx"> attributes.AttributeManager.__init__(self) </span><span class="cx"> </span><span class="cx"> def value_changed(self, obj, key, value): </span><del>- if hasattr(obj, '_instance_key'): - get_session(obj).register_dirty(obj) - else: - get_session(obj).register_new(obj) </del><ins>+ sess = get_session(obj, raiseerror=False) + if sess is not None: + if hasattr(obj, '_instance_key'): + sess.register_dirty(obj) + else: + sess.register_new(obj) </ins><span class="cx"> </span><span class="cx"> def create_prop(self, class_, key, uselist, callable_, **kwargs): </span><span class="cx"> return UOWProperty(class_, self, key, uselist, callable_, **kwargs) </span><span class="lines">@@ -174,6 +181,8 @@ </span><span class="cx"> self.attributes.commit(obj) </span><span class="cx"> </span><span class="cx"> def register_new(self, obj): </span><ins>+ if hasattr(obj, '_instance_key'): + raise InvalidRequestError("Object '%s' already has an identity - it cant be registered as new" % repr(obj)) </ins><span class="cx"> if not self.new.contains(obj): </span><span class="cx"> self.new.append(obj) </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -63,6 +63,7 @@ </span><span class="cx"> name = str(name) # in case of incoming unicode </span><span class="cx"> schema = kwargs.get('schema', None) </span><span class="cx"> autoload = kwargs.pop('autoload', False) </span><ins>+ autoload_with = kwargs.pop('autoload_with', False) </ins><span class="cx"> redefine = kwargs.pop('redefine', False) </span><span class="cx"> mustexist = kwargs.pop('mustexist', False) </span><span class="cx"> useexisting = kwargs.pop('useexisting', False) </span><span class="lines">@@ -83,7 +84,10 @@ </span><span class="cx"> # we do it after the table is in the singleton dictionary to support </span><span class="cx"> # circular foreign keys </span><span class="cx"> if autoload: </span><del>- metadata.engine.reflecttable(table) </del><ins>+ if autoload_with: + autoload_with.reflecttable(table) + else: + metadata.engine.reflecttable(table) </ins><span class="cx"> # initialize all the column, etc. objects. done after </span><span class="cx"> # reflection to allow user-overrides </span><span class="cx"> table._init_items(*args) </span></span></pre></div> <a id="sqlalchemybranchesschematestreflectionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/reflection.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/reflection.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/test/reflection.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -1,8 +1,6 @@ </span><span class="cx"> </span><span class="cx"> import sqlalchemy.ansisql as ansisql </span><span class="cx"> import sqlalchemy.databases.postgres as postgres </span><del>-import sqlalchemy.databases.oracle as oracle -import sqlalchemy.databases.sqlite as sqllite </del><span class="cx"> </span><span class="cx"> from sqlalchemy import * </span><span class="cx"> </span><span class="lines">@@ -14,7 +12,7 @@ </span><span class="cx"> def testbasic(self): </span><span class="cx"> # really trip it up with a circular reference </span><span class="cx"> </span><del>- use_function_defaults = testbase.db.engine.__module__.endswith('postgres') or testbase.db.engine.__module__.endswith('oracle') </del><ins>+ use_function_defaults = testbase.db.engine.name == 'postgres' or testbase.db.engine.name == 'oracle' </ins><span class="cx"> </span><span class="cx"> use_string_defaults = use_function_defaults or testbase.db.engine.__module__.endswith('sqlite') </span><span class="cx"> </span><span class="lines">@@ -123,9 +121,10 @@ </span><span class="cx"> table.drop() </span><span class="cx"> </span><span class="cx"> def testtoengine(self): </span><del>- db = ansisql.engine() </del><ins>+ meta = MetaData('md1') + meta2 = MetaData('md2') </ins><span class="cx"> </span><del>- table = Table('mytable', db, </del><ins>+ table = Table('mytable', meta, </ins><span class="cx"> Column('myid', Integer, key = 'id'), </span><span class="cx"> Column('name', String, key = 'name', nullable=False), </span><span class="cx"> Column('description', String, key = 'description'), </span><span class="lines">@@ -133,14 +132,14 @@ </span><span class="cx"> </span><span class="cx"> print repr(table) </span><span class="cx"> </span><del>- pgdb = postgres.engine({}) </del><ins>+ table2 = table.tometadata(meta2) </ins><span class="cx"> </span><del>- pgtable = table.toengine(pgdb) </del><ins>+ print repr(table2) </ins><span class="cx"> </span><del>- print repr(pgtable) - assert pgtable.c.id.nullable - assert not pgtable.c.name.nullable - assert pgtable.c.description.nullable </del><ins>+ assert table is not table2 + assert table2.c.id.nullable + assert not table2.c.name.nullable + assert table2.c.description.nullable </ins><span class="cx"> </span><span class="cx"> def testoverride(self): </span><span class="cx"> table = Table( </span></span></pre></div> <a id="sqlalchemybranchesschematestrelationshipspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/relationships.py (1286 => 1287)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/relationships.py 2006-04-18 18:35:39 UTC (rev 1286) +++ sqlalchemy/branches/schema/test/relationships.py 2006-04-18 19:06:04 UTC (rev 1287) </span><span class="lines">@@ -70,12 +70,12 @@ </span><span class="cx"> global c </span><span class="cx"> a = A(); a.name = "a1" </span><span class="cx"> b = B(); b.name = "b1" </span><ins>+ session.add(a,b) </ins><span class="cx"> c = C(); c.name = "c1"; c.a_row = a </span><span class="cx"> # we must have more than one d row or it won't fail </span><span class="cx"> d1 = D(); d1.name = "d1"; d1.b_row = b; d1.c_row = c </span><span class="cx"> d2 = D(); d2.name = "d2"; d2.b_row = b; d2.c_row = c </span><span class="cx"> d3 = D(); d3.name = "d3"; d3.b_row = b; d3.c_row = c </span><del>- session.register_new(a,b,c,d1,d2,d3) </del><span class="cx"> </span><span class="cx"> def tearDown(self): </span><span class="cx"> conn = session.connect() </span></span></pre> </div> </div> </body> </html> |