[Zope3-checkins] CVS: Zope3/src/zope/app/content - i18nfile.py:1.1.2.1 configure.zcml:1.1.2.3 i18nimage.py:1.1.2.4 sql.py:1.1.2.5
Jim Fulton
jim@zope.com
Tue, 24 Dec 2002 11:26:29 -0500
Update of /cvs-repository/Zope3/src/zope/app/content
In directory cvs.zope.org:/tmp/cvs-serv4174/zope/app/content
Modified Files:
Tag: NameGeddon-branch
configure.zcml i18nimage.py sql.py
Added Files:
Tag: NameGeddon-branch
i18nfile.py
Log Message:
got zope.app.content tests passing
=== Added File Zope3/src/zope/app/content/i18nfile.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: i18nfile.py,v 1.1.2.1 2002/12/24 16:25:58 jim Exp $
"""
import persistence
from zope.app.interfaces.content.i18nfile import II18nFile
from zope.app.content.file import File
# XXX We shouldn't be dependent on Browser here! Aaaargh.
from zope.publisher.browser import FileUpload
class I18nFile(persistence.Persistent):
"""I18n aware file object. It contains a number of File objects --
one for each language.
"""
__implements__ = II18nFile
def __init__(self, data='', contentType=None, defaultLanguage='en'):
""" """
self._data = {}
self.defaultLanguage = defaultLanguage
self.setData(data, language=defaultLanguage)
if contentType is None:
self.setContentType('')
else:
self.setContentType(contentType)
def __len__(self):
return self.getSize()
def _create(self, data):
"""Create a new subobject of the appropriate type. Should be
overriden in subclasses.
"""
return File(data)
def _get(self, language):
"""Helper function -- return a subobject for a given language,
and if it does not exist, return a subobject for the default
language.
"""
file = self._data.get(language)
if not file:
file = self._data[self.defaultLanguage]
return file
def _get_or_add(self, language, data=''):
"""Helper function -- return a subobject for a given language,
and if it does not exist, create and return a new subobject.
"""
if language is None:
language = self.defaultLanguage
file = self._data.get(language)
if not file:
self._data[language] = file = self._create(data)
self._p_changed = 1
return file
def setContentType(self, contentType):
'''See interface IFile'''
self._contentType = contentType
def getContentType(self):
'''See interface IFile'''
return self._contentType
contentType = property(getContentType, setContentType)
def edit(self, data, contentType=None, language=None):
'''See interface IFile'''
# XXX This seems broken to me, as setData can override the
# content type explicitly passed in.
if contentType is not None:
self.setContentType(contentType)
if hasattr(data, '__class__') and data.__class__ is FileUpload \
and not data.filename:
data = None # Ignore empty files
if data is not None:
self.setData(data, language)
def getData(self, language=None):
'''See interface IFile'''
return self._get(language).getData()
def setData(self, data, language=None):
'''See interface IFile'''
self._get_or_add(language).setData(data)
data = property(getData, setData)
def getSize(self, language=None):
'''See interface IFile'''
return self._get(language).getSize()
def getDefaultLanguage(self):
'See II18nAware'
return self.defaultLanguage
def setDefaultLanguage(self, language):
'See II18nAware'
if not self._data.has_key(language):
raise ValueError, \
'cannot set nonexistent language (%s) as default' % language
self.defaultLanguage = language
def getAvailableLanguages(self):
'See II18nAware'
return self._data.keys()
def removeLanguage(self, language):
'''See interface II18nFile'''
if language == self.defaultLanguage:
raise ValueError, 'cannot remove default language (%s)' % language
if self._data.has_key(language):
del self._data[language]
self._p_changed = 1
=== Zope3/src/zope/app/content/configure.zcml 1.1.2.2 => 1.1.2.3 ===
--- Zope3/src/zope/app/content/configure.zcml:1.1.2.2 Tue Dec 24 07:51:00 2002
+++ Zope3/src/zope/app/content/configure.zcml Tue Dec 24 11:25:58 2002
@@ -224,9 +224,9 @@
</content>
-<content class="zope.app.interfaces.content.18nfile.I18nFile">
+<content class="zope.app.content.18nfile.I18nFile">
<factory
- id="I18nFile"
+ id="zope.app.content.I18nFile"
permission="zope.ManageContent"
title="I18n File"
description="An Internationalized File" />
=== Zope3/src/zope/app/content/i18nimage.py 1.1.2.3 => 1.1.2.4 ===
--- Zope3/src/zope/app/content/i18nimage.py:1.1.2.3 Tue Dec 24 11:20:24 2002
+++ Zope3/src/zope/app/content/i18nimage.py Tue Dec 24 11:25:58 2002
@@ -17,7 +17,8 @@
"""
from zope.app.content.image import IImage, Image, getImageInfo
-from zope.app.interfaces.content.i18nfile import II18nFile, I18nFile
+from zope.app.interfaces.content.i18nfile import II18nFile
+from zope.app.content.i18nfile import I18nFile
from zope.app.interfaces.annotation import IAnnotatable
=== Zope3/src/zope/app/content/sql.py 1.1.2.4 => 1.1.2.5 ===
--- Zope3/src/zope/app/content/sql.py:1.1.2.4 Tue Dec 24 11:16:06 2002
+++ Zope3/src/zope/app/content/sql.py Tue Dec 24 11:25:58 2002
@@ -176,6 +176,8 @@
parmre = re.compile(r'([\000- ]*([^\000- ="]+)=([^\000- ="]+))')
qparmre = re.compile(r'([\000- ]*([^\000- ="]+)="([^"]*)")')
+valid_type = {'int':1, 'float':1, 'string':1, 'nb': 1}.has_key
+
class InvalidParameter(Exception):
pass
@@ -482,12 +484,282 @@
__call__ = render
-
# SQL compliant comparison operators
comparison_operators = { 'eq': '=', 'ne': '<>',
'lt': '<', 'le': '<=', 'lte': '<=',
'gt': '>', 'ge': '>=', 'gte': '>=' }
+
+class SQLGroup:
+ blockContinuations = 'and', 'or'
+ name = 'sqlgroup'
+ required = None
+ where = None
+
+ def __init__(self, blocks):
+ self.blocks = blocks
+ tname, args, section = blocks[0]
+ self.__name__ = "%s %s" % (tname, args)
+ args = parse_params(args, required=1, where=1)
+ if args.has_key(''):
+ args[args['']] = 1
+ if args.has_key('required'):
+ self.required = args['required']
+ if args.has_key('where'):
+ self.where = args['where']
+
+
+ def render(self, md):
+ result = []
+ for tname, args, section in self.blocks:
+ __traceback_info__ = tname
+ s = section(None, md).strip()
+ if s:
+ if result:
+ result.append(tname)
+ result.append("%s\n" % s)
+
+ if result:
+ if len(result) > 1:
+ result = "(%s)\n" %(' '.join(result))
+ else:
+ result = result[0]
+ if self.where:
+ result = "where\n" + result
+ return result
+
+ if self.required:
+ raise 'Input Error', 'Not enough input was provided!'
+
+ return ''
+
+ __call__ = render
+
+
+class SQLVar:
+ name = 'sqlvar'
+
+ # Some defaults
+ sql_delimiter = '\0'
+
+ def sql_quote__(self, v):
+ if v.find("\'") >= 0:
+ v = "''".join(v.split("\'"))
+ return "'%s'" %v
+
+ def __init__(self, args):
+ args = parse_params(args, name='', expr='', type=None, optional=1)
+
+ name, expr = name_param(args, 'sqlvar', 1)
+ if expr is None:
+ expr = name
+ else:
+ expr = expr.eval
+ self.__name__, self.expr = name, expr
+
+ self.args = args
+ if not args.has_key('type'):
+ raise ParseError, ('the type attribute is required', 'dtvar')
+
+ t = args['type']
+ if not valid_type(t):
+ raise ParseError, ('invalid type, %s' % t, 'dtvar')
+
+
+ def render(self, md):
+ name = self.__name__
+ args = self.args
+ t = args['type']
+ try:
+ expr = self.expr
+ if isinstance(expr, StringTypes):
+ v = md[expr]
+ else:
+ v = expr(md)
+ except:
+ if args.has_key('optional') and args['optional']:
+ return 'null'
+ if not isinstance(expr, StringTypes):
+ raise
+ raise ('Missing Input',
+ '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
+ # a plugin.
+ if t == 'int':
+ try:
+ if isinstance(v, StringTypes):
+ int(v)
+ else:
+ v = str(int(v))
+ except:
+ if not v and args.has_key('optional') and args['optional']:
+ return 'null'
+ raise ValueError, (
+ 'Invalid integer value for **%s**' % name)
+
+ elif t == 'float':
+ try:
+ if isinstance(v, StringTypes):
+ float(v)
+ else:
+ v = str(float(v))
+ except:
+ if not v and args.has_key('optional') and args['optional']:
+ return 'null'
+ raise ValueError, (
+ 'Invalid floating-point value for **%s**' % name)
+
+ else:
+ orig_v = v
+ v = str(v)
+ if (not v or orig_v is None) and t == 'nb':
+ if args.has_key('optional') and args['optional']:
+ return 'null'
+ else:
+ raise ValueError, (
+ 'Invalid empty string value for **%s**' % name)
+
+ v = self.sql_quote__(v)
+
+ return v
+
+ __call__ = render
+
+
+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
+
+ 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]
+ except:
+ # Okay, the first try failed, so let's try to find the default
+ arg = self._arguments[name]
+ try:
+ arg_values[name] = arg['default']
+ except:
+ # Now the argument might be optional anyways; let's check
+ try:
+ if not arg['optional']:
+ missing.append(name)
+ 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'