Author: phd
Date: 2005-01-09 11:28:46 +0000 (Sun, 09 Jan 2005)
New Revision: 522
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged patch from revision 521: added date/time validators, converters and tests.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-09 11:27:46 UTC (rev 521)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-09 11:28:46 UTC (rev 522)
@@ -2,8 +2,8 @@
Col
"""
+import re, time
import sqlbuilder
-import re
# Sadly the name "constraints" conflicts with many of the function
# arguments in this module, so we rename it:
import constraints as consts
@@ -12,7 +12,44 @@
NoDefault = sqlbuilder.NoDefault
True, False = 1==1, 0==1
+try:
+ import datetime
+except ImportError: # Python 2.2
+ datetime_available = False
+else:
+ datetime_available = True
+try:
+ from mx import DateTime
+except ImportError:
+ try:
+ import DateTime # old version of mxDateTime
+ except ImportError:
+ mxdatetime_available = False
+ else:
+ mxdatetime_available = True
+else:
+ mxdatetime_available = True
+
+if datetime_available:
+ DATETIME_IMPLEMENTATION = "datetime"
+
+if mxdatetime_available:
+ MXDATETIME_IMPLEMENTATION = "mxDateTime"
+ DateTimeType = type(DateTime.now())
+
+if datetime_available:
+ default_datetime_implementation = DATETIME_IMPLEMENTATION
+elif mxdatetime_available:
+ default_datetime_implementation = MXDATETIME_IMPLEMENTATION
+else:
+ default_datetime_implementation = None
+
+__all__ = ["datetime_available", "mxdatetime_available",
+ "DATETIME_IMPLEMENTATION", "MXDATETIME_IMPLEMENTATION",
+ "default_datetime_implementation"
+]
+
########################################
## Columns
########################################
@@ -620,11 +657,84 @@
class EnumCol(Col):
baseClass = SOEnumCol
+
+class DateTimeValidator(validators.DateValidator):
+ def fromPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, (datetime.date, datetime.datetime)):
+ return value
+ if hasattr(value, "strftime"):
+ return value.strftime(self.format)
+ raise validators.InvalidField("expected a datetime in the DateTimeCol '%s', got %s instead" % \
+ (self.name, type(value)), value, state)
+
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, (datetime.date, datetime.datetime)):
+ return value
+ if mxdatetime_available: # convert mxDateTime instance to datetime
+ if isinstance(value, DateTimeType):
+ if hasattr(value, "hour"):
+ return datetime.datetime(value.year, value.month, value.day,
+ value.hour, value.minute, value.second)
+ else:
+ return datetime.date(value.year, value.month, value.day)
+ try:
+ stime = time.strptime(value, self.format)
+ except:
+ raise validators.InvalidField("expected an ISO date/time string in the DateTimeCol '%s', got %s instead" % \
+ (self.name, type(value)), value, state)
+ secs = time.mktime(stime)
+ return datetime.datetime.fromtimestamp(secs)
+
+class MXDateTimeValidator(validators.DateValidator):
+ def fromPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, DateTimeType):
+ return value
+ if hasattr(value, "strftime"):
+ return value.strftime(self.format)
+ raise validators.InvalidField("expected a mxDateTime in the DateTimeCol '%s', got %s instead" % \
+ (self.name, type(value)), value, state)
+
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, DateTimeType):
+ return value
+ if datetime_available: # convert datetime instance to mxDateTime
+ if isinstance(value, (datetime.date, datetime.datetime)):
+ if hasattr(value, "hour"):
+ return DateTime.DateTime(value.year, value.month, value.day,
+ value.hour, value.minute, value.second)
+ else:
+ return DateTime.Date(value.year, value.month, value.day)
+ try:
+ stime = time.strptime(value, self.format)
+ except:
+ raise validators.InvalidField("expected an ISO date/time string in the DateTimeCol '%s', got %s instead" % \
+ (self.name, type(value)), value, state)
+ return DateTime.DateTime.mktime(stime)
+
class SODateTimeCol(SOCol):
+ if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ validatorClass = DateTimeValidator # can be overriden in descendants
+ elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ validatorClass = MXDateTimeValidator # can be overriden in descendants
+ datetimeFormat = '%Y-%m-%d %H:%M:%S'
- # 3-03 @@: provide constraints; right now we let the database
- # do any parsing and checking. And DATE and TIME?
+ def __init__(self, **kw):
+ SOCol.__init__(self, **kw)
+ if default_datetime_implementation:
+ self.validator = validators.All.join(self.createValidator(), self.validator)
+ def createValidator(self):
+ """Create a validator for the column. Can be overriden in descendants."""
+ return self.validatorClass(name=self.name, format=self.datetimeFormat)
+
def _mysqlType(self):
return 'DATETIME'
@@ -647,10 +757,21 @@
baseClass = SODateTimeCol
class SODateCol(SOCol):
+ if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ validatorClass = DateTimeValidator # can be overriden in descendants
+ elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ validatorClass = MXDateTimeValidator # can be overriden in descendants
+ dateFormat = '%Y-%m-%d'
- # 3-03 @@: provide constraints; right now we let the database
- # do any parsing and checking. And DATE and TIME?
+ def __init__(self, **kw):
+ SOCol.__init__(self, **kw)
+ if default_datetime_implementation:
+ self.validator = validators.All.join(self.createValidator(), self.validator)
+ def createValidator(self):
+ """Create a validator for the column. Can be overriden in descendants."""
+ return self.validatorClass(name=self.name, format=self.dateFormat)
+
def _mysqlType(self):
return 'DATE'
@@ -672,6 +793,7 @@
class DateCol(Col):
baseClass = SODateCol
+
class SODecimalCol(SOCol):
def __init__(self, **kw):
@@ -712,6 +834,7 @@
all = []
for key, value in globals().items():
- if isinstance(value, type) and issubclass(value, Col):
+ if isinstance(value, type) and issubclass(value, (Col, SOCol)):
all.append(key)
-__all__ = all
+__all__.extend(all)
+del all
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-09 11:27:46 UTC (rev 521)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-09 11:28:46 UTC (rev 522)
@@ -19,7 +19,11 @@
from sqlobject import *
from sqlobject.include import validators
from sqlobject import classregistry
-from mx import DateTime
+if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ from datetime import datetime
+ now = datetime.now
+elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ from mx.DateTime import now
global curr_db
curr_db = None
from sqlobject import cache
@@ -704,12 +708,12 @@
john = AutoTest(firstName='john',
lastName='doe',
age=10,
- created=DateTime.now(),
+ created=now(),
wannahavefun=False)
jane = AutoTest(firstName='jane',
lastName='doe',
happy='N',
- created=DateTime.now(),
+ created=now(),
wannahavefun=True)
self.failIf(john.wannahavefun)
self.failUnless(jane.wannahavefun)
@@ -1285,6 +1289,27 @@
self.assertEqual(self.data[count].encode('latin1'), col2)
########################################
+## Date/time columns
+########################################
+
+class DateTime1(SQLObject):
+ col1 = DateCol()
+ col2 = DateTimeCol()
+
+class DateTimeTest(SQLObjectTest):
+
+ classes = [DateTime1]
+
+ def testNow(self):
+ _now = now()
+ dt1 = DateTime1(col1=_now, col2=_now)
+
+ today_str = _now.strftime(SODateCol.dateFormat)
+ now_str = _now.strftime(SODateTimeCol.datetimeFormat)
+ self.assertEqual(str(dt1.col1), today_str)
+ self.assertEqual(str(dt1.col2), now_str)
+
+########################################
## Run from command-line:
########################################
|