sqlobject-cvs Mailing List for SQLObject (Page 172)
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
You can subscribe to this list here.
| 2003 |
Jan
|
Feb
|
Mar
(9) |
Apr
(74) |
May
(29) |
Jun
(16) |
Jul
(28) |
Aug
(10) |
Sep
(57) |
Oct
(9) |
Nov
(29) |
Dec
(12) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2004 |
Jan
(7) |
Feb
(14) |
Mar
(6) |
Apr
(3) |
May
(12) |
Jun
(34) |
Jul
(9) |
Aug
(29) |
Sep
(22) |
Oct
(2) |
Nov
(15) |
Dec
(52) |
| 2005 |
Jan
(47) |
Feb
(78) |
Mar
(14) |
Apr
(35) |
May
(33) |
Jun
(16) |
Jul
(26) |
Aug
(63) |
Sep
(40) |
Oct
(96) |
Nov
(96) |
Dec
(123) |
| 2006 |
Jan
(159) |
Feb
(144) |
Mar
(64) |
Apr
(31) |
May
(88) |
Jun
(48) |
Jul
(16) |
Aug
(64) |
Sep
(87) |
Oct
(92) |
Nov
(56) |
Dec
(76) |
| 2007 |
Jan
(94) |
Feb
(103) |
Mar
(126) |
Apr
(123) |
May
(85) |
Jun
(11) |
Jul
(130) |
Aug
(47) |
Sep
(65) |
Oct
(70) |
Nov
(12) |
Dec
(11) |
| 2008 |
Jan
(30) |
Feb
(55) |
Mar
(88) |
Apr
(20) |
May
(50) |
Jun
|
Jul
(38) |
Aug
(1) |
Sep
(9) |
Oct
(5) |
Nov
(6) |
Dec
(39) |
| 2009 |
Jan
(8) |
Feb
(16) |
Mar
(3) |
Apr
(33) |
May
(44) |
Jun
(1) |
Jul
(10) |
Aug
(33) |
Sep
(74) |
Oct
(22) |
Nov
|
Dec
(15) |
| 2010 |
Jan
(28) |
Feb
(22) |
Mar
(46) |
Apr
(29) |
May
(1) |
Jun
(1) |
Jul
(27) |
Aug
(8) |
Sep
(5) |
Oct
(33) |
Nov
(24) |
Dec
(41) |
| 2011 |
Jan
(4) |
Feb
(12) |
Mar
(35) |
Apr
(29) |
May
(19) |
Jun
(16) |
Jul
(32) |
Aug
(25) |
Sep
(5) |
Oct
(11) |
Nov
(21) |
Dec
(12) |
| 2012 |
Jan
(3) |
Feb
(4) |
Mar
(20) |
Apr
(4) |
May
(25) |
Jun
(13) |
Jul
|
Aug
|
Sep
(2) |
Oct
(25) |
Nov
(9) |
Dec
(1) |
| 2013 |
Jan
(6) |
Feb
(8) |
Mar
|
Apr
(10) |
May
(31) |
Jun
(7) |
Jul
(18) |
Aug
(33) |
Sep
(4) |
Oct
(16) |
Nov
|
Dec
(27) |
| 2014 |
Jan
(2) |
Feb
|
Mar
|
Apr
(11) |
May
(39) |
Jun
(8) |
Jul
(11) |
Aug
(4) |
Sep
|
Oct
(27) |
Nov
|
Dec
(71) |
| 2015 |
Jan
(17) |
Feb
(47) |
Mar
(33) |
Apr
|
May
|
Jun
(9) |
Jul
(7) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(8) |
| 2016 |
Jan
(4) |
Feb
(4) |
Mar
|
Apr
|
May
(12) |
Jun
(7) |
Jul
(9) |
Aug
(31) |
Sep
(8) |
Oct
(3) |
Nov
(15) |
Dec
(1) |
| 2017 |
Jan
(13) |
Feb
(7) |
Mar
(14) |
Apr
(8) |
May
(10) |
Jun
(4) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
(8) |
Nov
(4) |
Dec
(5) |
| 2018 |
Jan
(2) |
Feb
(8) |
Mar
|
Apr
(4) |
May
|
Jun
(6) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
| 2019 |
Jan
(1) |
Feb
(16) |
Mar
(1) |
Apr
(3) |
May
(5) |
Jun
(1) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
(3) |
| 2020 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
(2) |
Nov
|
Dec
(2) |
| 2021 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
| 2022 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(6) |
Oct
(1) |
Nov
(1) |
Dec
(4) |
| 2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(3) |
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
|
| 2024 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
(9) |
| 2025 |
Jan
|
Feb
(4) |
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(2) |
Dec
(2) |
|
From: <sub...@co...> - 2005-01-15 11:55:39
|
Author: phd
Date: 2005-01-15 11:55:33 +0000 (Sat, 15 Jan 2005)
New Revision: 546
Modified:
trunk/SQLObject/sqlobject/col.py
trunk/SQLObject/tests/test_sqlobject.py
Log:
Added FloatValidator and a test for it.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-14 17:17:46 UTC (rev 545)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-15 11:55:33 UTC (rev 546)
@@ -528,13 +528,44 @@
class BoolCol(Col):
baseClass = SOBoolCol
+
+class FloatValidator(validators.Validator):
+
+ def fromPython(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" % \
+ (self.name, type(value)), value, state)
+ return value
+
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, (int, long, float, sqlbuilder.SQLExpression)):
+ return value
+ try:
+ return float(value)
+ except:
+ raise validators.InvalidField("expected a float in the FloatCol '%s', got %s instead" % \
+ (self.name, type(value)), value, state)
+
class SOFloatCol(SOCol):
+ validatorClass = FloatValidator # can be overriden in descendants
# 3-03 @@: support precision (e.g., DECIMAL)
+ def __init__(self, **kw):
+ SOCol.__init__(self, **kw)
+ self.validator = validators.All.join(self.createValidator(), self.validator)
+
def autoConstraints(self):
return [consts.isFloat]
+ def createValidator(self):
+ """Create a validator for the column. Can be overriden in descendants."""
+ return self.validatorClass(name=self.name)
+
def _sqlType(self):
return 'FLOAT'
@@ -544,6 +575,7 @@
class FloatCol(Col):
baseClass = SOFloatCol
+
class SOKeyCol(SOCol):
# 3-03 @@: this should have a simplified constructor
Modified: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2005-01-14 17:17:46 UTC (rev 545)
+++ trunk/SQLObject/tests/test_sqlobject.py 2005-01-15 11:55:33 UTC (rev 546)
@@ -890,6 +890,7 @@
name = StringCol(validator=validators.PlainText(), default='x', dbName='name_col')
name2 = StringCol(validator=validators.ConfirmType(str), default='y')
name3 = IntCol(validator=validators.Wrapper(fromPython=int), default=100)
+ name4 = FloatCol(default=2.718)
class ValidationTest(SQLObjectTest):
@@ -905,6 +906,10 @@
t = SOValidation(name2='hey')
self.assertRaises(validators.InvalidField, setattr, t,
'name2', 1)
+ self.assertRaises(validators.InvalidField, setattr, t,
+ 'name3', '1')
+ self.assertRaises(validators.InvalidField, setattr, t,
+ 'name4', '1')
t.name2 = 'you'
def testWrapType(self):
|
|
From: <sub...@co...> - 2005-01-14 14:28:33
|
Author: phd
Date: 2005-01-14 14:28:29 +0000 (Fri, 14 Jan 2005)
New Revision: 544
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged patch from revision 543: added PickleCol, PickleValidator and tests.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-14 14:24:18 UTC (rev 543)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-14 14:28:29 UTC (rev 544)
@@ -19,6 +19,10 @@
"""
import re, time
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
import sqlbuilder
# Sadly the name "constraints" conflicts with many of the function
# arguments in this module, so we rename it:
@@ -885,6 +889,37 @@
baseClass = SOBLOBCol
+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.
+
+ The support for this relies directly on the support for binary for your
+ database.
+ """
+
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, str):
+ return pickle.loads(value)
+ return value
+
+ def fromPython(self, value, state):
+ if value is None:
+ return None
+ pickled = pickle.dumps(value)
+ return BinaryValidator.fromPython(self, pickled, state)
+
+
+class SOPickleCol(SOBLOBCol):
+ validatorClass = PickleValidator # can be overriden in descendants
+
+class PickleCol(BLOBCol):
+ baseClass = SOPickleCol
+
+
def popKey(kw, name, default=None):
if not kw.has_key(name):
return default
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-14 14:24:18 UTC (rev 543)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-14 14:28:29 UTC (rev 544)
@@ -1342,25 +1342,61 @@
## BLOB columns
########################################
-class Profile(SQLObject):
+class ImageData(SQLObject):
image = BLOBCol(default='emptydata', length=65535)
class BLOBColTest(SQLObjectTest):
- classes = [Profile]
+ classes = [ImageData]
def testBLOBCol(self):
data = ''.join([chr(x) for x in range(256)])
- prof = Profile()
+ prof = ImageData()
prof.image = data
iid = prof.id
connection().cache.clear()
- prof2 = Profile.get(iid)
- assert prof2.image == data
+ prof2 = ImageData.get(iid)
+ self.assertEqual(prof2.image, data)
########################################
+## Pickle columns
+########################################
+
+class PickleData:
+ pi = 3.14156
+ def __init__(self):
+ self.question = 'The Ulimate Question of Life, the Universe and Everything'
+ self.answer = 42
+
+class PickleContainer(SQLObject):
+ pickledata = PickleCol(default=None, length=65535)
+
+class PickleColTest(SQLObjectTest):
+ classes = [PickleContainer]
+
+ def testPickleCol(self):
+ mypickledata = PickleData()
+
+ ctnr = PickleContainer(pickledata=mypickledata)
+ iid = ctnr.id
+
+ connection().cache.clear()
+
+ ctnr2 = PickleContainer.get(iid)
+ s2 = ctnr2.pickledata
+
+ self.failUnless(isinstance(s2, PickleData))
+ self.failUnless(isinstance(s2.pi, float))
+ self.failUnless(isinstance(s2.question, str))
+ self.failUnless(isinstance(s2.answer, int))
+ self.assertEqual(s2.pi, mypickledata.pi)
+ self.assertEqual(s2.question, mypickledata.question)
+ self.assertEqual(s2.answer, mypickledata.answer)
+
+
+########################################
## Run from command-line:
########################################
|
|
From: <sub...@co...> - 2005-01-14 14:24:22
|
Author: phd
Date: 2005-01-14 14:24:18 +0000 (Fri, 14 Jan 2005)
New Revision: 543
Modified:
trunk/SQLObject/sqlobject/col.py
trunk/SQLObject/tests/test_sqlobject.py
Log:
Added PickleCol, PickleValidator and tests.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-14 13:53:41 UTC (rev 542)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-14 14:24:18 UTC (rev 543)
@@ -19,6 +19,10 @@
"""
import re, time
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
import sqlbuilder
# Sadly the name "constraints" conflicts with many of the function
# arguments in this module, so we rename it:
@@ -885,6 +889,37 @@
baseClass = SOBLOBCol
+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.
+
+ The support for this relies directly on the support for binary for your
+ database.
+ """
+
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, str):
+ return pickle.loads(value)
+ return value
+
+ def fromPython(self, value, state):
+ if value is None:
+ return None
+ pickled = pickle.dumps(value)
+ return BinaryValidator.fromPython(self, pickled, state)
+
+
+class SOPickleCol(SOBLOBCol):
+ validatorClass = PickleValidator # can be overriden in descendants
+
+class PickleCol(BLOBCol):
+ baseClass = SOPickleCol
+
+
def popKey(kw, name, default=None):
if not kw.has_key(name):
return default
Modified: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2005-01-14 13:53:41 UTC (rev 542)
+++ trunk/SQLObject/tests/test_sqlobject.py 2005-01-14 14:24:18 UTC (rev 543)
@@ -1342,25 +1342,61 @@
## BLOB columns
########################################
-class Profile(SQLObject):
+class ImageData(SQLObject):
image = BLOBCol(default='emptydata', length=65535)
class BLOBColTest(SQLObjectTest):
- classes = [Profile]
+ classes = [ImageData]
def testBLOBCol(self):
data = ''.join([chr(x) for x in range(256)])
- prof = Profile()
+ prof = ImageData()
prof.image = data
iid = prof.id
connection().cache.clear()
- prof2 = Profile.get(iid)
- assert prof2.image == data
+ prof2 = ImageData.get(iid)
+ self.assertEqual(prof2.image, data)
########################################
+## Pickle columns
+########################################
+
+class PickleData:
+ pi = 3.14156
+ def __init__(self):
+ self.question = 'The Ulimate Question of Life, the Universe and Everything'
+ self.answer = 42
+
+class PickleContainer(SQLObject):
+ pickledata = PickleCol(default=None, length=65535)
+
+class PickleColTest(SQLObjectTest):
+ classes = [PickleContainer]
+
+ def testPickleCol(self):
+ mypickledata = PickleData()
+
+ ctnr = PickleContainer(pickledata=mypickledata)
+ iid = ctnr.id
+
+ connection().cache.clear()
+
+ ctnr2 = PickleContainer.get(iid)
+ s2 = ctnr2.pickledata
+
+ self.failUnless(isinstance(s2, PickleData))
+ self.failUnless(isinstance(s2.pi, float))
+ self.failUnless(isinstance(s2.question, str))
+ self.failUnless(isinstance(s2.answer, int))
+ self.assertEqual(s2.pi, mypickledata.pi)
+ self.assertEqual(s2.question, mypickledata.question)
+ self.assertEqual(s2.answer, mypickledata.answer)
+
+
+########################################
## Run from command-line:
########################################
|
|
From: <sub...@co...> - 2005-01-14 13:53:43
|
Author: phd
Date: 2005-01-14 13:53:41 +0000 (Fri, 14 Jan 2005)
New Revision: 542
Modified:
home/phd/SQLObject/inheritance/docs/SQLObject.txt
home/phd/SQLObject/inheritance/sqlobject/col.py
Log:
Merged patches from revisions 539:541.
Modified: home/phd/SQLObject/inheritance/docs/SQLObject.txt
===================================================================
--- home/phd/SQLObject/inheritance/docs/SQLObject.txt 2005-01-14 13:52:12 UTC (rev 541)
+++ home/phd/SQLObject/inheritance/docs/SQLObject.txt 2005-01-14 13:53:41 UTC (rev 542)
@@ -1082,9 +1082,10 @@
`MySQLConnection` takes the keyword arguments `host`, `db`, `user`,
and `passwd`, just like `MySQLdb.connect` does.
-MySQLConnection supports all the features, though MySQL does not
-support transactions_ (except using a special proprietary backend that
-I haven't used).
+MySQLConnection supports all the features, though MySQL only supports
+transactions_ when using the InnoDB backend, and SQLObject currently
+does not have support for explicitly defining the backend when using
+``createTable``.
Postgres
--------
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-14 13:52:12 UTC (rev 541)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-14 13:53:41 UTC (rev 542)
@@ -898,7 +898,7 @@
all = []
for key, value in globals().items():
- if isinstance(value, type) and issubclass(value, (Col, SOCol)):
+ if isinstance(value, type) and (issubclass(value, Col) or issubclass(value, SOCol)):
all.append(key)
__all__.extend(all)
del all
|
|
From: <sub...@co...> - 2005-01-14 13:52:17
|
Author: phd
Date: 2005-01-14 13:52:12 +0000 (Fri, 14 Jan 2005)
New Revision: 541
Modified:
trunk/SQLObject/sqlobject/col.py
Log:
Fixed incompatibility - in Python 2.2 issubclass allows only a class as a second argument.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-13 17:29:02 UTC (rev 540)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-14 13:52:12 UTC (rev 541)
@@ -898,7 +898,7 @@
all = []
for key, value in globals().items():
- if isinstance(value, type) and issubclass(value, (Col, SOCol)):
+ if isinstance(value, type) and (issubclass(value, Col) or issubclass(value, SOCol)):
all.append(key)
__all__.extend(all)
del all
|
|
From: <sub...@co...> - 2005-01-13 17:29:08
|
Author: ianb Date: 2005-01-13 17:29:02 +0000 (Thu, 13 Jan 2005) New Revision: 540 Modified: trunk/SQLObject/docs/SQLObject.txt Log: Noted that MySQL does support transactions a little more clearly Modified: trunk/SQLObject/docs/SQLObject.txt =================================================================== --- trunk/SQLObject/docs/SQLObject.txt 2005-01-13 10:50:11 UTC (rev 539) +++ trunk/SQLObject/docs/SQLObject.txt 2005-01-13 17:29:02 UTC (rev 540) @@ -1082,9 +1082,10 @@ `MySQLConnection` takes the keyword arguments `host`, `db`, `user`, and `passwd`, just like `MySQLdb.connect` does. -MySQLConnection supports all the features, though MySQL does not -support transactions_ (except using a special proprietary backend that -I haven't used). +MySQLConnection supports all the features, though MySQL only supports +transactions_ when using the InnoDB backend, and SQLObject currently +does not have support for explicitly defining the backend when using +``createTable``. Postgres -------- |
|
From: Ian B. <ia...@co...> - 2005-01-13 16:40:23
|
sub...@co... wrote: > Author: phd > Date: 2005-01-13 10:43:56 +0000 (Thu, 13 Jan 2005) > New Revision: 538 > > Modified: > trunk/SQLObject/sqlobject/converters.py > Log: > Fixed a bug in sqlStringReplace - MySQL and PostgreSQL use backslash to escape quotes. Did you actually encounter this as a bug? They should both accept '' as well as \'; they are still different than other databases, because you have to quote \'s themselves, but you don't have to use that form. -- Ian Bicking / ia...@co... / http://blog.ianbicking.org |
|
From: <sub...@co...> - 2005-01-13 10:50:17
|
Author: phd
Date: 2005-01-13 10:50:11 +0000 (Thu, 13 Jan 2005)
New Revision: 539
Modified:
home/phd/SQLObject/inheritance/sqlobject/converters.py
Log:
Fixed a bug in sqlStringReplace - MySQL and PostgreSQL use backslash to escape quotes.
Modified: home/phd/SQLObject/inheritance/sqlobject/converters.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/converters.py 2005-01-13 10:43:56 UTC (rev 538)
+++ home/phd/SQLObject/inheritance/sqlobject/converters.py 2005-01-13 10:50:11 UTC (rev 539)
@@ -47,7 +47,7 @@
sqlStringReplace = [
('\\', '\\\\'),
- ("'", "''"),
+ ("'", "\\'"),
('\000', '\\0'),
('\b', '\\b'),
('\n', '\\n'),
|
|
From: <sub...@co...> - 2005-01-13 10:44:06
|
Author: phd
Date: 2005-01-13 10:43:56 +0000 (Thu, 13 Jan 2005)
New Revision: 538
Modified:
trunk/SQLObject/sqlobject/converters.py
Log:
Fixed a bug in sqlStringReplace - MySQL and PostgreSQL use backslash to escape quotes.
Modified: trunk/SQLObject/sqlobject/converters.py
===================================================================
--- trunk/SQLObject/sqlobject/converters.py 2005-01-12 17:39:30 UTC (rev 537)
+++ trunk/SQLObject/sqlobject/converters.py 2005-01-13 10:43:56 UTC (rev 538)
@@ -47,7 +47,7 @@
sqlStringReplace = [
('\\', '\\\\'),
- ("'", "''"),
+ ("'", "\\'"),
('\000', '\\0'),
('\b', '\\b'),
('\n', '\\n'),
|
|
From: <sub...@co...> - 2005-01-12 17:39:42
|
Author: phd
Date: 2005-01-12 17:39:30 +0000 (Wed, 12 Jan 2005)
New Revision: 537
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
home/phd/SQLObject/inheritance/sqlobject/converters.py
home/phd/SQLObject/inheritance/sqlobject/dbconnection.py
home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py
home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged patches from revision 536:
added BLOB column type (for PostgreSQL and MySQL),
BinaryValidator and a test for them.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -845,6 +845,46 @@
class CurrencyCol(DecimalCol):
baseClass = SOCurrencyCol
+
+class BinaryValidator(validators.Validator):
+ """
+ Validator for binary types.
+
+ We're assuming that the per-database modules provide some form
+ of wrapper type for binary conversion.
+ """
+
+ def fromPython(self, value, state):
+ return state.soObject._connection.createBinary(value)
+
+class SOBLOBCol(SOStringCol):
+ validatorClass = BinaryValidator # can be overriden in descendants
+
+ def __init__(self, **kw):
+ SOStringCol.__init__(self, **kw)
+ self.validator = validators.All.join(self.createValidator(), self.validator)
+
+ def createValidator(self):
+ return self.validatorClass()
+
+ def _mysqlType(self):
+ length = self.length
+ varchar = self.varchar
+ if length >= 2**24:
+ return varchar and "LONGTEXT" or "LONGBLOB"
+ if length >= 2**16:
+ return varchar and "MEDIUMTEXT" or "MEDIUMBLOB"
+ if length >= 2**8:
+ return varchar and "TEXT" or "BLOB"
+ return varchar and "TINYTEXT" or "TINYBLOB"
+
+ def _postgresType(self):
+ return 'BYTEA'
+
+class BLOBCol(StringCol):
+ baseClass = SOBLOBCol
+
+
def popKey(kw, name, default=None):
if not kw.has_key(name):
return default
Modified: home/phd/SQLObject/inheritance/sqlobject/converters.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/converters.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/converters.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -188,4 +188,3 @@
else:
return reprFunc(db)
-
Modified: home/phd/SQLObject/inheritance/sqlobject/dbconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/dbconnection.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/dbconnection.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -375,6 +375,13 @@
# that.
self.query("DELETE FROM %s" % tableName)
+ def createBinary(self, value):
+ """
+ Create a binary object wrapper for the given database.
+ """
+ # Default is Binary() function from the connection driver.
+ return self.module.Binary(value)
+
# The _SO_* series of methods are sorts of "friend" methods
# with SQLObject. They grab values from the SQLObject instances
# or classes freely, but keep the SQLObject class from accessing
Modified: home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -120,6 +120,21 @@
return col.DateTimeCol, {}
elif t.startswith('bool'):
return col.BoolCol, {}
+ elif t.startswith('tinyblob'):
+ return col.BLOBCol, {"length": 2**8-1}
+ elif t.startswith('tinytext'):
+ return col.BLOBCol, {"length": 2**8-1, "varchar": True}
+ elif t.startswith('blob'):
+ return col.BLOBCol, {"length": 2**16-1}
+ elif t.startswith('text'):
+ return col.BLOBCol, {"length": 2**16-1, "varchar": True}
+ elif t.startswith('mediumblob'):
+ return col.BLOBCol, {"length": 2**24-1}
+ elif t.startswith('mediumtext'):
+ return col.BLOBCol, {"length": 2**24-1, "varchar": True}
+ elif t.startswith('longblob'):
+ return col.BLOBCol, {"length": 2**32}
+ elif t.startswith('longtext'):
+ return col.BLOBCol, {"length": 2**32, "varchar": True}
else:
return col.Col, {}
-
Modified: home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -2,6 +2,7 @@
import re
from sqlobject import col
from sqlobject import sqlbuilder
+from sqlobject.converters import registerConverter
psycopg = None
pgdb = None
@@ -24,6 +25,10 @@
import psycopg
self.module = psycopg
+ # Register a converter for psycopg Binary type.
+ registerConverter(type(psycopg.Binary('')),
+ PsycoBinaryConverter)
+
if dsn is None:
dsn = []
if db:
@@ -49,7 +54,9 @@
connectionFromURI = classmethod(connectionFromURI)
def _setAutoCommit(self, conn, auto):
- conn.autocommit(auto)
+ # psycopg2 does not have an autocommit method.
+ if hasattr(conn, 'autocommit'):
+ conn.autocommit(auto)
def makeConnection(self):
try:
@@ -57,7 +64,9 @@
except self.module.OperationalError, e:
raise self.module.OperationalError("%s; used connection string %r" % (e, self.dsn))
if self.autoCommit:
- conn.autocommit(1)
+ # psycopg2 does not have an autocommit method.
+ if hasattr(conn, 'autocommit'):
+ conn.autocommit(1)
return conn
def _queryInsertID(self, conn, soInstance, id, names, values):
@@ -199,6 +208,8 @@
return col.DateTimeCol, {}
elif t.startswith('bool'):
return col.BoolCol, {}
+ elif t.startswith('bytea'):
+ return col.BLOBCol, {}
else:
return col.Col, {}
@@ -210,3 +221,9 @@
self._server_version = server_version.split()[1]
return self._server_version
server_version = property(server_version)
+
+
+# Converter for psycopg Binary type.
+def PsycoBinaryConverter(value, db):
+ assert db == 'postgres'
+ return str(value)
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-12 17:36:14 UTC (rev 536)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-12 17:39:30 UTC (rev 537)
@@ -1339,6 +1339,28 @@
self.assertEqual(str(dt2.col2), now_str)
########################################
+## BLOB columns
+########################################
+
+class Profile(SQLObject):
+ image = BLOBCol(default='emptydata', length=65535)
+
+class BLOBColTest(SQLObjectTest):
+ classes = [Profile]
+
+ def testBLOBCol(self):
+ data = ''.join([chr(x) for x in range(256)])
+
+ prof = Profile()
+ prof.image = data
+ iid = prof.id
+
+ connection().cache.clear()
+
+ prof2 = Profile.get(iid)
+ assert prof2.image == data
+
+########################################
## Run from command-line:
########################################
|
|
From: <sub...@co...> - 2005-01-12 17:36:25
|
Author: phd
Date: 2005-01-12 17:36:14 +0000 (Wed, 12 Jan 2005)
New Revision: 536
Modified:
trunk/SQLObject/sqlobject/col.py
trunk/SQLObject/sqlobject/converters.py
trunk/SQLObject/sqlobject/dbconnection.py
trunk/SQLObject/sqlobject/mysql/mysqlconnection.py
trunk/SQLObject/sqlobject/postgres/pgconnection.py
trunk/SQLObject/tests/test_sqlobject.py
Log:
Added BLOB column type (for PostgreSQL and MySQL),
BinaryValidator and a test for them.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-12 12:25:36 UTC (rev 535)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-12 17:36:14 UTC (rev 536)
@@ -845,6 +845,46 @@
class CurrencyCol(DecimalCol):
baseClass = SOCurrencyCol
+
+class BinaryValidator(validators.Validator):
+ """
+ Validator for binary types.
+
+ We're assuming that the per-database modules provide some form
+ of wrapper type for binary conversion.
+ """
+
+ def fromPython(self, value, state):
+ return state.soObject._connection.createBinary(value)
+
+class SOBLOBCol(SOStringCol):
+ validatorClass = BinaryValidator # can be overriden in descendants
+
+ def __init__(self, **kw):
+ SOStringCol.__init__(self, **kw)
+ self.validator = validators.All.join(self.createValidator(), self.validator)
+
+ def createValidator(self):
+ return self.validatorClass()
+
+ def _mysqlType(self):
+ length = self.length
+ varchar = self.varchar
+ if length >= 2**24:
+ return varchar and "LONGTEXT" or "LONGBLOB"
+ if length >= 2**16:
+ return varchar and "MEDIUMTEXT" or "MEDIUMBLOB"
+ if length >= 2**8:
+ return varchar and "TEXT" or "BLOB"
+ return varchar and "TINYTEXT" or "TINYBLOB"
+
+ def _postgresType(self):
+ return 'BYTEA'
+
+class BLOBCol(StringCol):
+ baseClass = SOBLOBCol
+
+
def popKey(kw, name, default=None):
if not kw.has_key(name):
return default
Modified: trunk/SQLObject/sqlobject/converters.py
===================================================================
--- trunk/SQLObject/sqlobject/converters.py 2005-01-12 12:25:36 UTC (rev 535)
+++ trunk/SQLObject/sqlobject/converters.py 2005-01-12 17:36:14 UTC (rev 536)
@@ -188,4 +188,3 @@
else:
return reprFunc(db)
-
Modified: trunk/SQLObject/sqlobject/dbconnection.py
===================================================================
--- trunk/SQLObject/sqlobject/dbconnection.py 2005-01-12 12:25:36 UTC (rev 535)
+++ trunk/SQLObject/sqlobject/dbconnection.py 2005-01-12 17:36:14 UTC (rev 536)
@@ -375,6 +375,13 @@
# that.
self.query("DELETE FROM %s" % tableName)
+ def createBinary(self, value):
+ """
+ Create a binary object wrapper for the given database.
+ """
+ # Default is Binary() function from the connection driver.
+ return self.module.Binary(value)
+
# The _SO_* series of methods are sorts of "friend" methods
# with SQLObject. They grab values from the SQLObject instances
# or classes freely, but keep the SQLObject class from accessing
Modified: trunk/SQLObject/sqlobject/mysql/mysqlconnection.py
===================================================================
--- trunk/SQLObject/sqlobject/mysql/mysqlconnection.py 2005-01-12 12:25:36 UTC (rev 535)
+++ trunk/SQLObject/sqlobject/mysql/mysqlconnection.py 2005-01-12 17:36:14 UTC (rev 536)
@@ -120,6 +120,21 @@
return col.DateTimeCol, {}
elif t.startswith('bool'):
return col.BoolCol, {}
+ elif t.startswith('tinyblob'):
+ return col.BLOBCol, {"length": 2**8-1}
+ elif t.startswith('tinytext'):
+ return col.BLOBCol, {"length": 2**8-1, "varchar": True}
+ elif t.startswith('blob'):
+ return col.BLOBCol, {"length": 2**16-1}
+ elif t.startswith('text'):
+ return col.BLOBCol, {"length": 2**16-1, "varchar": True}
+ elif t.startswith('mediumblob'):
+ return col.BLOBCol, {"length": 2**24-1}
+ elif t.startswith('mediumtext'):
+ return col.BLOBCol, {"length": 2**24-1, "varchar": True}
+ elif t.startswith('longblob'):
+ return col.BLOBCol, {"length": 2**32}
+ elif t.startswith('longtext'):
+ return col.BLOBCol, {"length": 2**32, "varchar": True}
else:
return col.Col, {}
-
Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py
===================================================================
--- trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-01-12 12:25:36 UTC (rev 535)
+++ trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-01-12 17:36:14 UTC (rev 536)
@@ -2,6 +2,7 @@
import re
from sqlobject import col
from sqlobject import sqlbuilder
+from sqlobject.converters import registerConverter
psycopg = None
pgdb = None
@@ -24,6 +25,10 @@
import psycopg
self.module = psycopg
+ # Register a converter for psycopg Binary type.
+ registerConverter(type(psycopg.Binary('')),
+ PsycoBinaryConverter)
+
if dsn is None:
dsn = []
if db:
@@ -49,7 +54,9 @@
connectionFromURI = classmethod(connectionFromURI)
def _setAutoCommit(self, conn, auto):
- conn.autocommit(auto)
+ # psycopg2 does not have an autocommit method.
+ if hasattr(conn, 'autocommit'):
+ conn.autocommit(auto)
def makeConnection(self):
try:
@@ -57,7 +64,9 @@
except self.module.OperationalError, e:
raise self.module.OperationalError("%s; used connection string %r" % (e, self.dsn))
if self.autoCommit:
- conn.autocommit(1)
+ # psycopg2 does not have an autocommit method.
+ if hasattr(conn, 'autocommit'):
+ conn.autocommit(1)
return conn
def _queryInsertID(self, conn, soInstance, id, names, values):
@@ -199,6 +208,8 @@
return col.DateTimeCol, {}
elif t.startswith('bool'):
return col.BoolCol, {}
+ elif t.startswith('bytea'):
+ return col.BLOBCol, {}
else:
return col.Col, {}
@@ -210,3 +221,9 @@
self._server_version = server_version.split()[1]
return self._server_version
server_version = property(server_version)
+
+
+# Converter for psycopg Binary type.
+def PsycoBinaryConverter(value, db):
+ assert db == 'postgres'
+ return str(value)
Modified: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2005-01-12 12:25:36 UTC (rev 535)
+++ trunk/SQLObject/tests/test_sqlobject.py 2005-01-12 17:36:14 UTC (rev 536)
@@ -1339,6 +1339,28 @@
self.assertEqual(str(dt2.col2), now_str)
########################################
+## BLOB columns
+########################################
+
+class Profile(SQLObject):
+ image = BLOBCol(default='emptydata', length=65535)
+
+class BLOBColTest(SQLObjectTest):
+ classes = [Profile]
+
+ def testBLOBCol(self):
+ data = ''.join([chr(x) for x in range(256)])
+
+ prof = Profile()
+ prof.image = data
+ iid = prof.id
+
+ connection().cache.clear()
+
+ prof2 = Profile.get(iid)
+ assert prof2.image == data
+
+########################################
## Run from command-line:
########################################
|
|
From: <sub...@co...> - 2005-01-12 12:25:41
|
Author: phd
Date: 2005-01-12 12:25:36 +0000 (Wed, 12 Jan 2005)
New Revision: 535
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
Log:
mxDateTime stores second as float - datetime wants an int.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 12:25:05 UTC (rev 534)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 12:25:36 UTC (rev 535)
@@ -698,7 +698,7 @@
# convert mxDateTime instance to datetime
if ("%H" in self.format) or ("%T" in self.format):
return datetime.datetime(value.year, value.month, value.day,
- value.hour, value.minute, value.second)
+ value.hour, value.minute, int(value.second))
else:
return datetime.date(value.year, value.month, value.day)
try:
|
|
From: <sub...@co...> - 2005-01-12 12:25:10
|
Author: phd
Date: 2005-01-12 12:25:05 +0000 (Wed, 12 Jan 2005)
New Revision: 534
Modified:
trunk/SQLObject/sqlobject/col.py
Log:
mxDateTime stores second as float - datetime wants an int.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-12 12:14:08 UTC (rev 533)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-12 12:25:05 UTC (rev 534)
@@ -698,7 +698,7 @@
# convert mxDateTime instance to datetime
if ("%H" in self.format) or ("%T" in self.format):
return datetime.datetime(value.year, value.month, value.day,
- value.hour, value.minute, value.second)
+ value.hour, value.minute, int(value.second))
else:
return datetime.date(value.year, value.month, value.day)
try:
|
|
From: <sub...@co...> - 2005-01-12 12:14:14
|
Author: phd
Date: 2005-01-12 12:14:08 +0000 (Wed, 12 Jan 2005)
New Revision: 533
Modified:
home/phd/SQLObject/inheritance/sqlobject/cache.py
home/phd/SQLObject/inheritance/sqlobject/col.py
Log:
Merged patches from revisions 528:532
Modified: home/phd/SQLObject/inheritance/sqlobject/cache.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/cache.py 2005-01-11 21:20:59 UTC (rev 532)
+++ home/phd/SQLObject/inheritance/sqlobject/cache.py 2005-01-12 12:14:08 UTC (rev 533)
@@ -1,3 +1,11 @@
+"""
+This implements the instance caching in SQLObject. Caching is
+relatively aggressive. All objects are retained so long as they are
+in memory, by keeping weak references to objects. We also keep other
+objects in a cache that doesn't allow them to be garbage collected
+(unless caching is turned off).
+"""
+
import threading
from weakref import ref
from time import time as now
@@ -46,6 +54,9 @@
self.lock = threading.Lock()
def tryGet(self, id):
+ """
+ This returns None, or the object in cache.
+ """
value = self.expiredCache.get(id)
if value:
# it's actually a weakref:
@@ -55,7 +66,29 @@
return self.cache.get(id)
def get(self, id):
+ """
+ This method can cause deadlocks! tryGet is safer
+ This returns the object found in cache, or None. If None,
+ then the cache will remain locked! This is so that the
+ calling function can create the object in a threadsafe manner
+ before releasing the lock. You should use this like (note
+ that ``cache`` is actually a CacheSet object in this
+ example)::
+
+ obj = cache.get(some_id, my_class)
+ if obj is None:
+ try:
+ obj = create_object(some_id)
+ cache.put(some_id, my_class, obj)
+ finally:
+ cache.finishPut(cls)
+
+ This method checks both the main cache (which retains
+ references) and the 'expired' cache, which retains only weak
+ references.
+ """
+
if self.doCache:
if self.cullCount > self.cullFrequency:
# Two threads could hit the cull in a row, but
@@ -109,21 +142,40 @@
return val
def put(self, id, obj):
+ """
+ Puts an object into the cache. Should only be called after
+ .get(), so that duplicate objects don't end up in the cache.
+ """
if self.doCache:
self.cache[id] = obj
else:
self.expiredCache[id] = ref(obj)
def finishPut(self):
+ """
+ Releases the lock that is retained when .get() is called and
+ returns None.
+ """
self.lock.release()
def created(self, id, obj):
+ """
+ Inserts and object into the cache. Should be used when no one
+ else knows about the object yet, so there cannot be any object
+ already in the cache. After a database INSERT is an example
+ of this situation.
+ """
if self.doCache:
self.cache[id] = obj
else:
self.expiredCache[id] = ref(obj)
def cull(self):
+ """
+ Runs through the cache and expires objects. E.g., if
+ ``cullFraction`` is 3, then every third object is moved to
+ the 'expired' (aka weakref) cache.
+ """
self.lock.acquire()
try:
keys = self.cache.keys()
@@ -139,11 +191,19 @@
self.lock.release()
def clear(self):
+ """
+ Removes everything from the cache. Warning! This can cause
+ duplicate objects in memory.
+ """
if self.doCache:
self.cache.clear()
self.expiredCache.clear()
def expire(self, id):
+ """
+ Expires a single object. Typically called after a delete.
+ Doesn't even keep a weakref. (@@: bad name?)
+ """
if not self.doCache:
return
self.lock.acquire()
@@ -156,6 +216,10 @@
self.lock.release()
def expireAll(self):
+ """
+ Expires all objects, moving them all into the expired/weakref
+ cache.
+ """
if not self.doCache:
return
self.lock.acquire()
@@ -167,6 +231,9 @@
self.lock.release()
def allIDs(self):
+ """
+ Returns the IDs of all objects in the cache.
+ """
if self.doCache:
all = self.cache.keys()
else:
@@ -178,6 +245,14 @@
class CacheSet(object):
+ """
+ A CacheSet is used to collect and maintain a series of caches. In
+ SQLObject, there is one CacheSet per connection, and one Cache
+ in the CacheSet for each class, since IDs are not unique across
+ classes. It contains methods similar to Cache, but that take
+ a ``cls`` argument.
+ """
+
def __init__(self, *args, **kw):
self.caches = {}
self.args = args
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-11 21:20:59 UTC (rev 532)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-12 12:14:08 UTC (rev 533)
@@ -1,5 +1,21 @@
"""
-Col
+Col -- SQLObject columns
+
+Note that each column object is named BlahBlahCol, and these are used
+in class definitions. But there's also a corresponding SOBlahBlahCol
+object, which is used in SQLObject *classes*.
+
+An explanation: when a SQLObject subclass is created, the metaclass
+looks through your class definition for any subclasses of Col. It
+collects them together, and indexes them to do all the database stuff
+you like, like the magic attributes and whatnot. It then asks the Col
+object to create an SOCol object (usually a subclass, actually). The
+SOCol object contains all the interesting logic, as well as a record
+of the attribute name you used and the class it is bound to (set by
+the metaclass).
+
+So, in summary: Col objects are what you define, but SOCol objects
+are what gets used.
"""
import re, time
|
|
From: <sub...@co...> - 2005-01-11 17:22:47
|
Author: ianb
Date: 2005-01-11 17:22:39 +0000 (Tue, 11 Jan 2005)
New Revision: 530
Modified:
trunk/SQLObject/sqlobject/cache.py
Log:
Added docstrings to methods and module
Modified: trunk/SQLObject/sqlobject/cache.py
===================================================================
--- trunk/SQLObject/sqlobject/cache.py 2005-01-11 17:22:12 UTC (rev 529)
+++ trunk/SQLObject/sqlobject/cache.py 2005-01-11 17:22:39 UTC (rev 530)
@@ -1,3 +1,11 @@
+"""
+This implements the instance caching in SQLObject. Caching is
+relatively aggressive. All objects are retained so long as they are
+in memory, by keeping weak references to objects. We also keep other
+objects in a cache that doesn't allow them to be garbage collected
+(unless caching is turned off).
+"""
+
import threading
from weakref import ref
from time import time as now
@@ -46,6 +54,9 @@
self.lock = threading.Lock()
def tryGet(self, id):
+ """
+ This returns None, or the object in cache.
+ """
value = self.expiredCache.get(id)
if value:
# it's actually a weakref:
@@ -55,7 +66,29 @@
return self.cache.get(id)
def get(self, id):
+ """
+ This method can cause deadlocks! tryGet is safer
+ This returns the object found in cache, or None. If None,
+ then the cache will remain locked! This is so that the
+ calling function can create the object in a threadsafe manner
+ before releasing the lock. You should use this like (note
+ that ``cache`` is actually a CacheSet object in this
+ example)::
+
+ obj = cache.get(some_id, my_class)
+ if obj is None:
+ try:
+ obj = create_object(some_id)
+ cache.put(some_id, my_class, obj)
+ finally:
+ cache.finishPut(cls)
+
+ This method checks both the main cache (which retains
+ references) and the 'expired' cache, which retains only weak
+ references.
+ """
+
if self.doCache:
if self.cullCount > self.cullFrequency:
# Two threads could hit the cull in a row, but
@@ -109,21 +142,40 @@
return val
def put(self, id, obj):
+ """
+ Puts an object into the cache. Should only be called after
+ .get(), so that duplicate objects don't end up in the cache.
+ """
if self.doCache:
self.cache[id] = obj
else:
self.expiredCache[id] = ref(obj)
def finishPut(self):
+ """
+ Releases the lock that is retained when .get() is called and
+ returns None.
+ """
self.lock.release()
def created(self, id, obj):
+ """
+ Inserts and object into the cache. Should be used when no one
+ else knows about the object yet, so there cannot be any object
+ already in the cache. After a database INSERT is an example
+ of this situation.
+ """
if self.doCache:
self.cache[id] = obj
else:
self.expiredCache[id] = ref(obj)
def cull(self):
+ """
+ Runs through the cache and expires objects. E.g., if
+ ``cullFraction`` is 3, then every third object is moved to
+ the 'expired' (aka weakref) cache.
+ """
self.lock.acquire()
try:
keys = self.cache.keys()
@@ -139,11 +191,19 @@
self.lock.release()
def clear(self):
+ """
+ Removes everything from the cache. Warning! This can cause
+ duplicate objects in memory.
+ """
if self.doCache:
self.cache.clear()
self.expiredCache.clear()
def expire(self, id):
+ """
+ Expires a single object. Typically called after a delete.
+ Doesn't even keep a weakref. (@@: bad name?)
+ """
if not self.doCache:
return
self.lock.acquire()
@@ -156,6 +216,10 @@
self.lock.release()
def expireAll(self):
+ """
+ Expires all objects, moving them all into the expired/weakref
+ cache.
+ """
if not self.doCache:
return
self.lock.acquire()
@@ -167,6 +231,9 @@
self.lock.release()
def allIDs(self):
+ """
+ Returns the IDs of all objects in the cache.
+ """
if self.doCache:
all = self.cache.keys()
else:
@@ -178,6 +245,14 @@
class CacheSet(object):
+ """
+ A CacheSet is used to collect and maintain a series of caches. In
+ SQLObject, there is one CacheSet per connection, and one Cache
+ in the CacheSet for each class, since IDs are not unique across
+ classes. It contains methods similar to Cache, but that take
+ a ``cls`` argument.
+ """
+
def __init__(self, *args, **kw):
self.caches = {}
self.args = args
|
|
From: <sub...@co...> - 2005-01-11 17:22:17
|
Author: ianb Date: 2005-01-11 17:22:12 +0000 (Tue, 11 Jan 2005) New Revision: 529 Modified: trunk/SQLObject/sqlobject/col.py Log: Added docstring to top Modified: trunk/SQLObject/sqlobject/col.py =================================================================== --- trunk/SQLObject/sqlobject/col.py 2005-01-10 11:55:16 UTC (rev 528) +++ trunk/SQLObject/sqlobject/col.py 2005-01-11 17:22:12 UTC (rev 529) @@ -1,5 +1,21 @@ """ -Col +Col -- SQLObject columns + +Note that each column object is named BlahBlahCol, and these are used +in class definitions. But there's also a corresponding SOBlahBlahCol +object, which is used in SQLObject *classes*. + +An explanation: when a SQLObject subclass is created, the metaclass +looks through your class definition for any subclasses of Col. It +collects them together, and indexes them to do all the database stuff +you like, like the magic attributes and whatnot. It then asks the Col +object to create an SOCol object (usually a subclass, actually). The +SOCol object contains all the interesting logic, as well as a record +of the attribute name you used and the class it is bound to (set by +the metaclass). + +So, in summary: Col objects are what you define, but SOCol objects +are what gets used. """ import re, time |
|
From: <sub...@co...> - 2005-01-10 11:55:25
|
Author: phd
Date: 2005-01-10 11:55:16 +0000 (Mon, 10 Jan 2005)
New Revision: 528
Modified:
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Minor improvements in the date/time tests.
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-10 11:54:39 UTC (rev 527)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-10 11:55:16 UTC (rev 528)
@@ -1308,12 +1308,9 @@
def testDateTime(self):
_now = now()
dt1 = DateTime1(col1=_now, col2=_now)
+ self.failUnless(isinstance(dt1.col1, date))
+ self.failUnless(isinstance(dt1.col2, datetime))
- date_type = date
- datetime_type = datetime
- self.assertEqual(type(dt1.col1), date_type)
- self.assertEqual(type(dt1.col2), datetime_type)
-
today_str = _now.strftime("%Y-%m-%d")
now_str = _now.strftime("%Y-%m-%d %T")
self.assertEqual(str(dt1.col1), today_str)
@@ -1333,12 +1330,9 @@
def testMxDateTime(self):
_now = now()
dt2 = DateTime2(col1=_now, col2=_now)
+ self.failUnless(isinstance(dt2.col1, col.DateTimeType))
+ self.failUnless(isinstance(dt2.col2, col.DateTimeType))
- date_type = col.DateTimeType
- datetime_type = col.DateTimeType
- self.assertEqual(type(dt2.col1), date_type)
- self.assertEqual(type(dt2.col2), datetime_type)
-
today_str = _now.strftime("%Y-%m-%d 00:00:00.00")
now_str = _now.strftime("%Y-%m-%d %T.00")
self.assertEqual(str(dt2.col1), today_str)
|
|
From: <sub...@co...> - 2005-01-10 11:54:45
|
Author: phd
Date: 2005-01-10 11:54:39 +0000 (Mon, 10 Jan 2005)
New Revision: 527
Modified:
trunk/SQLObject/tests/test_sqlobject.py
Log:
Minor improvements in the date/time tests.
Modified: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2005-01-09 16:55:21 UTC (rev 526)
+++ trunk/SQLObject/tests/test_sqlobject.py 2005-01-10 11:54:39 UTC (rev 527)
@@ -1308,12 +1308,9 @@
def testDateTime(self):
_now = now()
dt1 = DateTime1(col1=_now, col2=_now)
+ self.failUnless(isinstance(dt1.col1, date))
+ self.failUnless(isinstance(dt1.col2, datetime))
- date_type = date
- datetime_type = datetime
- self.assertEqual(type(dt1.col1), date_type)
- self.assertEqual(type(dt1.col2), datetime_type)
-
today_str = _now.strftime("%Y-%m-%d")
now_str = _now.strftime("%Y-%m-%d %T")
self.assertEqual(str(dt1.col1), today_str)
@@ -1333,12 +1330,9 @@
def testMxDateTime(self):
_now = now()
dt2 = DateTime2(col1=_now, col2=_now)
+ self.failUnless(isinstance(dt2.col1, col.DateTimeType))
+ self.failUnless(isinstance(dt2.col2, col.DateTimeType))
- date_type = col.DateTimeType
- datetime_type = col.DateTimeType
- self.assertEqual(type(dt2.col1), date_type)
- self.assertEqual(type(dt2.col2), datetime_type)
-
today_str = _now.strftime("%Y-%m-%d 00:00:00.00")
now_str = _now.strftime("%Y-%m-%d %T.00")
self.assertEqual(str(dt2.col1), today_str)
|
|
From: <sub...@co...> - 2005-01-09 16:55:26
|
Author: phd
Date: 2005-01-09 16:55:21 +0000 (Sun, 09 Jan 2005)
New Revision: 526
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged patch from revision 525: a lot of minor improvements and bug fixes
in date/time validators and tests. Added tests for MXDateTimeValidator.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-09 16:54:03 UTC (rev 525)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-09 16:55:21 UTC (rev 526)
@@ -46,9 +46,12 @@
default_datetime_implementation = None
__all__ = ["datetime_available", "mxdatetime_available",
- "DATETIME_IMPLEMENTATION", "MXDATETIME_IMPLEMENTATION",
"default_datetime_implementation"
]
+if datetime_available:
+ __all__.append("DATETIME_IMPLEMENTATION")
+if mxdatetime_available:
+ __all__.append("MXDATETIME_IMPLEMENTATION")
########################################
## Columns
@@ -658,82 +661,85 @@
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)
+if datetime_available:
+ 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):
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, (datetime.date, datetime.datetime)):
+ return value
+ if mxdatetime_available and isinstance(value, DateTimeType):
+ # convert mxDateTime instance to datetime
if ("%H" in self.format) or ("%T" in self.format):
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" % \
+ 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" % \
+ (self.format, self.name, type(value)), value, state)
+ secs = time.mktime(stime)
+ return datetime.datetime.fromtimestamp(secs)
+
+if mxdatetime_available:
+ 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)
- 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"):
+ 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.datetime):
return DateTime.DateTime(value.year, value.month, value.day,
value.hour, value.minute, value.second)
- else:
+ elif isinstance(value, datetime.date):
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)
+ 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" % \
+ (self.format, self.name, type(value)), value, state)
+ return 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'
def __init__(self, **kw):
+ datetimeFormat = popKey(kw, 'datetimeFormat')
+ if datetimeFormat: self.datetimeFormat = datetimeFormat
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)
+ if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ validatorClass = DateTimeValidator
+ elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ validatorClass = MXDateTimeValidator
+ return validatorClass(name=self.name, format=self.datetimeFormat)
def _mysqlType(self):
return 'DATETIME'
@@ -757,20 +763,22 @@
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'
def __init__(self, **kw):
+ dateFormat = popKey(kw, 'dateFormat')
+ if dateFormat: self.dateFormat = dateFormat
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)
+ if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ validatorClass = DateTimeValidator
+ elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ validatorClass = MXDateTimeValidator
+ return validatorClass(name=self.name, format=self.dateFormat)
def _mysqlType(self):
return 'DATE'
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-09 16:54:03 UTC (rev 525)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2005-01-09 16:55:21 UTC (rev 526)
@@ -17,6 +17,7 @@
from SQLObjectTest import *
from sqlobject import *
+from sqlobject import col
from sqlobject.include import validators
from sqlobject import classregistry
if default_datetime_implementation == DATETIME_IMPLEMENTATION:
@@ -1292,23 +1293,57 @@
## Date/time columns
########################################
-class DateTime1(SQLObject):
- col1 = DateCol()
- col2 = DateTimeCol()
+if datetime_available:
+ col.default_datetime_implementation = DATETIME_IMPLEMENTATION
+ from datetime import date, datetime
-class DateTimeTest(SQLObjectTest):
+ class DateTime1(SQLObject):
+ col1 = DateCol()
+ col2 = DateTimeCol()
- classes = [DateTime1]
+ class DateTimeTest1(SQLObjectTest):
- def testNow(self):
- _now = now()
- dt1 = DateTime1(col1=_now, col2=_now)
+ classes = [DateTime1]
- 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)
+ def testDateTime(self):
+ _now = now()
+ dt1 = DateTime1(col1=_now, col2=_now)
+ date_type = date
+ datetime_type = datetime
+ self.assertEqual(type(dt1.col1), date_type)
+ self.assertEqual(type(dt1.col2), datetime_type)
+
+ today_str = _now.strftime("%Y-%m-%d")
+ now_str = _now.strftime("%Y-%m-%d %T")
+ self.assertEqual(str(dt1.col1), today_str)
+ self.assertEqual(str(dt1.col2), now_str)
+
+if mxdatetime_available:
+ col.default_datetime_implementation = MXDATETIME_IMPLEMENTATION
+
+ class DateTime2(SQLObject):
+ col1 = DateCol()
+ col2 = DateTimeCol()
+
+ class DateTimeTest2(SQLObjectTest):
+
+ classes = [DateTime2]
+
+ def testMxDateTime(self):
+ _now = now()
+ dt2 = DateTime2(col1=_now, col2=_now)
+
+ date_type = col.DateTimeType
+ datetime_type = col.DateTimeType
+ self.assertEqual(type(dt2.col1), date_type)
+ self.assertEqual(type(dt2.col2), datetime_type)
+
+ today_str = _now.strftime("%Y-%m-%d 00:00:00.00")
+ now_str = _now.strftime("%Y-%m-%d %T.00")
+ self.assertEqual(str(dt2.col1), today_str)
+ self.assertEqual(str(dt2.col2), now_str)
+
########################################
## Run from command-line:
########################################
|
|
From: <sub...@co...> - 2005-01-09 16:54:13
|
Author: phd
Date: 2005-01-09 16:54:03 +0000 (Sun, 09 Jan 2005)
New Revision: 525
Modified:
trunk/SQLObject/sqlobject/col.py
trunk/SQLObject/tests/test_sqlobject.py
Log:
A lot of minor improvements and bug fixes in date/time validators and tests.
Added tests for MXDateTimeValidator.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-09 11:38:33 UTC (rev 524)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-09 16:54:03 UTC (rev 525)
@@ -46,9 +46,12 @@
default_datetime_implementation = None
__all__ = ["datetime_available", "mxdatetime_available",
- "DATETIME_IMPLEMENTATION", "MXDATETIME_IMPLEMENTATION",
"default_datetime_implementation"
]
+if datetime_available:
+ __all__.append("DATETIME_IMPLEMENTATION")
+if mxdatetime_available:
+ __all__.append("MXDATETIME_IMPLEMENTATION")
########################################
## Columns
@@ -658,82 +661,85 @@
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)
+if datetime_available:
+ 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):
+ def toPython(self, value, state):
+ if value is None:
+ return None
+ if isinstance(value, (datetime.date, datetime.datetime)):
+ return value
+ if mxdatetime_available and isinstance(value, DateTimeType):
+ # convert mxDateTime instance to datetime
if ("%H" in self.format) or ("%T" in self.format):
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" % \
+ 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" % \
+ (self.format, self.name, type(value)), value, state)
+ secs = time.mktime(stime)
+ return datetime.datetime.fromtimestamp(secs)
+
+if mxdatetime_available:
+ 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)
- 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"):
+ 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.datetime):
return DateTime.DateTime(value.year, value.month, value.day,
value.hour, value.minute, value.second)
- else:
+ elif isinstance(value, datetime.date):
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)
+ 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" % \
+ (self.format, self.name, type(value)), value, state)
+ return 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'
def __init__(self, **kw):
+ datetimeFormat = popKey(kw, 'datetimeFormat')
+ if datetimeFormat: self.datetimeFormat = datetimeFormat
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)
+ if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ validatorClass = DateTimeValidator
+ elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ validatorClass = MXDateTimeValidator
+ return validatorClass(name=self.name, format=self.datetimeFormat)
def _mysqlType(self):
return 'DATETIME'
@@ -757,20 +763,22 @@
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'
def __init__(self, **kw):
+ dateFormat = popKey(kw, 'dateFormat')
+ if dateFormat: self.dateFormat = dateFormat
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)
+ if default_datetime_implementation == DATETIME_IMPLEMENTATION:
+ validatorClass = DateTimeValidator
+ elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
+ validatorClass = MXDateTimeValidator
+ return validatorClass(name=self.name, format=self.dateFormat)
def _mysqlType(self):
return 'DATE'
Modified: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2005-01-09 11:38:33 UTC (rev 524)
+++ trunk/SQLObject/tests/test_sqlobject.py 2005-01-09 16:54:03 UTC (rev 525)
@@ -17,6 +17,7 @@
from SQLObjectTest import *
from sqlobject import *
+from sqlobject import col
from sqlobject.include import validators
from sqlobject import classregistry
if default_datetime_implementation == DATETIME_IMPLEMENTATION:
@@ -1292,23 +1293,57 @@
## Date/time columns
########################################
-class DateTime1(SQLObject):
- col1 = DateCol()
- col2 = DateTimeCol()
+if datetime_available:
+ col.default_datetime_implementation = DATETIME_IMPLEMENTATION
+ from datetime import date, datetime
-class DateTimeTest(SQLObjectTest):
+ class DateTime1(SQLObject):
+ col1 = DateCol()
+ col2 = DateTimeCol()
- classes = [DateTime1]
+ class DateTimeTest1(SQLObjectTest):
- def testNow(self):
- _now = now()
- dt1 = DateTime1(col1=_now, col2=_now)
+ classes = [DateTime1]
- 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)
+ def testDateTime(self):
+ _now = now()
+ dt1 = DateTime1(col1=_now, col2=_now)
+ date_type = date
+ datetime_type = datetime
+ self.assertEqual(type(dt1.col1), date_type)
+ self.assertEqual(type(dt1.col2), datetime_type)
+
+ today_str = _now.strftime("%Y-%m-%d")
+ now_str = _now.strftime("%Y-%m-%d %T")
+ self.assertEqual(str(dt1.col1), today_str)
+ self.assertEqual(str(dt1.col2), now_str)
+
+if mxdatetime_available:
+ col.default_datetime_implementation = MXDATETIME_IMPLEMENTATION
+
+ class DateTime2(SQLObject):
+ col1 = DateCol()
+ col2 = DateTimeCol()
+
+ class DateTimeTest2(SQLObjectTest):
+
+ classes = [DateTime2]
+
+ def testMxDateTime(self):
+ _now = now()
+ dt2 = DateTime2(col1=_now, col2=_now)
+
+ date_type = col.DateTimeType
+ datetime_type = col.DateTimeType
+ self.assertEqual(type(dt2.col1), date_type)
+ self.assertEqual(type(dt2.col2), datetime_type)
+
+ today_str = _now.strftime("%Y-%m-%d 00:00:00.00")
+ now_str = _now.strftime("%Y-%m-%d %T.00")
+ self.assertEqual(str(dt2.col1), today_str)
+ self.assertEqual(str(dt2.col2), now_str)
+
########################################
## Run from command-line:
########################################
|
|
From: <sub...@co...> - 2005-01-09 11:38:36
|
Author: phd
Date: 2005-01-09 11:38:33 +0000 (Sun, 09 Jan 2005)
New Revision: 524
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
Log:
Merged patch from revision 523: DateTime always has 'hour' - test for date by or in format.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-09 11:37:24 UTC (rev 523)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-09 11:38:33 UTC (rev 524)
@@ -676,7 +676,7 @@
return value
if mxdatetime_available: # convert mxDateTime instance to datetime
if isinstance(value, DateTimeType):
- if hasattr(value, "hour"):
+ if ("%H" in self.format) or ("%T" in self.format):
return datetime.datetime(value.year, value.month, value.day,
value.hour, value.minute, value.second)
else:
|
|
From: <sub...@co...> - 2005-01-09 11:37:28
|
Author: phd
Date: 2005-01-09 11:37:24 +0000 (Sun, 09 Jan 2005)
New Revision: 523
Modified:
trunk/SQLObject/sqlobject/col.py
Log:
DateTime always has 'hour' - test for date by or in format.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-09 11:28:46 UTC (rev 522)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-09 11:37:24 UTC (rev 523)
@@ -676,7 +676,7 @@
return value
if mxdatetime_available: # convert mxDateTime instance to datetime
if isinstance(value, DateTimeType):
- if hasattr(value, "hour"):
+ if ("%H" in self.format) or ("%T" in self.format):
return datetime.datetime(value.year, value.month, value.day,
value.hour, value.minute, value.second)
else:
|
|
From: <sub...@co...> - 2005-01-09 11:28:53
|
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:
########################################
|
|
From: <sub...@co...> - 2005-01-09 11:27:52
|
Author: phd
Date: 2005-01-09 11:27:46 +0000 (Sun, 09 Jan 2005)
New Revision: 521
Modified:
trunk/SQLObject/sqlobject/col.py
trunk/SQLObject/tests/test_sqlobject.py
Log:
Added date/time validators, converters and tests.
Modified: trunk/SQLObject/sqlobject/col.py
===================================================================
--- trunk/SQLObject/sqlobject/col.py 2005-01-07 11:20:49 UTC (rev 520)
+++ trunk/SQLObject/sqlobject/col.py 2005-01-09 11:27:46 UTC (rev 521)
@@ -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: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2005-01-07 11:20:49 UTC (rev 520)
+++ trunk/SQLObject/tests/test_sqlobject.py 2005-01-09 11:27:46 UTC (rev 521)
@@ -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:
########################################
|
|
From: <sub...@co...> - 2005-01-07 11:20:53
|
Author: phd
Date: 2005-01-07 11:20:49 +0000 (Fri, 07 Jan 2005)
New Revision: 520
Modified:
home/phd/SQLObject/inheritance/sqlobject/col.py
Log:
Merged patch from rev 519: changed IntValidator.toPython - it now calls int() to convert non-integer value.
Modified: home/phd/SQLObject/inheritance/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-07 11:16:34 UTC (rev 519)
+++ home/phd/SQLObject/inheritance/sqlobject/col.py 2005-01-07 11:20:49 UTC (rev 520)
@@ -386,10 +386,16 @@
def toPython(self, value, state):
if value is None:
return None
- if not isinstance(value, (int, long, sqlbuilder.SQLExpression)):
+ if isinstance(value, (int, long, sqlbuilder.SQLExpression)):
+ return value
+ try:
+ try:
+ return int(value)
+ except OverflowError: # for Python 2.2
+ return long(value)
+ except:
raise validators.InvalidField("expected an int in the IntCol '%s', got %s instead" % \
(self.name, type(value)), value, state)
- return value
class SOIntCol(SOCol):
validatorClass = IntValidator # can be overriden in descendants
|