]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Improve warning message
authorAlessio Bogon <youtux@gmail.com>
Sun, 1 Sep 2019 12:43:37 +0000 (14:43 +0200)
committerAlessio Bogon <youtux@gmail.com>
Sun, 1 Sep 2019 12:43:37 +0000 (14:43 +0200)
lib/sqlalchemy/ext/linter.py
test/ext/test_linter.py

index 160731745d48fcd63db64155156082afb09a4009..6a96a62f037dc2fe1cddc6110bf736c55e3a8249 100644 (file)
@@ -7,6 +7,10 @@ from sqlalchemy.sql import visitors
 from sqlalchemy.sql.expression import Select
 
 
+def _indent(text, indent):
+    return "\n".join(indent + line for line in text.split("\n"))
+
+
 def before_execute_hook(conn, clauseelement, multiparams, params):
     if isinstance(clauseelement, Select):
         lint(clauseelement)
@@ -93,14 +97,14 @@ def warn_for_unmatching_froms(query):
     # type: (Select) -> None
     froms, start_with = find_unmatching_froms(query)
     if froms:
-        util.warn(
-            'for stmt %s FROM elements %s are not joined up to FROM element "%r"'
-            % (
-                id(query),  # defeat the warnings filter
-                ", ".join('"%r"' % f for f in froms),
-                start_with,
-            )
+        template = '''Query\n{query}\nhas FROM elements:\n{froms}\nthat are not joined up to FROM element\n{start}'''
+        indent = '    '
+        message = template.format(
+            query=_indent(str(query), indent),
+            froms=_indent('\n'.join(str(from_) for from_ in froms), indent + '* '),
+            start=_indent(str(start_with), indent + '* '),
         )
+        util.warn(message)
 
 
 def lint(query):
index 763090b0913c2966659dbbec36517fdb4778e006..b8bc76f892a831a467461d975627061ea9395e9d 100644 (file)
@@ -3,9 +3,10 @@ from sqlalchemy.ext import linter
 from sqlalchemy.ext.linter import find_unmatching_froms
 from sqlalchemy.testing import fixtures, expect_warnings
 from sqlalchemy.testing.schema import Table, Column
+from sqlalchemy.testing.mock import patch
 
 
-class TestFinder(fixtures.TablesTest):
+class TestFindUnmatchingFroms(fixtures.TablesTest):
     @classmethod
     def define_tables(cls, metadata):
         Table("table_a", metadata, Column("col_a", Integer, primary_key=True))
@@ -194,18 +195,25 @@ class TestLinter(fixtures.TablesTest):
 
     def test_integration(self):
         query = (
-            select([self.a])
+            select([self.a.c.col_a])
             .where(self.b.c.col_b == 5)
         )
-        # TODO:
-        #  - make it a unit by mocking or spying "find_unmatching_froms"
-        #  - Make error string proper
-        with expect_warnings(
-            r"for stmt .* FROM elements .*table_.*col_.* "
-            r"are not joined up to FROM element .*table_.*col_.*"
-        ):
-            with testing.db.connect() as conn:
-                conn.execute(query)
+
+        def deterministic_find_unmatching_froms(query):
+            return find_unmatching_froms(query, start_with=self.a)
+
+        with patch(
+            'sqlalchemy.ext.linter.find_unmatching_froms',
+            autospec=True,
+            side_effect=deterministic_find_unmatching_froms,
+        ) as m:
+            with expect_warnings(
+                r"Query.*Select table_a\.col_a.*has FROM elements.*table_b.*"
+                r"that are not joined up to FROM element.*table_a.*"
+            ):
+                with testing.db.connect() as conn:
+                    conn.execute(query)
+            m.assert_called_once_with(query)
 
     def teardown(self):
         event.remove(testing.db, 'before_execute', linter.before_execute_hook)