Author: cito
Date: Thu Jul 21 12:57:25 2016
New Revision: 878

Log:
Allow extra keys in params to query_formatted()

Modified:
   trunk/docs/contents/changelog.rst
   trunk/pg.py
   trunk/tests/test_classic_dbwrapper.py

Modified: trunk/docs/contents/changelog.rst
==============================================================================
--- trunk/docs/contents/changelog.rst   Sat Jul 16 05:36:09 2016        (r877)
+++ trunk/docs/contents/changelog.rst   Thu Jul 21 12:57:25 2016        (r878)
@@ -13,6 +13,8 @@
   old versions of PostgreSQL are not officially supported and tested any more.
 - Fixed an issue with Postgres types that have an OID >= 0x80000000 (reported
   on the mailing list by Justin Pryzby).
+- Allow extra values that are not used in the command in the parameter dict
+  passed to the query_formatted() method (as suggested by Justin Pryzby).
 - Made C extension compatible with MSVC 9 again (this was needed to compile for
   Python 2 on Windows).
 

Modified: trunk/pg.py
==============================================================================
--- trunk/pg.py Sat Jul 16 05:36:09 2016        (r877)
+++ trunk/pg.py Thu Jul 21 12:57:25 2016        (r878)
@@ -619,8 +619,20 @@
                 else:
                     for value in values:
                         append(add(value))
-            command = command % tuple(literals)
+            command %= tuple(literals)
         elif isinstance(values, dict):
+            # we want to allow extra keys in the dictionary,
+            # so we first must find the values actually used in the command
+            used_values = {}
+            literals = dict.fromkeys(values, '')
+            for key in literals:
+                del literals[key]
+                try:
+                    command % literals
+                except KeyError:
+                    used_values[key] = values[key]
+                literals[key] = ''
+            values = used_values
             if inline:
                 adapt = self.adapt_inline
                 literals = dict((key, adapt(value))
@@ -629,15 +641,14 @@
                 add = params.add
                 literals = {}
                 if types:
-                    if (not isinstance(types, dict) or
-                            len(types) < len(values)):
+                    if not isinstance(types, dict):
                         raise TypeError('The values and types do not match')
                     for key in sorted(values):
-                        literals[key] = add(values[key], types[key])
+                        literals[key] = add(values[key], types.get(key))
                 else:
                     for key in sorted(values):
                         literals[key] = add(values[key])
-            command = command % literals
+            command %= literals
         else:
             raise TypeError('The values must be passed as tuple, list or dict')
         return command, params

Modified: trunk/tests/test_classic_dbwrapper.py
==============================================================================
--- trunk/tests/test_classic_dbwrapper.py       Sat Jul 16 05:36:09 2016        
(r877)
+++ trunk/tests/test_classic_dbwrapper.py       Thu Jul 21 12:57:25 2016        
(r878)
@@ -893,10 +893,12 @@
     def testQueryFormatted(self):
         f = self.db.query_formatted
         t = True if pg.get_bool() else 't'
+        # test with tuple
         q = f("select %s::int, %s::real, %s::text, %s::bool",
               (3, 2.5, 'hello', True))
         r = q.getresult()[0]
         self.assertEqual(r, (3, 2.5, 'hello', t))
+        # test with tuple, inline
         q = f("select %s, %s, %s, %s", (3, 2.5, 'hello', True), inline=True)
         r = q.getresult()[0]
         if isinstance(r[1], Decimal):
@@ -905,6 +907,28 @@
             r[1] = float(r[1])
             r = tuple(r)
         self.assertEqual(r, (3, 2.5, 'hello', t))
+        # test with dict
+        q = f("select %(a)s::int, %(b)s::real, %(c)s::text, %(d)s::bool",
+              dict(a=3, b=2.5, c='hello', d=True))
+        r = q.getresult()[0]
+        self.assertEqual(r, (3, 2.5, 'hello', t))
+        # test with dict, inline
+        q = f("select %(a)s, %(b)s, %(c)s, %(d)s",
+              dict(a=3, b=2.5, c='hello', d=True), inline=True)
+        r = q.getresult()[0]
+        if isinstance(r[1], Decimal):
+            # Python 2.6 cannot compare float and Decimal
+            r = list(r)
+            r[1] = float(r[1])
+            r = tuple(r)
+        self.assertEqual(r, (3, 2.5, 'hello', t))
+        # test with dict and extra values
+        q = f("select %(a)s||%(b)s||%(c)s||%(d)s||'epsilon'",
+              dict(a='alpha', b='beta', c='gamma', d='delta', e='extra'))
+        r = q.getresult()[0][0]
+        self.assertEqual(r, 'alphabetagammadeltaepsilon')
+
+
 
     def testPkey(self):
         query = self.db.query
_______________________________________________
PyGreSQL mailing list
[email protected]
https://mail.vex.net/mailman/listinfo.cgi/pygresql

Reply via email to