Mike Bayer avatar Mike Bayer committed a3f2f73

- fix the fixture here that wasn't creating consistently
- rewrite --dropfirst to be more industrial strength, includes views
- fix order_by="foreign_key" to maintain the same ordering as
metadata.sorted_tables. Not ideal that this was the other way throughout
0.7 but this is still a little-used method, in contrast to metadata.sorted_tables.

Comments (0)

Files changed (7)

     where specific capabilities and features can
     be enabled or disabled for testing.
+  - [bug] The Inspector.get_table_names()
+    order_by="foreign_key" feature now sorts
+    tables by dependee first, to be consistent
+    with util.sort_tables and metadata.sorted_tables.
   - [bug] Fixed bug whereby if a database restart
     affected multiple connections, each
     connection would individually invoke a new


         return []
     def get_table_names(self, schema=None, order_by=None):
-        """Return all table names in `schema`.
+        """Return all table names in referred to within a particular schema.
-        :param schema: Optional, retrieve names from a non-default schema.
+        The names are expected to be real tables only, not views.
+        Views are instead returned using the :meth:`.get_view_names`
+        method.
+        :param schema: Schema name. If ``schema`` is left at ``None``, the
+         database's default schema is
+         used, else the named schema is searched.  If the database does not
+         support named schemas, behavior is undefined if ``schema`` is not
+         passed as ``None``.
         :param order_by: Optional, may be the string "foreign_key" to sort
-                         the result on foreign key dependencies.
+         the result on foreign key dependencies.
-        This should probably not return view names or maybe it should return
-        them with an indicator t or v.
+         .. versionchanged:: 0.8 the "foreign_key" sorting sorts tables
+            in order of dependee to dependent; that is, in creation
+            order, rather than in drop order.  This is to maintain
+            consistency with similar features such as
+            :attr:`.MetaData.sorted_tables` and :func:`.util.sort_tables`.
+        .. seealso::
+            :attr:`.MetaData.sorted_tables`
         if hasattr(self.dialect, 'get_table_names'):
             tnames = self.engine.table_names(schema)
         if order_by == 'foreign_key':
-            import random
-            random.shuffle(tnames)
             tuples = []
             for tname in tnames:
                 for fkey in self.get_foreign_keys(tname, schema):
                     if tname != fkey['referred_table']:
-                        tuples.append((tname, fkey['referred_table']))
+                        tuples.append((fkey['referred_table'], tname))
             tnames = list(topological.sort(tuples, tnames))
         return tnames


     def sorted_tables(self):
-        """Returns a list of ``Table`` objects sorted in order of
-        dependency.
+        """Returns a list of :class:`.Table` objects sorted in order of
+        foreign key dependency.
+        The sorting will place :class:`.Table` objects that have dependencies
+        first, before the dependencies themselves, representing the
+        order in which they can be created.   To get the order in which
+        the tables would be dropped, use the ``reversed()`` Python built-in.
+        .. seealso::
+            :meth:`.Inspector.sorted_tables`
         return sqlutil.sort_tables(self.tables.itervalues())
             for column in element.columns
+class _DropView(_CreateDropBase):
+    """Semi-public 'DROP VIEW' construct.
+    Used by the test suite for dialect-agnostic drops of views.
+    This object will eventually be part of a public "view" API.
+    """
+    __visit_name__ = "drop_view"
 class CreateColumn(visitors.Visitable):
     """Represent a :class:`.Column` as rendered in a CREATE TABLE statement,
     via the :class:`.CreateTable` construct.


     def visit_drop_table(self, drop):
         return "\nDROP TABLE " + self.preparer.format_table(drop.element)
+    def visit_drop_view(self, drop):
+        return "\nDROP VIEW " + self.preparer.format_table(drop.element)
     def _index_identifier(self, ident):
         if isinstance(ident, sql._truncated_label):
             max = self.dialect.max_index_name_length or \


 """Utility functions that build upon SQL and Schema constructs."""
 def sort_tables(tables, skip_fn=None):
-    """sort a collection of Table objects in order of their foreign-key dependency."""
+    """sort a collection of Table objects in order of
+                their foreign-key dependency."""
     tables = list(tables)
     tuples = []
     for table in tables:
-                            {'schema_visitor':True},
-                            {'foreign_key':visit_foreign_key})
+                            {'schema_visitor': True},
+                            {'foreign_key': visit_foreign_key})
             [parent, table] for parent in table._extra_dependencies


 def _prep_testing_database(options, file_config):
     from sqlalchemy.testing import engines
-    from sqlalchemy import schema
+    from sqlalchemy import schema, inspect
     # also create alt schemas etc. here?
     if options.dropfirst:
         e = engines.utf8_engine()
-        existing = e.table_names()
-        if existing:
-            print "Dropping existing tables in database: " + db_url
-            try:
-                print "Tables: %s" % ', '.join(existing)
-            except:
-                pass
-            print "Abort within 5 seconds..."
-            time.sleep(5)
-            md = schema.MetaData(e, reflect=True)
-            md.drop_all()
+        inspector = inspect(e)
+        for vname in inspector.get_view_names():
+            e.execute(schema._DropView(schema.Table(vname, schema.MetaData())))
+        for vname in inspector.get_view_names(schema="test_schema"):
+            e.execute(schema._DropView(
+                        schema.Table(vname,
+                                    schema.MetaData(), schema="test_schema")))
+        for tname in reversed(inspector.get_table_names(order_by="foreign_key")):
+            e.execute(schema.DropTable(schema.Table(tname, schema.MetaData())))
+        for tname in reversed(inspector.get_table_names(
+                                order_by="foreign_key", schema="test_schema")):
+            e.execute(schema.DropTable(
+                schema.Table(tname, schema.MetaData(), schema="test_schema")))


         cls.define_index(metadata, users)
-        cls.define_views(metadata, schema=None)
+        cls.define_views(metadata, schema)
     def define_index(cls, metadata, users):
             view_name = fullname + '_v'
             query = "CREATE VIEW %s AS SELECT * FROM %s" % (
                                 view_name, fullname)
             table_names = insp.get_table_names(schema,
             if order_by == 'foreign_key':
-                answer = ['dingalings', 'email_addresses', 'users']
+                answer = ['users', 'email_addresses', 'dingalings']
                 eq_(table_names, answer)
                 answer = ['dingalings', 'email_addresses', 'users']
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.