From 427ed1966f0f9ce13df49dcdbe43ce48333e94fa Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 19 Aug 2008 21:27:34 +0000 Subject: [PATCH] - fixed a bug in declarative test which was looking for old version of history - Added "sorted_tables" accessor to MetaData, which returns Table objects sorted in order of dependency as a list. This deprecates the MetaData.table_iterator() method. The "reverse=False" keyword argument has also been removed from util.sort_tables(); use the Python 'reversed' function to reverse the results. [ticket:1033] --- CHANGES | 10 +++++++++- lib/sqlalchemy/orm/mapper.py | 2 +- lib/sqlalchemy/schema.py | 15 ++++++++++++--- lib/sqlalchemy/sql/compiler.py | 14 +++++++++++--- lib/sqlalchemy/sql/util.py | 8 ++------ test/engine/_base.py | 4 ++-- test/engine/reflection.py | 4 ++-- test/ext/declarative.py | 4 ++-- test/orm/_base.py | 4 ++-- test/orm/_fixtures.py | 2 +- test/orm/inheritance/basic.py | 2 +- test/orm/inheritance/polymorph2.py | 2 +- test/testlib/testing.py | 2 +- 13 files changed, 47 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index 093a4b7fed..e5746ea3e7 100644 --- a/CHANGES +++ b/CHANGES @@ -69,7 +69,15 @@ CHANGES may now be a mix of lists and tuples. (Previously members were always lists.) - +- schema + - Added "sorted_tables" accessor to MetaData, which returns + Table objects sorted in order of dependency as a list. + This deprecates the MetaData.table_iterator() method. + The "reverse=False" keyword argument has also been + removed from util.sort_tables(); use the Python + 'reversed' function to reverse the results. + [ticket:1033] + - sql - Temporarily rolled back the "ORDER BY" enhancement from [ticket:1068]. This feature is on hold pending further diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 3e5f418fa1..d1713e6f99 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1314,7 +1314,7 @@ class Mapper(object): for t in mapper.tables: table_to_mapper[t] = mapper - for table in sqlutil.sort_tables(table_to_mapper.keys(), reverse=True): + for table in reversed(sqlutil.sort_tables(table_to_mapper.keys())): delete = {} for state, mapper, connection in tups: if table not in mapper._pks_by_table: diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index f6e55581f6..bb97943ebe 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -1534,14 +1534,23 @@ class MetaData(SchemaItem): # TODO: scan all other tables and remove FK _column del self.tables[table.key] + @util.deprecated('Deprecated. Use ``metadata.sorted_tables``') def table_iterator(self, reverse=True, tables=None): from sqlalchemy.sql.util import sort_tables if tables is None: tables = self.tables.values() else: tables = set(tables).intersection(self.tables.values()) - return iter(sort_tables(tables, reverse=reverse)) - + ret = sort_tables(tables) + if reverse: + ret = reversed(ret) + return iter(ret) + + @property + def sorted_tables(self): + from sqlalchemy.sql.util import sort_tables + return sort_tables(self.tables.values()) + def reflect(self, bind=None, schema=None, only=None): """Load all available table definitions from the database. @@ -1660,8 +1669,8 @@ class MetaData(SchemaItem): checkfirst Defaults to True, don't issue CREATEs for tables already present in the target database. + """ - if bind is None: bind = _bind_or_error(self) for listener in self.ddl_listeners['before-create']: diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 4a47df9417..eacbe59e10 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -20,7 +20,7 @@ is otherwise internal to SQLAlchemy. import string, re from sqlalchemy import schema, engine, util, exc -from sqlalchemy.sql import operators, functions +from sqlalchemy.sql import operators, functions, util as sql_util from sqlalchemy.sql import expression as sql RESERVED_WORDS = set([ @@ -787,7 +787,11 @@ class SchemaGenerator(DDLBase): return not self.checkfirst or not self.dialect.has_table(self.connection, table.name, schema=table.schema) def visit_metadata(self, metadata): - collection = [t for t in metadata.table_iterator(reverse=False, tables=self.tables) if self._can_create(t)] + if self.tables: + tables = self.tables + else: + tables = metadata.tables.values() + collection = [t for t in sql_util.sort_tables(tables) if self._can_create(t)] for table in collection: self.traverse_single(table) if self.dialect.supports_alter: @@ -950,7 +954,11 @@ class SchemaDropper(DDLBase): self.dialect = dialect def visit_metadata(self, metadata): - collection = [t for t in metadata.table_iterator(reverse=True, tables=self.tables) if self._can_drop(t)] + if self.tables: + tables = self.tables + else: + tables = metadata.tables.values() + collection = [t for t in reversed(sql_util.sort_tables(tables)) if self._can_drop(t)] if self.dialect.supports_alter: for alterable in self.find_alterables(collection): self.drop_foreignkey(alterable) diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index ba6b5a6056..e1636ccf90 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -4,7 +4,7 @@ from itertools import chain """Utility functions that build upon SQL and Schema constructs.""" -def sort_tables(tables, reverse=False): +def sort_tables(tables): """sort a collection of Table objects in order of their foreign-key dependency.""" tuples = [] @@ -18,11 +18,7 @@ def sort_tables(tables, reverse=False): for table in tables: visitors.traverse(table, {'schema_visitor':True}, {'foreign_key':visit_foreign_key}) - sequence = topological.sort(tuples, tables) - if reverse: - return reversed(sequence) - else: - return sequence + return topological.sort(tuples, tables) def search(clause, target): if not clause: diff --git a/test/engine/_base.py b/test/engine/_base.py index c215b2e962..3c31d378ad 100644 --- a/test/engine/_base.py +++ b/test/engine/_base.py @@ -82,7 +82,7 @@ class TablesTest(testing.TestBase): def tearDown(self): # no need to run deletes if tables are recreated on setup if self.run_define_tables != 'each' and self.run_deletes: - for table in self.metadata.table_iterator(reverse=True): + for table in reversed(self.metadata.sorted_tables): try: table.delete().execute().close() except sa.exc.DBAPIError, ex: @@ -135,7 +135,7 @@ class TablesTest(testing.TestBase): table = self.tables[table] headers[table] = data[0] rows[table] = data[1:] - for table in self.metadata.table_iterator(reverse=False): + for table in self.metadata.sorted_tables: if table not in headers: continue table.bind.execute( diff --git a/test/engine/reflection.py b/test/engine/reflection.py index 873c05aa53..5916e8cada 100644 --- a/test/engine/reflection.py +++ b/test/engine/reflection.py @@ -555,7 +555,7 @@ class CreateDropTest(TestBase): ) def test_sorter( self ): - tables = metadata.table_iterator(reverse=False) + tables = metadata.sorted_tables table_names = [t.name for t in tables] self.assert_( table_names == ['users', 'orders', 'items', 'email_addresses'] or table_names == ['users', 'email_addresses', 'orders', 'items']) @@ -657,7 +657,7 @@ class SchemaTest(TestBase): Column('col2', sa.Integer, sa.ForeignKey('someschema.table1.col1')), schema='someschema') # ensure this doesnt crash - print [t for t in metadata.table_iterator()] + print [t for t in metadata.sorted_tables] buf = StringIO.StringIO() def foo(s, p=None): buf.write(s) diff --git a/test/ext/declarative.py b/test/ext/declarative.py index c1a56ced29..b9fa57cf05 100644 --- a/test/ext/declarative.py +++ b/test/ext/declarative.py @@ -392,7 +392,7 @@ class DeclarativeTest(testing.TestBase, testing.AssertsExecutionResults): u1 = User(name='u1', a='a', b='b') eq_(u1.a, 'a') - eq_(User.a.get_history(u1), (['a'], [], [])) + eq_(User.a.get_history(u1), (['a'], (), ())) sess = create_session() sess.save(u1) sess.flush() @@ -777,7 +777,7 @@ class DeclarativeReflectionTest(testing.TestBase): Base = decl.declarative_base(testing.db) def tearDown(self): - for t in reflection_metadata.table_iterator(): + for t in reflection_metadata.sorted_tables: t.delete().execute() def tearDownAll(self): diff --git a/test/orm/_base.py b/test/orm/_base.py index 4523a32233..ae8cbd746e 100644 --- a/test/orm/_base.py +++ b/test/orm/_base.py @@ -202,7 +202,7 @@ class MappedTest(ORMTest): # no need to run deletes if tables are recreated on setup if self.run_define_tables != 'each' and self.run_deletes: - for table in self.metadata.table_iterator(reverse=True): + for table in reversed(self.metadata.sorted_tables): try: table.delete().execute().close() except sa.exc.DBAPIError, ex: @@ -264,7 +264,7 @@ class MappedTest(ORMTest): table = self.tables[table] headers[table] = data[0] rows[table] = data[1:] - for table in self.metadata.table_iterator(reverse=False): + for table in self.metadata.sorted_tables: if table not in headers: continue table.bind.execute( diff --git a/test/orm/_fixtures.py b/test/orm/_fixtures.py index 77dd510b26..efab37487e 100644 --- a/test/orm/_fixtures.py +++ b/test/orm/_fixtures.py @@ -153,7 +153,7 @@ item_keywords = fixture_table( def _load_fixtures(): - for table in fixture_metadata.table_iterator(reverse=False): + for table in fixture_metadata.sorted_tables: table.info[('fixture', 'loader')]() def run_inserts_for(table, bind=None): diff --git a/test/orm/inheritance/basic.py b/test/orm/inheritance/basic.py index e3e374eed7..b7759aaeb3 100644 --- a/test/orm/inheritance/basic.py +++ b/test/orm/inheritance/basic.py @@ -653,7 +653,7 @@ class SyncCompileTest(ORMTest): for j1 in (None, _b_table.c.a_id==_a_table.c.id, _a_table.c.id==_b_table.c.a_id): for j2 in (None, _b_table.c.a_id==_c_table.c.b_a_id, _c_table.c.b_a_id==_b_table.c.a_id): self._do_test(j1, j2) - for t in _a_table.metadata.table_iterator(reverse=True): + for t in reversed(_a_table.metadata.sorted_tables): t.delete().execute().close() def _do_test(self, j1, j2): diff --git a/test/orm/inheritance/polymorph2.py b/test/orm/inheritance/polymorph2.py index 955a6b4e93..6e9cf305e6 100644 --- a/test/orm/inheritance/polymorph2.py +++ b/test/orm/inheritance/polymorph2.py @@ -652,7 +652,7 @@ class GenerativeTest(TestBase, AssertsExecutionResults): metadata.drop_all() def tearDown(self): clear_mappers() - for t in metadata.table_iterator(reverse=True): + for t in reversed(metadata.sorted_tables): t.delete().execute() def testjointo(self): diff --git a/test/testlib/testing.py b/test/testlib/testing.py index 1c3b0f0bc8..cc77369379 100644 --- a/test/testlib/testing.py +++ b/test/testlib/testing.py @@ -911,7 +911,7 @@ class ORMTest(TestBase, AssertsExecutionResults): if not self.keep_mappers: clear_mappers() if not self.keep_data: - for t in _otest_metadata.table_iterator(reverse=True): + for t in reversed(_otest_metadata.sorted_tables): try: t.delete().execute().close() except Exception, e: -- 2.47.3