Author: ianb
Date: 2005-08-19 03:13:46 +0000 (Fri, 19 Aug 2005)
New Revision: 921
Removed:
trunk/SQLObject/sqlobject/include/
Modified:
trunk/SQLObject/docs/DeveloperGuide.txt
trunk/SQLObject/sqlobject/__init__.py
trunk/SQLObject/sqlobject/col.py
trunk/SQLObject/sqlobject/main.py
trunk/SQLObject/sqlobject/postgres/pgconnection.py
trunk/SQLObject/sqlobject/tests/test_enum.py
trunk/SQLObject/sqlobject/tests/test_validation.py
Log:
Moved to FormEncode for the validators; see DeveloperGuide for new installation process
Modified: trunk/SQLObject/docs/DeveloperGuide.txt
===================================================================
--- trunk/SQLObject/docs/DeveloperGuide.txt 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/docs/DeveloperGuide.txt 2005-08-19 03:13:46 UTC (rev 921)
@@ -14,6 +14,25 @@
-- Ian Bicking
+Development Installation
+========================
+
+First install `FormEncode <http://formencode.org>`_::
+
+ $ svn co http://svn.colorstudy.com/FormEncode/trunk FormEncode
+ $ cd FormEncode
+ $ sudo python setup.py develop
+
+Then do the same for SQLObject::
+
+ $ svn co http://svn.colorstudy.com/trunk/SQLObject SQLObject
+ $ cd SQLObject
+ $ sudo python setup.py develop
+
+Voila! The packages are globally installed, but the files from the
+checkout were not copied into ``site-packages``. See `setuptools
+<http://peak.telecommunity.com/DevCenter/setuptools>`_ for more.
+
Style Guide
===========
Modified: trunk/SQLObject/sqlobject/__init__.py
===================================================================
--- trunk/SQLObject/sqlobject/__init__.py 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/sqlobject/__init__.py 2005-08-19 03:13:46 UTC (rev 921)
@@ -4,7 +4,6 @@
from styles import *
from joins import *
from index import *
-from include import validators
from dbconnection import connectionForURI
## Each of these imports allows the driver to install itself
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/sqlobject/col.py 2005-08-19 03:13:46 UTC (rev 921)
@@ -27,7 +27,8 @@
# Sadly the name "constraints" conflicts with many of the function
# arguments in this module, so we rename it:
import constraints as consts
-from include import validators
+from formencode import compound
+from formencode import validators
from classregistry import findClass
from converters import array_type
from util.backports import count
@@ -78,12 +79,12 @@
creationOrder = count()
-class SQLValidator(validators.All):
+class SQLValidator(compound.All):
def attemptConvert(self, value, state, validate):
- if validate is validators.toPython:
+ if validate is validators.to_python:
vlist = list(self.validators[:])
vlist.reverse()
- elif validate is validators.fromPython:
+ elif validate is validators.from_python:
vlist = self.validators
else:
raise RuntimeError
@@ -121,6 +122,8 @@
lazy=False,
noCache=False,
forceDBName=False,
+ title=None,
+ tags=[],
origName=None,
extra_vars=None):
@@ -213,6 +216,8 @@
# this is in case of ForeignKey, where we rename the column
# and append an ID
self.origName = origName or name
+ self.title = title
+ self.tags = tags
if extra_vars:
for name, value in extra_vars.items():
@@ -221,11 +226,11 @@
def _set_validator(self, value):
self._validator = value
if self._validator:
- self.toPython = self._validator.toPython
- self.fromPython = self._validator.fromPython
+ self.to_python = self._validator.to_python
+ self.from_python = self._validator.from_python
else:
- self.toPython = None
- self.fromPython = None
+ self.to_python = None
+ self.from_python = None
def _get_validator(self):
return self._validator
@@ -477,14 +482,14 @@
class StringValidator(validators.Validator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, unicode):
return value.encode("ascii")
return value
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
if isinstance(value, str):
@@ -504,14 +509,14 @@
class UnicodeStringValidator(validators.Validator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, unicode):
return value
return unicode(value, self.db_encoding)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
if isinstance(value, str):
@@ -533,7 +538,7 @@
class IntValidator(validators.Validator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, (int, long, sqlbuilder.SQLExpression)):
@@ -544,14 +549,14 @@
except OverflowError: # for Python 2.2
return long(value)
except:
- raise validators.InvalidField("expected an int in the IntCol '%s', got %s instead" % \
+ raise validators.Invalid("expected an int in the IntCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
if not isinstance(value, (int, long, sqlbuilder.SQLExpression)):
- raise validators.InvalidField("expected an int in the IntCol '%s', got %s instead" % \
+ raise validators.Invalid("expected an int in the IntCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
return value
@@ -573,7 +578,7 @@
class BoolValidator(validators.Validator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
elif not value:
@@ -581,7 +586,7 @@
else:
return sqlbuilder.TRUE
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
elif value:
@@ -621,7 +626,7 @@
class FloatValidator(validators.Validator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, (int, long, float, sqlbuilder.SQLExpression)):
@@ -629,14 +634,14 @@
try:
return float(value)
except:
- raise validators.InvalidField("expected a float in the FloatCol '%s', got %s instead" % \
+ raise validators.Invalid("expected a float in the FloatCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
if not isinstance(value, (int, long, float, sqlbuilder.SQLExpression)):
- raise validators.InvalidField("expected a float in the FloatCol '%s', got %s instead" % \
+ raise validators.Invalid("expected a float in the FloatCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
return value
@@ -765,6 +770,10 @@
def autoConstraints(self):
return [consts.isString, consts.InList(self.enumValues)]
+ def createValidators(self):
+ return [EnumValidator(name = self.name, enumValues = self.enumValues)] + \
+ super(SOEnumCol, self).createValidators()
+
def _mysqlType(self):
return "ENUM(%s)" % ', '.join([sqlbuilder.sqlrepr(v, 'mysql') for v in self.enumValues])
@@ -790,13 +799,25 @@
def _maxdbType(self):
raise "Enum type is not supported"
+class EnumValidator(validators.Validator):
+
+ def to_python(self, value, state):
+ if value in self.enumValues:
+ return value
+ else:
+ raise validators.Invalid("expected a member of %r in the EnumCol '%s', got %r instead" % \
+ (self.enumValues, self.name, value), value, state)
+
+ def from_python(self, value, state):
+ return self.to_python(value, state)
+
class EnumCol(Col):
baseClass = SOEnumCol
if datetime_available:
class DateTimeValidator(validators.DateValidator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, (datetime.date, datetime.datetime, sqlbuilder.SQLExpression)):
@@ -811,24 +832,24 @@
try:
stime = time.strptime(value, self.format)
except:
- raise validators.InvalidField("expected an date/time string of the '%s' format in the DateTimeCol '%s', got %s instead" % \
+ raise validators.Invalid("expected an date/time string of the '%s' format in the DateTimeCol '%s', got %s instead" % \
(self.format, self.name, type(value)), value, state)
secs = time.mktime(stime)
return datetime.datetime.fromtimestamp(secs)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
if isinstance(value, (datetime.date, datetime.datetime, sqlbuilder.SQLExpression)):
return value
if hasattr(value, "strftime"):
return value.strftime(self.format)
- raise validators.InvalidField("expected a datetime in the DateTimeCol '%s', got %s instead" % \
+ raise validators.Invalid("expected a datetime in the DateTimeCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
if mxdatetime_available:
class MXDateTimeValidator(validators.DateValidator):
- def toPython(self, value, state):
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, (DateTimeType, sqlbuilder.SQLExpression)):
@@ -842,18 +863,18 @@
try:
stime = time.strptime(value, self.format)
except:
- raise validators.InvalidField("expected an date/time string of the '%s' format in the DateTimeCol '%s', got %s instead" % \
+ raise validators.Invalid("expected an date/time string of the '%s' format in the DateTimeCol '%s', got %s instead" % \
(self.format, self.name, type(value)), value, state)
return DateTime.mktime(stime)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
if isinstance(value, (DateTimeType, sqlbuilder.SQLExpression)):
return value
if hasattr(value, "strftime"):
return value.strftime(self.format)
- raise validators.InvalidField("expected a mxDateTime in the DateTimeCol '%s', got %s instead" % \
+ raise validators.Invalid("expected a mxDateTime in the DateTimeCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
class SODateTimeCol(SOCol):
@@ -909,13 +930,13 @@
if datetime_available:
class DateValidator(DateTimeValidator):
- def toPython(self, value, state):
- value = super(DateValidator, self).toPython(value, state)
+ def to_python(self, value, state):
+ value = super(DateValidator, self).to_python(value, state)
if isinstance(value, datetime.datetime):
value = datetime.date(value.year, value.month, value.day)
return value
- fromPython = toPython
+ from_python = to_python
class SODateCol(SOCol):
dateFormat = '%Y-%m-%d'
@@ -994,7 +1015,9 @@
of wrapper type for binary conversion.
"""
- def toPython(self, value, state):
+ _cachedValue = None
+
+ def to_python(self, value, state):
if value is None:
return None
if isinstance(value, str):
@@ -1003,20 +1026,21 @@
value = module.decode(value)
return value
if isinstance(value, state.soObject._connection._binaryType):
- if hasattr(self, "_binaryValue") and (value == self._binaryValue):
- return self._origValue
+ cachedValue = self._cachedValue
+ if cachedValue and cachedValue[1] == value:
+ return cachedValue[0]
if isinstance(value, array_type): # MySQL
return value.tostring()
return str(value) # buffer => string
- raise validators.InvalidField("expected a string in the BLOBCol '%s', got %s instead" % \
+ raise validators.Invalid("expected a string in the BLOBCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
if value is None:
return None
- self._origValue = value # store the original value
- self._binaryValue = state.soObject._connection.createBinary(value)
- return self._binaryValue
+ binary = state.soObject._connection.createBinary(value)
+ self._cachedValue = (value, binary)
+ return binary
class SOBLOBCol(SOStringCol):
def createValidators(self):
@@ -1043,42 +1067,46 @@
class PickleValidator(BinaryValidator):
"""
- Validator for pickle types. A pickle type is simply a binary type with
- hidden pickling, so that we can simply store any kind of stuff in a
- particular column.
+ Validator for pickle types. A pickle type is simply a binary type
+ with hidden pickling, so that we can simply store any kind of
+ stuff in a particular column.
- The support for this relies directly on the support for binary for your
- database.
+ The support for this relies directly on the support for binary for
+ your database.
"""
- def toPython(self, value, state):
+ def to_python(self, value, state):
+ print str(value)
if value is None:
return None
if isinstance(value, unicode):
value = value.encode("ascii")
if isinstance(value, str):
+ print repr(value)
return pickle.loads(value)
- raise validators.InvalidField("expected a pickle string in the PickleCol '%s', got %s instead" % \
+ raise validators.Invalid("expected a pickle string in the PickleCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
- def fromPython(self, value, state):
+ def from_python(self, value, state):
+ print "IN/OUT", [value, pickle.dumps(value)]
if value is None:
return None
return pickle.dumps(value)
class SOPickleCol(SOBLOBCol):
+
def __init__(self, **kw):
self.pickleProtocol = popKey(kw, 'pickleProtocol', 1)
SOBLOBCol.__init__(self, **kw)
def createValidators(self):
- return [PickleValidator(name=self.name, pickleProtocol=self.pickleProtocol)] + \
+ return [PickleValidator(
+ name=self.name, pickleProtocol=self.pickleProtocol)] + \
super(SOPickleCol, self).createValidators()
class PickleCol(BLOBCol):
baseClass = SOPickleCol
-
def popKey(kw, name, default=None):
if not kw.has_key(name):
return default
Modified: trunk/SQLObject/sqlobject/main.py
===================================================================
--- trunk/SQLObject/sqlobject/main.py 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/sqlobject/main.py 2005-08-19 03:13:46 UTC (rev 921)
@@ -40,6 +40,7 @@
import classregistry
import declarative
from sresults import SelectResults
+from formencode import schema, compound
import sys
if sys.version_info[:3] < (2, 2, 0):
@@ -338,9 +339,9 @@
# making the table read-only
if not column.immutable:
# We start by just using the _SO_setValue method
- setter = eval('lambda self, val: self._SO_setValue(%s, val, self.%s, self.%s)' % (repr(name), '_SO_fromPython_%s' % name, '_SO_toPython_%s' % name))
- setattr(soClass, '_SO_fromPython_%s' % name, column.fromPython)
- setattr(soClass, '_SO_toPython_%s' % name, column.toPython)
+ setter = eval('lambda self, val: self._SO_setValue(%s, val, self.%s, self.%s)' % (repr(name), '_SO_from_python_%s' % name, '_SO_to_python_%s' % name))
+ setattr(soClass, '_SO_from_python_%s' % name, column.from_python)
+ setattr(soClass, '_SO_to_python_%s' % name, column.to_python)
setattr(soClass, rawSetterName(name), setter)
# Then do the aliasing
if not hasattr(soClass, setterName(name)) or (name == 'childName'):
@@ -556,7 +557,7 @@
index = indexDef.withClass(cls.soClass)
cls.indexes.append(index)
addIndex = classmethod(addIndex)
-
+
sqlhub = dbconnection.ConnectionHub()
class _sqlmeta_attr(object):
@@ -809,6 +810,7 @@
delJoin = _sqlmeta_attr('delJoin', 2)
addIndex = _sqlmeta_attr('addIndex', 2)
delIndex = _sqlmeta_attr('delIndex', 2)
+ getSchema = _sqlmeta_attr('getSchema', 2)
# @classmethod
def _SO_setupSqlmeta(cls, new_attrs, is_base):
@@ -1012,7 +1014,7 @@
finally:
self._SO_writeLock.release()
- def _SO_setValue(self, name, value, fromPython, toPython):
+ def _SO_setValue(self, name, value, from_python, to_python):
# This is the place where we actually update the
# database.
@@ -1020,12 +1022,12 @@
# in the database, and we can't insert it until all
# the parts are set. So we just keep them in a
# dictionary until later:
- if fromPython:
- dbValue = fromPython(value, self._SO_validatorState)
+ if from_python:
+ dbValue = from_python(value, self._SO_validatorState)
else:
dbValue = value
- if toPython:
- value = toPython(dbValue, self._SO_validatorState)
+ if to_python:
+ value = to_python(dbValue, self._SO_validatorState)
if self.sqlmeta._creating or self.sqlmeta.lazyUpdate:
self.dirty = True
self._SO_createValues[name] = dbValue
@@ -1056,14 +1058,14 @@
# _creating is special, see _SO_setValue
if self.sqlmeta._creating or self.sqlmeta.lazyUpdate:
for name, value in kw.items():
- fromPython = getattr(self, '_SO_fromPython_%s' % name, None)
- if fromPython:
- kw[name] = dbValue = fromPython(value, self._SO_validatorState)
+ from_python = getattr(self, '_SO_from_python_%s' % name, None)
+ if from_python:
+ kw[name] = dbValue = from_python(value, self._SO_validatorState)
else:
dbValue = value
- toPython = getattr(self, '_SO_toPython_%s' % name, None)
- if toPython:
- value = toPython(dbValue, self._SO_validatorState)
+ to_python = getattr(self, '_SO_to_python_%s' % name, None)
+ if to_python:
+ value = to_python(dbValue, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
try:
@@ -1093,14 +1095,14 @@
# else into a single UPDATE, if necessary.
toUpdate = {}
for name, value in kw.items():
- fromPython = getattr(self, '_SO_fromPython_%s' % name, None)
- if fromPython:
- dbValue = fromPython(value, self._SO_validatorState)
+ from_python = getattr(self, '_SO_from_python_%s' % name, None)
+ if from_python:
+ dbValue = from_python(value, self._SO_validatorState)
else:
dbValue = value
- toPython = getattr(self, '_SO_toPython_%s' % name, None)
- if toPython:
- value = toPython(dbValue, self._SO_validatorState)
+ to_python = getattr(self, '_SO_to_python_%s' % name, None)
+ if to_python:
+ value = to_python(dbValue, self._SO_validatorState)
if self.sqlmeta.cacheValues:
setattr(self, instanceName(name), value)
toUpdate[name] = dbValue
@@ -1124,8 +1126,8 @@
def _SO_selectInit(self, row):
for col, colValue in zip(self.sqlmeta.columnList, row):
- if col.toPython:
- colValue = col.toPython(colValue, self._SO_validatorState)
+ if col.to_python:
+ colValue = col.to_python(colValue, self._SO_validatorState)
setattr(self, instanceName(col.name), colValue)
def _SO_getValue(self, name):
@@ -1141,8 +1143,8 @@
assert results != None, "%s with id %s is not in the database" \
% (self.__class__.__name__, self.id)
value = results[0]
- if column.toPython:
- value = column.toPython(value, self._SO_validatorState)
+ if column.to_python:
+ value = column.to_python(value, self._SO_validatorState)
return value
def _SO_foreignKey(self, id, joinClass):
Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py
===================================================================
--- trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-19 03:13:46 UTC (rev 921)
@@ -102,6 +102,7 @@
q = self._insertSQL(table, names, values)
if self.debug:
self.printDebug(conn, q, 'QueryIns')
+ print [q]
c.execute(q)
if self.debugOutput:
self.printDebug(conn, id, 'QueryIns', 'result')
Modified: trunk/SQLObject/sqlobject/tests/test_enum.py
===================================================================
--- trunk/SQLObject/sqlobject/tests/test_enum.py 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/sqlobject/tests/test_enum.py 2005-08-19 03:13:46 UTC (rev 921)
@@ -1,5 +1,6 @@
from sqlobject import *
from sqlobject.tests.dbtest import *
+from formencode import Invalid
########################################
## Enum test
@@ -13,8 +14,8 @@
setupClass(Enum1)
for l in ['a', 'bcd', 'a', 'e']:
Enum1(l=l)
- if supports('restrictedEnum'):
- raises(
- (Enum1._connection.module.IntegrityError,
- Enum1._connection.module.ProgrammingError),
- Enum1, l='b')
+ raises(
+ (Enum1._connection.module.IntegrityError,
+ Enum1._connection.module.ProgrammingError,
+ Invalid),
+ Enum1, l='b')
Modified: trunk/SQLObject/sqlobject/tests/test_validation.py
===================================================================
--- trunk/SQLObject/sqlobject/tests/test_validation.py 2005-08-19 03:09:06 UTC (rev 920)
+++ trunk/SQLObject/sqlobject/tests/test_validation.py 2005-08-19 03:13:46 UTC (rev 921)
@@ -1,5 +1,6 @@
from sqlobject import *
from sqlobject.tests.dbtest import *
+from formencode import validators
########################################
## Validation/conversion
@@ -8,7 +9,7 @@
class SOValidation(SQLObject):
name = StringCol(validator=validators.PlainText(), default='x', dbName='name_col')
- name2 = StringCol(validator=validators.ConfirmType(str), default='y')
+ name2 = StringCol(validator=validators.ConfirmType(type=str), default='y')
name3 = IntCol(validator=validators.Wrapper(fromPython=int), default=100)
name4 = FloatCol(default=2.718)
@@ -19,23 +20,23 @@
def test_validate(self):
t = SOValidation(name='hey')
- raises(validators.InvalidField, setattr, t,
+ raises(validators.Invalid, setattr, t,
'name', '!!!')
t.name = 'you'
def test_confirmType(self):
t = SOValidation(name2='hey')
- raises(validators.InvalidField, setattr, t,
+ raises(validators.Invalid, setattr, t,
'name2', 1)
- raises(validators.InvalidField, setattr, t,
+ raises(validators.Invalid, setattr, t,
'name3', '1')
- raises(validators.InvalidField, setattr, t,
+ raises(validators.Invalid, setattr, t,
'name4', '1')
t.name2 = 'you'
def test_wrapType(self):
t = SOValidation(name3=1)
- raises(validators.InvalidField, setattr, t,
+ raises(validators.Invalid, setattr, t,
'name3', 'x')
t.name3 = 1L
assert t.name3 == 1
|