[Zope3-checkins] CVS: Zope3/src/zope/app/content - sql.py:1.7

Stephan Richter srichter@cosmos.phy.tufts.edu
Wed, 11 Jun 2003 09:48:28 -0400


Update of /cvs-repository/Zope3/src/zope/app/content
In directory cvs.zope.org:/tmp/cvs-serv23479/content

Modified Files:
	sql.py 
Log Message:
Fixed SQLScript:

- Removed doubled 'Cache' menu entry.

- I had to context-wrap connectionName (using ContextProperty), since
  ContextMethod(setConnectionName) did not work anymore.

- Caching also did not work correctly; in the __call__() method of SQLScript
  it used a lit '[]' as the marker for the default return object; for some
  reason this did not work. When I replaced the list with object(),
  everything worked just fine.

- Removed many bare excepts and therefore XXX comments

- Cleaned up the ISQLScript interface to remove old cruft from the time I did
  not feel comfortable with properties

- Fixed bug where it would not allow you to edit an SQL script unless a 'SQL
  Connections Service' was registered. 

- In the 'rdb' package, if we experience an exception during connect, we want
  to convert this exception to a DatabaseException, so that the higher-level
  machinery can catch it. Note that I had to leave the exception blank, since
  DBI implementations have their own Exception hierarchy.


=== Zope3/src/zope/app/content/sql.py 1.6 => 1.7 ===
--- Zope3/src/zope/app/content/sql.py:1.6	Sat Jun  7 02:37:23 2003
+++ Zope3/src/zope/app/content/sql.py	Wed Jun 11 09:47:57 2003
@@ -159,14 +159,14 @@
 
 from zope.interface import implements
 from zope.component import getService
-from zope.context import ContextMethod
+from zope.context import ContextMethod, ContextProperty
 
 from zope.app.cache.caching import getCacheForObj, getLocationForCache
 from zope.app.interfaces.content.file import IFileContent
-from zope.app.interfaces.content.sql import ISQLScript
-from zope.app.interfaces.annotation import IAttributeAnnotatable
+from zope.app.interfaces.content.sql import ISQLScript, MissingInput
 from zope.app.rdb import SQLCommand
 from zope.app.rdb import queryForResults
+from zope.app.traversing import objectName
 
 unparmre = re.compile(r'([\000- ]*([^\000- ="]+))')
 parmre = re.compile(r'([\000- ]*([^\000- ="]+)=([^\000- ="]+))')
@@ -326,25 +326,24 @@
                 v = md[expr]
             else:
                 v = expr(md)
-        except:
+        except (KeyError, ValueError):
             if args.has_key('optional') and args['optional']:
                 return 'null'
             if not isinstance(expr, StringTypes):
                 raise
-            raise ('Missing Input',
-                   'Missing input variable, **%s**' % name)
+            raise MissingInput, 'Missing input variable, **%s**' % name
 
-        # XXX Shrug, should these tyoes be really hard coded? What about
+        # XXX Shrug, should these types be really hard coded? What about
         # Dates and other types a DB supports; I think we should make this
         # a plugin.
+        # We might be able to reuse some of the widget conversion code. (SR)
         if t == 'int':
             try:
                 if isinstance(v, StringTypes):
                     int(v)
                 else:
                     v = str(int(v))
-                # XXX Bare except!
-            except:
+            except ValueError:
                 if not v and args.has_key('optional') and args['optional']:
                     return 'null'
                 raise ValueError, (
@@ -356,8 +355,7 @@
                     float(v)
                 else:
                     v = str(float(v))
-                # XXX Bare except!
-            except:
+            except ValueError:
                 if not v and args.has_key('optional') and args['optional']:
                     return 'null'
                 raise ValueError, (
@@ -448,10 +446,9 @@
                         int(v)
                     else:
                         v = str(int(v))
-                    # XXX Bare except!
-                except:
+                except ValueError:
                     raise ValueError, (
-                        'Invalid integer value for **%s**' % name)
+                        'Invalid integer value for **%s**' %name)
 
             elif t == 'float':
                 if not v and isinstance(v, str):
@@ -461,10 +458,9 @@
                         float(v)
                     else:
                         v = str(float(v))
-                    # XXX Bare except!
-                except:
+                except ValueError:
                     raise ValueError, (
-                        'Invalid floating-point value for **%s**' % name)
+                        'Invalid floating-point value for **%s**' %name)
             else:
                 v = str(v)
                 v = self.sql_quote__(v)
@@ -474,8 +470,7 @@
         if not vs:
             if self.optional:
                 return ''
-            raise 'Missing Input', (
-                'No input was provided for **%s**' % name)
+            raise MissingInput, 'No input was provided for **%s**' %name
 
         if len(vs) > 1:
             vs = ', '.join(map(str, vs))
@@ -576,14 +571,12 @@
                 v = md[expr]
             else:
                 v = expr(md)
-            # XXX Bare except!
-        except:
+        except (KeyError, ValueError):
             if args.has_key('optional') and args['optional']:
                 return 'null'
             if not isinstance(expr, StringTypes):
                 raise
-            raise ('Missing Input',
-                   'Missing input variable, **%s**' % name)
+            raise MissingInput, 'Missing input variable, **%s**' %name
 
         # XXX Shrug, should these tyoes be really hard coded? What about
         # Dates and other types a DB supports; I think we should make this
@@ -606,8 +599,7 @@
                     float(v)
                 else:
                     v = str(float(v))
-                # XXX Bare except!
-            except:
+            except ValueError:
                 if not v and args.has_key('optional') and args['optional']:
                     return 'null'
                 raise ValueError, (
@@ -646,16 +638,15 @@
 
 class SQLScript(SQLCommand, Persistent):
 
-    implements(ISQLScript, IFileContent, IAttributeAnnotatable)
+    implements(ISQLScript, IFileContent)
 
     def __init__(self, connectionName='', source='', arguments=''):
         self.template = SQLDTML(source)
-        self.setConnectionName(connectionName)
+        self.connectionName = connectionName
         # In our case arguments should be a string that is parsed
-        self.setArguments(arguments)
+        self.arguments = arguments
 
     def setArguments(self, arguments):
-        'See ISQLScript'
         assert isinstance(arguments, StringTypes), (
                '"arguments" argument of setArguments() must be a string'
                )
@@ -663,163 +654,29 @@
         self._arguments = parseArguments(arguments)
 
     def getArguments(self):
-        'See ISQLScript'
+        'See zope.app.interfaces.content.sql.ISQLScript'
         return self._arguments
 
     def getArgumentsString(self):
-        'See ISQLScript'
         return self._arg_string
 
-    def setSource(self, source):
-        'See ISQLScript'
-        self.template.munge(source)
-
-    def getSource(self):
-        'See ISQLScript'
-        return self.template.read_raw()
-
-    def getTemplate(self):
-        'See ISQLScript'
-        return self.template
-
-    def setConnectionName(self, name):
-        'See ISQLScript'
-        self._connectionName = name
-        cache = getCacheForObj(self)
-        location = getLocationForCache(self)
-
-        if cache and location:
-            cache.invalidate(location)
-
-    setConnectionName = ContextMethod(setConnectionName)
-
-    def getConnectionName(self):
-        'See ISQLScript'
-        return self._connectionName
-
-    def getConnection(self):
-        'See ISQLCommand'
-        connection_service = getService(self, "SQLDatabaseConnections")
-        connection = connection_service.getConnection(self.connectionName)
-        return connection
-
-    getConnection = ContextMethod(getConnection)
-
-    def __call__(self, **kw):
-        'See ISQLCommand'
-
-        # Try to resolve arguments
-        arg_values = {}
-        missing = []
-        for name in self._arguments.keys():
-            name = name.encode('UTF-8')
-            try:
-                # Try to find argument in keywords
-                arg_values[name] = kw[name]
-                # XXX Bare except!
-            except:
-                # Okay, the first try failed, so let's try to find the default
-                arg = self._arguments[name]
-                try:
-                    arg_values[name] = arg['default']
-                    # XXX Bare except!
-                except:
-                    # Now the argument might be optional anyways; let's check
-                    try:
-                        if not arg['optional']:
-                            missing.append(name)
-                        # XXX Bare except!
-                    except:
-                        missing.append(name)
-
-        try:
-            connection = self.getConnection()
-        except AttributeError:
-            raise AttributeError, (
-                "The database connection **%s** cannot be found." % (
-                self.connectionName))
-
-        if connection is None:
-            raise 'Database Error', (
-                '%s is not connected to a database' %'foo')# self.id)
-
-        query = apply(self.template, (), arg_values)
-        cache = getCacheForObj(self)
-        location = getLocationForCache(self)
-        if cache and location:
-            _marker = []
-            result = cache.query(location, {'query': query}, default=_marker)
-            if result is not _marker:
-                return result
-        result = queryForResults(connection, query)
-        if cache and location:
-            cache.set(result, location, {'query': query})
-        return result
-
-    __call__ = ContextMethod(__call__)
-
-
-    # See ISQLScript
-    arguments = property(getArgumentsString, setArguments, None,
-                         "Set the arguments that are used for the SQL Script.")
-    source = property(getSource, setSource, None,
-                      "Set the SQL template source.")
-    connectionName = property(getConnectionName, setConnectionName, None,
-                              "Connection Name for the SQL scripts.")
-
-class SQLDTML(HTML):
-    __name__ = 'SQLDTML'
-
-    commands = {}
-
-    for k, v in HTML.commands.items():
-        commands[k]=v
-
-    # add the new tags to the DTML
-    commands['sqlvar'] = SQLVar
-    commands['sqltest'] = SQLTest
-    commands['sqlgroup'] = SQLGroup
-
-
-class SQLScript(SQLCommand, Persistent):
-
-    implements(ISQLScript, IFileContent, IAttributeAnnotatable)
-
-    def __init__(self, connectionName='', source='', arguments=''):
-        self.template = SQLDTML(source)
-        self.setConnectionName(connectionName)
-        # In our case arguments should be a string that is parsed
-        self.setArguments(arguments)
-
-    def setArguments(self, arguments):
-        'See ISQLScript'
-        assert isinstance(arguments, StringTypes), \
-               '"arguments" argument of setArguments() must be a string'
-        self._arg_string = arguments
-        self._arguments = parseArguments(arguments)
-
-    def getArguments(self):
-        'See ISQLScript'
-        return self._arguments
-
-    def getArgumentsString(self):
-        'See ISQLScript'
-        return self._arg_string
+    # See zope.app.interfaces.content.sql.ISQLScript
+    arguments = property(getArgumentsString, setArguments)
 
     def setSource(self, source):
-        'See ISQLScript'
         self.template.munge(source)
 
     def getSource(self):
-        'See ISQLScript'
         return self.template.read_raw()
 
+    # See zope.app.interfaces.content.sql.ISQLScript
+    source = property(getSource, setSource)
+
     def getTemplate(self):
-        'See ISQLScript'
+        'See zope.app.interfaces.content.sql.ISQLScript'
         return self.template
 
-    def setConnectionName(self, name):
-        'See ISQLScript'
+    def _setConnectionName(self, name):
         self._connectionName = name
         cache = getCacheForObj(self)
         location = getLocationForCache(self)
@@ -827,22 +684,23 @@
         if cache and location:
             cache.invalidate(location)
 
-    setConnectionName = ContextMethod(setConnectionName)
-
-    def getConnectionName(self):
-        'See ISQLScript'
+    def _getConnectionName(self):
         return self._connectionName
 
     def getConnection(self):
-        'See ISQLCommand'
         connection_service = getService(self, "SQLDatabaseConnections")
         connection = connection_service.getConnection(self.connectionName)
         return connection
 
     getConnection = ContextMethod(getConnection)
 
+    # See zope.app.interfaces.content.sql.ISQLScript
+    # We need to preserve the context for connectionName, so we make it
+    # a ContextProperty instead of a property
+    connectionName = ContextProperty(_getConnectionName, _setConnectionName)
+
     def __call__(self, **kw):
-        'See ISQLCommand'
+        'See zope.app.interfaces.rdb'
 
         # Try to resolve arguments
         arg_values = {}
@@ -852,38 +710,31 @@
             try:
                 # Try to find argument in keywords
                 arg_values[name] = kw[name]
-                # XXX Bare Except!
-            except:
+            except KeyError:
                 # Okay, the first try failed, so let's try to find the default
                 arg = self._arguments[name]
                 try:
                     arg_values[name] = arg['default']
-                    # XXX Bare except!
-                except:
+                except KeyError:
                     # Now the argument might be optional anyways; let's check
                     try:
                         if not arg['optional']:
                             missing.append(name)
-                        # XXX Bare except!
-                    except:
+                    except KeyError:
                         missing.append(name)
 
         try:
             connection = self.getConnection()
-        except AttributeError:
+        except KeyError:
             raise AttributeError, (
-                "The database connection **%s** cannot be found." % (
+                "The database connection '%s' cannot be found." % (
                 self.connectionName))
 
-        if connection is None:
-            raise 'Database Error', (
-                '%s is not connected to a database' %'foo')# self.id)
-
         query = apply(self.template, (), arg_values)
         cache = getCacheForObj(self)
         location = getLocationForCache(self)
         if cache and location:
-            _marker = []
+            _marker = object()
             result = cache.query(location, {'query': query}, default=_marker)
             if result is not _marker:
                 return result
@@ -893,15 +744,6 @@
         return result
 
     __call__ = ContextMethod(__call__)
-
-
-    # See ISQLScript
-    arguments = property(getArgumentsString, setArguments, None,
-                         "Set the arguments that are used for the SQL Script.")
-    source = property(getSource, setSource, None,
-                      "Set the SQL template source.")
-    connectionName = property(getConnectionName, setConnectionName, None,
-                              "Connection Name for the SQL scripts.")
-
+    
 
 valid_type = {'int':1, 'float':1, 'string':1, 'nb': 1}.has_key