sqlobject-cvs Mailing List for SQLObject (Page 110)
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...> - 2007-01-04 20:39:56
|
Author: novalis
Date: 2007-01-04 13:39:49 -0700 (Thu, 04 Jan 2007)
New Revision: 2174
Modified:
SQLObject/trunk/sqlobject/versioning/test/test_version.py
Log:
clean up before tests
Modified: SQLObject/trunk/sqlobject/versioning/test/test_version.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/test/test_version.py 2007-01-04 19:44:56 UTC (rev 2173)
+++ SQLObject/trunk/sqlobject/versioning/test/test_version.py 2007-01-04 20:39:49 UTC (rev 2174)
@@ -8,33 +8,30 @@
def setup():
- setupClass(MyClass)
- setupClass(Base)
- setupClass(Child)
- setupClass(Government)
- setupClass(Monarchy)
- setupClass(VChild)
- setupClass(HasForeign)
-
+ for cls in [MyClass, Base, Child, Government, Monarchy, VChild, HasForeign]:
+ setupClass(cls)
+ if hasattr(cls, 'versions'):
+ for version in cls.versions.versionClass.select():
+ version.destroySelf()
+
class MyClass(SQLObject):
- name = StringCol()
- versions = Versioning()
+ name = StringCol()
+ versions = Versioning()
class Base(InheritableSQLObject):
- name = StringCol()
- value = IntCol(default=0)
- versions = Versioning()
+ name = StringCol()
+ value = IntCol(default=0)
+ versions = Versioning()
class Child(Base):
- toy = StringCol()
+ toy = StringCol()
-
class Government(InheritableSQLObject):
- name = StringCol()
+ name = StringCol()
class Monarchy(Government):
- monarch = StringCol()
- versions = Versioning()
+ monarch = StringCol()
+ versions = Versioning()
class VChild(Base):
weapon = StringCol()
|
|
From: <sub...@co...> - 2007-01-04 19:45:09
|
Author: novalis
Date: 2007-01-04 12:44:56 -0700 (Thu, 04 Jan 2007)
New Revision: 2173
Modified:
SQLObject/trunk/sqlobject/versioning/__init__.py
SQLObject/trunk/sqlobject/versioning/test/test_version.py
Log:
now versions work with foreign keys
Modified: SQLObject/trunk/sqlobject/versioning/__init__.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/__init__.py 2007-01-04 18:52:37 UTC (rev 2172)
+++ SQLObject/trunk/sqlobject/versioning/__init__.py 2007-01-04 19:44:56 UTC (rev 2173)
@@ -11,7 +11,9 @@
def getColumns(columns, cls):
for column, defi in cls.sqlmeta.columnDefinitions.items():
- columns[column] = defi.__class__()
+ if column.endswith("ID") and isinstance(defi, ForeignKey):
+ column = column[:-2]
+ columns[column] = defi.__class__(**defi._kw)
#ascend heirarchy
if cls.sqlmeta.parentClass:
Modified: SQLObject/trunk/sqlobject/versioning/test/test_version.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/test/test_version.py 2007-01-04 18:52:37 UTC (rev 2172)
+++ SQLObject/trunk/sqlobject/versioning/test/test_version.py 2007-01-04 19:44:56 UTC (rev 2173)
@@ -14,6 +14,7 @@
setupClass(Government)
setupClass(Monarchy)
setupClass(VChild)
+ setupClass(HasForeign)
class MyClass(SQLObject):
name = StringCol()
@@ -39,6 +40,10 @@
weapon = StringCol()
versions = Versioning()
+class HasForeign(SQLObject):
+ foreign = ForeignKey("Base")
+ versions = Versioning()
+
def test_versioning():
#the simple case
@@ -114,4 +119,10 @@
assert base.versions[0].getChangedFields() == ['Name']
assert sorted(base.versions[1].getChangedFields()) == ['Name', 'Value']
-
+def test_foreign_keys():
+ setup()
+ base1 = Base(name='first', value=1)
+ base2 = Base(name='first', value=1)
+ has_foreign = HasForeign(foreign = base1)
+ has_foreign.foreign = base2
+ assert has_foreign.versions[0].foreign == base1
|
|
From: <sub...@co...> - 2007-01-04 18:52:47
|
Author: novalis
Date: 2007-01-04 11:52:37 -0700 (Thu, 04 Jan 2007)
New Revision: 2172
Modified:
SQLObject/trunk/sqlobject/versioning/__init__.py
SQLObject/trunk/sqlobject/versioning/test/test_version.py
Log:
Added nextVersion and getChangedFields to Versioning
Modified: SQLObject/trunk/sqlobject/versioning/__init__.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/__init__.py 2006-12-29 15:34:08 UTC (rev 2171)
+++ SQLObject/trunk/sqlobject/versioning/__init__.py 2007-01-04 18:52:37 UTC (rev 2172)
@@ -17,10 +17,29 @@
if cls.sqlmeta.parentClass:
getColumns(columns, cls.sqlmeta.parentClass)
+#these two are methods for a versionable object
+def _nextVersion(self):
+ version = self.select(AND(self.q.masterID == self.masterID, self.q.id > self.id), limit=1, orderBy=self.q.id)
+ if version.count():
+ return version[0]
+ else:
+ return self.master
+def _getChangedFields(self):
+ next = self.nextVersion()
+ columns = self.__class__.sqlmeta.columns
+ fields = []
+ for column in columns:
+ if column not in ["dateArchived", "id", "masterID"]:
+ if getattr(self, column) != getattr(next, column):
+ fields.append(column.title())
+
+ return fields
+
class Versioning(object):
def __init__(self):
pass
+
def __addtoclass__(self, soClass, name):
self.name = name
self.soClass = soClass
@@ -31,16 +50,19 @@
events.RowUpdateSignal)
def createVersionTable(self, cls, conn):
- columns = {'dateArchived': DateTimeCol(default=datetime.now),
- 'masterID': IntCol(),
- 'masterClass' : self.soClass,
- }
+ attrs = {'dateArchived': DateTimeCol(default=datetime.now),
+ 'master': ForeignKey(self.soClass.__name__),
+ 'masterClass' : self.soClass,
+ 'nextVersion' : _nextVersion,
+ 'getChangedFields' : _getChangedFields,
+ '_connection' : conn,
+ }
- getColumns (columns, self.soClass)
+ getColumns (attrs, self.soClass)
self.versionClass = type(self.soClass.__name__+'Versions',
(Version,),
- columns)
+ attrs)
self.versionClass.createTable(connection=conn)
Modified: SQLObject/trunk/sqlobject/versioning/test/test_version.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/test/test_version.py 2006-12-29 15:34:08 UTC (rev 2171)
+++ SQLObject/trunk/sqlobject/versioning/test/test_version.py 2007-01-04 18:52:37 UTC (rev 2172)
@@ -21,6 +21,7 @@
class Base(InheritableSQLObject):
name = StringCol()
+ value = IntCol(default=0)
versions = Versioning()
class Child(Base):
@@ -95,3 +96,22 @@
monarchy.versions[0].restore()
assert monarchy.name == "USA"
assert monarchy.monarch == "Emperor Norton I"
+
+def test_next():
+ setup()
+ base = Base(name='first', value=1)
+ base.set(name='second')
+ base.set(name='third', value=2)
+ version = base.versions[0]
+ assert version.nextVersion() == base.versions[1]
+ assert version.nextVersion().nextVersion() == base
+
+def test_get_changed():
+ setup()
+ base = Base(name='first', value=1)
+ base.set(name='second')
+ base.set(name='third', value=2)
+ assert base.versions[0].getChangedFields() == ['Name']
+ assert sorted(base.versions[1].getChangedFields()) == ['Name', 'Value']
+
+
|
|
From: <sub...@co...> - 2006-12-29 15:34:12
|
Author: phd
Date: 2006-12-29 08:34:08 -0700 (Fri, 29 Dec 2006)
New Revision: 2171
Added:
home/phd/SQLObject/paramstyles/sqlobject/versioning/
home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/versioning/test/
home/phd/SQLObject/paramstyles/sqlobject/versioning/test/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py
Removed:
home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/versioning/test/
home/phd/SQLObject/paramstyles/sqlobject/versioning/test/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py
Modified:
home/phd/SQLObject/paramstyles/setup.py
home/phd/SQLObject/paramstyles/sqlobject/inheritance/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
Log:
Merged patches from the revisions 2162:2170 from the trunk
Modified: home/phd/SQLObject/paramstyles/setup.py
===================================================================
--- home/phd/SQLObject/paramstyles/setup.py 2006-12-29 15:32:16 UTC (rev 2170)
+++ home/phd/SQLObject/paramstyles/setup.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -11,7 +11,7 @@
subpackages = ['firebird', 'include', 'include.pydispatch', 'inheritance',
'manager', 'maxdb', 'mssql', 'mysql', 'postgres', 'sqlite',
- 'sybase', 'util']
+ 'sybase', 'util', 'versioning']
import sys
# patch distutils if it can't cope with the "classifiers" keyword
Modified: home/phd/SQLObject/paramstyles/sqlobject/inheritance/__init__.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/inheritance/__init__.py 2006-12-29 15:32:16 UTC (rev 2170)
+++ home/phd/SQLObject/paramstyles/sqlobject/inheritance/__init__.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -164,7 +164,22 @@
delJoin = classmethod(delJoin)
+ def getAllColumns(sqlmeta):
+ columns = sqlmeta.columns.copy()
+ sm = sqlmeta
+ while sm.parentClass:
+ columns.update(sm.parentClass.sqlmeta.columns)
+ sm = sm.parentClass.sqlmeta
+ return columns
+ def asDict(sqlmeta):
+ result = {}
+ for key in sqlmeta.getAllColumns():
+ result[key] = getattr(sqlmeta.instance, key)
+ result['id'] = sqlmeta.instance.id
+ return result
+
+
class InheritableSQLObject(SQLObject):
sqlmeta = InheritableSQLMeta
Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-29 15:32:16 UTC (rev 2170)
+++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -78,7 +78,19 @@
conn.autocommit(auto)
def _executeRetry(self, conn, cursor, query):
- while 1:
+ # When a server connection is lost and a query is attempted, most of
+ # the time the query will raise a SERVER_LOST exception, then at the
+ # second attempt to execute it, the mysql lib will reconnect and
+ # succeed. However is a few cases, the first attempt raises the
+ # SERVER_GONE exception, the second attempt the SERVER_LOST exception
+ # and only the third succeeds. Thus the 3 in the loop count.
+ # If it doesn't reconnect even after 3 attempts, while the database is
+ # up and running, it is because a 5.0.x (or newer) server is used
+ # which no longer permits autoreconnects by default. In their case a
+ # reconnect flag must be set when making the connection to indicate
+ # that autoreconnecting is desired and the python-mysqldb module
+ # doesn't set this flag.
+ for c in range(0, 3):
try:
if self.need_unicode:
# For MysqlDB 1.2.1 and later, we go
@@ -88,7 +100,9 @@
else:
return DBAPI._executeRetry(self, conn, cursor, query)
except MySQLdb.OperationalError, e:
- if e.args[0] == 2013: # SERVER_LOST error
+ if e.args[0] in (2006, 2013): # SERVER_GONE or SERVER_LOST error
+ if c == 2:
+ raise OperationalError(ErrorMessage(e))
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
Copied: home/phd/SQLObject/paramstyles/sqlobject/versioning (from rev 2168, SQLObject/trunk/sqlobject/versioning)
Deleted: home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/__init__.py 2006-12-29 15:19:00 UTC (rev 2168)
+++ home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -1,65 +0,0 @@
-from sqlobject import *
-from datetime import datetime
-
-class Version(SQLObject):
- def restore(self):
- values = self.sqlmeta.asDict()
- del values['id']
- del values['masterID']
- del values['dateArchived']
- self.masterClass.get(self.masterID).set(**values)
-
-def getColumns(columns, cls):
- for column, defi in cls.sqlmeta.columnDefinitions.items():
- columns[column] = defi.__class__()
-
- #ascend heirarchy
- if cls.sqlmeta.parentClass:
- getColumns(columns, cls.sqlmeta.parentClass)
-
-
-class Versioning(object):
- def __init__(self):
- pass
- def __addtoclass__(self, soClass, name):
- self.name = name
- self.soClass = soClass
- self.versionClass = None
- events.listen(self.createTable,
- soClass, events.CreateTableSignal)
- events.listen(self.rowUpdate, soClass,
- events.RowUpdateSignal)
-
- def createVersionTable(self, cls, conn):
- columns = {'dateArchived': DateTimeCol(default=datetime.now),
- 'masterID': IntCol(),
- 'masterClass' : self.soClass,
- }
-
- getColumns (columns, self.soClass)
-
- self.versionClass = type(self.soClass.__name__+'Versions',
- (Version,),
- columns)
-
- self.versionClass.createTable(connection=conn)
-
- def createTable(self, soClass, connection, extra_sql, post_funcs):
- assert soClass is self.soClass
- post_funcs.append(self.createVersionTable)
-
- def rowUpdate(self, instance, kwargs):
- if instance.childName and instance.childName != self.soClass.__name__:
- return #if you want your child class versioned, version it.
-
- values = instance.sqlmeta.asDict()
- del values['id']
- values['masterID'] = instance.id
- self.versionClass(connection=instance._connection, **values)
-
- def __get__(self, obj, type=None):
- if obj is None:
- return self
- return self.versionClass.select(
- self.versionClass.q.masterID==obj.id, connection=obj._connection)
-
Copied: home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py (from rev 2168, SQLObject/trunk/sqlobject/versioning/__init__.py)
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py (rev 0)
+++ home/phd/SQLObject/paramstyles/sqlobject/versioning/__init__.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -0,0 +1,65 @@
+from sqlobject import *
+from datetime import datetime
+
+class Version(SQLObject):
+ def restore(self):
+ values = self.sqlmeta.asDict()
+ del values['id']
+ del values['masterID']
+ del values['dateArchived']
+ self.masterClass.get(self.masterID).set(**values)
+
+def getColumns(columns, cls):
+ for column, defi in cls.sqlmeta.columnDefinitions.items():
+ columns[column] = defi.__class__()
+
+ #ascend heirarchy
+ if cls.sqlmeta.parentClass:
+ getColumns(columns, cls.sqlmeta.parentClass)
+
+
+class Versioning(object):
+ def __init__(self):
+ pass
+ def __addtoclass__(self, soClass, name):
+ self.name = name
+ self.soClass = soClass
+ self.versionClass = None
+ events.listen(self.createTable,
+ soClass, events.CreateTableSignal)
+ events.listen(self.rowUpdate, soClass,
+ events.RowUpdateSignal)
+
+ def createVersionTable(self, cls, conn):
+ columns = {'dateArchived': DateTimeCol(default=datetime.now),
+ 'masterID': IntCol(),
+ 'masterClass' : self.soClass,
+ }
+
+ getColumns (columns, self.soClass)
+
+ self.versionClass = type(self.soClass.__name__+'Versions',
+ (Version,),
+ columns)
+
+ self.versionClass.createTable(connection=conn)
+
+ def createTable(self, soClass, connection, extra_sql, post_funcs):
+ assert soClass is self.soClass
+ post_funcs.append(self.createVersionTable)
+
+ def rowUpdate(self, instance, kwargs):
+ if instance.childName and instance.childName != self.soClass.__name__:
+ return #if you want your child class versioned, version it.
+
+ values = instance.sqlmeta.asDict()
+ del values['id']
+ values['masterID'] = instance.id
+ self.versionClass(connection=instance._connection, **values)
+
+ def __get__(self, obj, type=None):
+ if obj is None:
+ return self
+ return self.versionClass.select(
+ self.versionClass.q.masterID==obj.id, connection=obj._connection)
+
Copied: home/phd/SQLObject/paramstyles/sqlobject/versioning/test (from rev 2168, SQLObject/trunk/sqlobject/versioning/test)
Deleted: home/phd/SQLObject/paramstyles/sqlobject/versioning/test/__init__.py
===================================================================
Copied: home/phd/SQLObject/paramstyles/sqlobject/versioning/test/__init__.py (from rev 2168, SQLObject/trunk/sqlobject/versioning/test/__init__.py)
===================================================================
Deleted: home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/test/test_version.py 2006-12-29 15:19:00 UTC (rev 2168)
+++ home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -1,97 +0,0 @@
-from py.test import raises
-from sqlobject import *
-from sqlobject.tests.dbtest import *
-from sqlobject.inheritance import InheritableSQLObject
-from sqlobject.versioning import Versioning
-
-from datetime import datetime
-
-
-def setup():
- setupClass(MyClass)
- setupClass(Base)
- setupClass(Child)
- setupClass(Government)
- setupClass(Monarchy)
- setupClass(VChild)
-
-class MyClass(SQLObject):
- name = StringCol()
- versions = Versioning()
-
-class Base(InheritableSQLObject):
- name = StringCol()
- versions = Versioning()
-
-class Child(Base):
- toy = StringCol()
-
-
-class Government(InheritableSQLObject):
- name = StringCol()
-
-class Monarchy(Government):
- monarch = StringCol()
- versions = Versioning()
-
-class VChild(Base):
- weapon = StringCol()
- versions = Versioning()
-
-def test_versioning():
-
- #the simple case
- setup()
- mc = MyClass(name='fleem')
- mc.set(name='morx')
- assert len(list(mc.versions)) == 1
- assert mc.versions[0].name == "fleem"
-
- assert len(list(MyClass.select())) == 1
-
-def test_inheritable_versioning():
- setup()
-
- #base versioned, child unversioned
- base = Base(name='fleem')
- base.set(name='morx')
- assert len(list(base.versions)) == 1
- assert base.versions[0].name == "fleem"
- assert len(list(Base.select())) == 1
-
- child = Child(name='child', toy='nintendo')
- child.set(name='teenager', toy='guitar')
- assert len(list(child.versions)) == 0
-
-
- #child versioned, base unversioned
- government = Government(name='canada')
- assert not hasattr(government, 'versions')
-
- monarchy = Monarchy(name='UK', monarch='king george iv')
- monarchy.set(name='queen elisabeth ii')
- assert len(list(monarchy.versions)) == 1
- assert monarchy.versions[0].name == "UK"
- assert len(list(Monarchy.select())) == 1
-
- #both parent and child versioned
- num_base_versions = len(list(base.versions))
- vchild = VChild(name='kid', weapon='slingshot')
- vchild.set(name='toon', weapon='dynamite')
- assert len(list(base.versions)) == num_base_versions
- assert len(list(vchild.versions)) == 1
-
-def test_restore():
- setup()
- base = Base(name='fleem')
- base.set(name='morx')
- assert base.name == "morx"
- base.versions[0].restore()
- assert base.name == "fleem"
-
- monarchy = Monarchy(name='USA', monarch='Emperor Norton I')
- monarchy.set(name='morx')
- assert monarchy.name == "morx"
- monarchy.versions[0].restore()
- assert monarchy.name == "USA"
- assert monarchy.monarch == "Emperor Norton I"
Copied: home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py (from rev 2168, SQLObject/trunk/sqlobject/versioning/test/test_version.py)
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py (rev 0)
+++ home/phd/SQLObject/paramstyles/sqlobject/versioning/test/test_version.py 2006-12-29 15:34:08 UTC (rev 2171)
@@ -0,0 +1,97 @@
+from py.test import raises
+from sqlobject import *
+from sqlobject.tests.dbtest import *
+from sqlobject.inheritance import InheritableSQLObject
+from sqlobject.versioning import Versioning
+
+from datetime import datetime
+
+
+def setup():
+ setupClass(MyClass)
+ setupClass(Base)
+ setupClass(Child)
+ setupClass(Government)
+ setupClass(Monarchy)
+ setupClass(VChild)
+
+class MyClass(SQLObject):
+ name = StringCol()
+ versions = Versioning()
+
+class Base(InheritableSQLObject):
+ name = StringCol()
+ versions = Versioning()
+
+class Child(Base):
+ toy = StringCol()
+
+
+class Government(InheritableSQLObject):
+ name = StringCol()
+
+class Monarchy(Government):
+ monarch = StringCol()
+ versions = Versioning()
+
+class VChild(Base):
+ weapon = StringCol()
+ versions = Versioning()
+
+def test_versioning():
+
+ #the simple case
+ setup()
+ mc = MyClass(name='fleem')
+ mc.set(name='morx')
+ assert len(list(mc.versions)) == 1
+ assert mc.versions[0].name == "fleem"
+
+ assert len(list(MyClass.select())) == 1
+
+def test_inheritable_versioning():
+ setup()
+
+ #base versioned, child unversioned
+ base = Base(name='fleem')
+ base.set(name='morx')
+ assert len(list(base.versions)) == 1
+ assert base.versions[0].name == "fleem"
+ assert len(list(Base.select())) == 1
+
+ child = Child(name='child', toy='nintendo')
+ child.set(name='teenager', toy='guitar')
+ assert len(list(child.versions)) == 0
+
+
+ #child versioned, base unversioned
+ government = Government(name='canada')
+ assert not hasattr(government, 'versions')
+
+ monarchy = Monarchy(name='UK', monarch='king george iv')
+ monarchy.set(name='queen elisabeth ii')
+ assert len(list(monarchy.versions)) == 1
+ assert monarchy.versions[0].name == "UK"
+ assert len(list(Monarchy.select())) == 1
+
+ #both parent and child versioned
+ num_base_versions = len(list(base.versions))
+ vchild = VChild(name='kid', weapon='slingshot')
+ vchild.set(name='toon', weapon='dynamite')
+ assert len(list(base.versions)) == num_base_versions
+ assert len(list(vchild.versions)) == 1
+
+def test_restore():
+ setup()
+ base = Base(name='fleem')
+ base.set(name='morx')
+ assert base.name == "morx"
+ base.versions[0].restore()
+ assert base.name == "fleem"
+
+ monarchy = Monarchy(name='USA', monarch='Emperor Norton I')
+ monarchy.set(name='morx')
+ assert monarchy.name == "morx"
+ monarchy.versions[0].restore()
+ assert monarchy.name == "USA"
+ assert monarchy.monarch == "Emperor Norton I"
|
|
From: <sub...@co...> - 2006-12-29 15:32:19
|
Author: phd Date: 2006-12-29 08:32:16 -0700 (Fri, 29 Dec 2006) New Revision: 2170 Modified: SQLObject/docs/Authors.txt SQLObject/docs/News.txt SQLObject/docs/Versioning.txt SQLObject/docs/index.txt SQLObject/docs/rebuild Log: Added Versioning. Modified: SQLObject/docs/Authors.txt =================================================================== --- SQLObject/docs/Authors.txt 2006-12-29 15:22:20 UTC (rev 2169) +++ SQLObject/docs/Authors.txt 2006-12-29 15:32:16 UTC (rev 2170) @@ -19,4 +19,5 @@ * Runar Petursson <grunar at gmail.com> * J Paulo Fernandes Farias <jpaulofarias at gmail.com> * Shahms King <shahms at shahms.com> +* David Turner, The Open Planning Project * Oleg Broytmann <ph...@ph...> Modified: SQLObject/docs/News.txt =================================================================== --- SQLObject/docs/News.txt 2006-12-29 15:22:20 UTC (rev 2169) +++ SQLObject/docs/News.txt 2006-12-29 15:32:16 UTC (rev 2170) @@ -30,6 +30,10 @@ delColumn() is implemented by creating a new table without the column, copying all data, dropping the original table and renaming the new table. +* Versioning_. + +.. _Versioning: Versioning.html + Small Features -------------- Modified: SQLObject/docs/Versioning.txt =================================================================== --- SQLObject/docs/Versioning.txt 2006-12-29 15:22:20 UTC (rev 2169) +++ SQLObject/docs/Versioning.txt 2006-12-29 15:32:16 UTC (rev 2170) @@ -42,8 +42,10 @@ Inheritance ~~~~~~~~~~~ -There are three ways versioning can be used with inheritance: +There are three ways versioning can be used with inheritance_: +.. _inheritance: Inheritance.html + 1. Parent versioned, children unversioned:: class Base(InheritableSQLObject): Modified: SQLObject/docs/index.txt =================================================================== --- SQLObject/docs/index.txt 2006-12-29 15:22:20 UTC (rev 2169) +++ SQLObject/docs/index.txt 2006-12-29 15:32:16 UTC (rev 2170) @@ -19,10 +19,11 @@ * `News and updates <News.html>`_ * `Main SQLObject documentation <SQLObject.html>`_ +* `Frequently Asked Questions <FAQ.html>`_ * `sqlbuilder documentation <SQLBuilder.html>`_ * `sqlobject-admin documentation <sqlobject-admin.html>`_ -* `Frequently Asked Questions <FAQ.html>`_ * `Inheritance <Inheritance.html>`_ +* `Versioning <Versioning.html>`_ * `Developer Guide <DeveloperGuide.html>`_ * `Contributors <Authors.html>`_ Modified: SQLObject/docs/rebuild =================================================================== --- SQLObject/docs/rebuild 2006-12-29 15:22:20 UTC (rev 2169) +++ SQLObject/docs/rebuild 2006-12-29 15:32:16 UTC (rev 2170) @@ -6,7 +6,8 @@ export PYTHONPATH=$parent:$PYTHONPATH NORMAL="Authors DeveloperGuide FAQ Inheritance News SQLBuilder - SQLObject TODO web/index web/links web/repository web/community + SQLObject TODO Versioning + web/index web/links web/repository web/community index community sqlobject-admin" for NAME in $NORMAL ; do |
|
From: <sub...@co...> - 2006-12-29 15:22:26
|
Author: phd
Date: 2006-12-29 08:22:20 -0700 (Fri, 29 Dec 2006)
New Revision: 2169
Modified:
SQLObject/trunk/setup.py
Log:
Added versioning subpackage.
Modified: SQLObject/trunk/setup.py
===================================================================
--- SQLObject/trunk/setup.py 2006-12-29 15:19:00 UTC (rev 2168)
+++ SQLObject/trunk/setup.py 2006-12-29 15:22:20 UTC (rev 2169)
@@ -11,7 +11,7 @@
subpackages = ['firebird', 'include', 'include.pydispatch', 'inheritance',
'manager', 'maxdb', 'mysql', 'mssql', 'postgres', 'sqlite',
- 'sybase', 'util']
+ 'sybase', 'util', 'versioning']
import sys
# patch distutils if it can't cope with the "classifiers" keyword
|
|
From: <sub...@co...> - 2006-12-29 15:19:06
|
Author: phd Date: 2006-12-29 08:19:00 -0700 (Fri, 29 Dec 2006) New Revision: 2168 Modified: SQLObject/docs/News.txt Log: Another bugfix by Dan Pascu <da...@ag...> for MySQL errors 2006 and 2013 (SERVER_GONE, SERVER_LOST). Modified: SQLObject/docs/News.txt =================================================================== --- SQLObject/docs/News.txt 2006-12-29 15:18:17 UTC (rev 2167) +++ SQLObject/docs/News.txt 2006-12-29 15:19:00 UTC (rev 2168) @@ -125,7 +125,8 @@ * The reference loop between SQLObject and SQLObjectState eliminated using weak references. -* Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE). +* Another round of bugfixes for MySQL errors 2006 and 2013 (SERVER_GONE, + SERVER_LOST). SQLObject 0.7.3 =============== |
|
From: <sub...@co...> - 2006-12-29 15:18:20
|
Author: phd
Date: 2006-12-29 08:18:17 -0700 (Fri, 29 Dec 2006)
New Revision: 2167
Modified:
SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py
Log:
Another bugfix by Dan Pascu <da...@ag...> for MySQL errors 2006 and 2013 (SERVER_GONE, SERVER_LOST).
Modified: SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py 2006-12-29 15:17:40 UTC (rev 2166)
+++ SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py 2006-12-29 15:18:17 UTC (rev 2167)
@@ -78,7 +78,19 @@
conn.autocommit(auto)
def _executeRetry(self, conn, cursor, query):
- while 1:
+ # When a server connection is lost and a query is attempted, most of
+ # the time the query will raise a SERVER_LOST exception, then at the
+ # second attempt to execute it, the mysql lib will reconnect and
+ # succeed. However is a few cases, the first attempt raises the
+ # SERVER_GONE exception, the second attempt the SERVER_LOST exception
+ # and only the third succeeds. Thus the 3 in the loop count.
+ # If it doesn't reconnect even after 3 attempts, while the database is
+ # up and running, it is because a 5.0.x (or newer) server is used
+ # which no longer permits autoreconnects by default. In their case a
+ # reconnect flag must be set when making the connection to indicate
+ # that autoreconnecting is desired and the python-mysqldb module
+ # doesn't set this flag.
+ for c in range(0, 3):
try:
if self.need_unicode:
# For MysqlDB 1.2.1 and later, we go
@@ -88,7 +100,9 @@
else:
return cursor.execute(query)
except MySQLdb.OperationalError, e:
- if e.args[0] == 2013: # SERVER_LOST error
+ if e.args[0] in (2006, 2013): # SERVER_GONE or SERVER_LOST error
+ if c == 2:
+ raise OperationalError(ErrorMessage(e))
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2006-12-29 15:17:46
|
Author: phd
Date: 2006-12-29 08:17:40 -0700 (Fri, 29 Dec 2006)
New Revision: 2166
Modified:
SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
Log:
Another bugfix by Dan Pascu <da...@ag...> for MySQL errors 2006 and 2013 (SERVER_GONE, SERVER_LOST).
Modified: SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:55:44 UTC (rev 2165)
+++ SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2006-12-29 15:17:40 UTC (rev 2166)
@@ -78,7 +78,19 @@
conn.autocommit(auto)
def _executeRetry(self, conn, cursor, query):
- while 1:
+ # When a server connection is lost and a query is attempted, most of
+ # the time the query will raise a SERVER_LOST exception, then at the
+ # second attempt to execute it, the mysql lib will reconnect and
+ # succeed. However is a few cases, the first attempt raises the
+ # SERVER_GONE exception, the second attempt the SERVER_LOST exception
+ # and only the third succeeds. Thus the 3 in the loop count.
+ # If it doesn't reconnect even after 3 attempts, while the database is
+ # up and running, it is because a 5.0.x (or newer) server is used
+ # which no longer permits autoreconnects by default. In their case a
+ # reconnect flag must be set when making the connection to indicate
+ # that autoreconnecting is desired and the python-mysqldb module
+ # doesn't set this flag.
+ for c in range(0, 3):
try:
if self.need_unicode:
# For MysqlDB 1.2.1 and later, we go
@@ -88,7 +100,9 @@
else:
return cursor.execute(query)
except MySQLdb.OperationalError, e:
- if e.args[0] == 2013: # SERVER_LOST error
+ if e.args[0] in (2006, 2013): # SERVER_GONE or SERVER_LOST error
+ if c == 2:
+ raise OperationalError(ErrorMessage(e))
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2006-12-28 20:55:50
|
Author: novalis Date: 2006-12-28 13:55:44 -0700 (Thu, 28 Dec 2006) New Revision: 2165 Added: SQLObject/docs/Versioning.txt Log: fixed code samples Added: SQLObject/docs/Versioning.txt =================================================================== --- SQLObject/docs/Versioning.txt (rev 0) +++ SQLObject/docs/Versioning.txt 2006-12-28 20:55:44 UTC (rev 2165) @@ -0,0 +1,81 @@ +:Author: David Turner, The Open Planning Project + +Versioning +----------- + +Why +~~~ + +You have a table where rows can be altered, such as a table of wiki +pages. You want to retain a history of changes for auditing, backup, +or tracking purposes. + +You could write a decorator that stores old versions and manage all +access to this object through it. Or you could take advantage of the +event system in SQLObject 0.8+ and just catch row accesses to the +object. SQLObject's versioning module does this for you. And it even +works with inheritance! + +How +~~~ + +Here's how to set it up:: + + class MyClass(SQLObject): + name = StringCol() + versions = Versioning() + +To use it, just create an instance as usual:: + + mc = MyClass(name='fleem') + +Then make some changes and check out the results:: + + mc.set(name='morx') + assert mc.versions[0].name == 'fleem' + +You can also restore to a previous version:: + + mc.versions[0].restore() + assert mc.name == "fleem" + +Inheritance +~~~~~~~~~~~ + +There are three ways versioning can be used with inheritance: + +1. Parent versioned, children unversioned:: + + class Base(InheritableSQLObject): + name = StringCol() + versions = Versioning() + + class Child(Base): + toy = StringCol() + +In this case, when changes are made to an instance of Base, new +versions are created. But when changes are made to an instance of +Child, no new versions are created. + +2. Children versioned, parents unversioned. + +In this case, when changes are made to an instance of Child, new +versions are created. But when changes are made to an instance of +Base, no new versions are created. The version data for Child +contains all of the columns from child and from base, so that a full +restore is possible. + +3. Both children and parents versioned. + +In this case, changes to either Child or Base instances create new +versions, but in different tables. Child versions still contain all +Base data, and a change to a Child only creates a new Child version, not +a new Base version. + +Version Tables +~~~~~~~~~~~~~~ + +Versions are stored in a special table which is created when the table +for a versioned class is created. Version tables are not altered when +the main table is altered, so if you add a column to your main class, +you will need to manually add the column to your version table. |
|
From: <sub...@co...> - 2006-12-28 20:52:45
|
Author: novalis
Date: 2006-12-28 13:52:41 -0700 (Thu, 28 Dec 2006)
New Revision: 2164
Added:
SQLObject/trunk/sqlobject/versioning/
SQLObject/trunk/sqlobject/versioning/__init__.py
SQLObject/trunk/sqlobject/versioning/test/
SQLObject/trunk/sqlobject/versioning/test/__init__.py
SQLObject/trunk/sqlobject/versioning/test/test_version.py
Modified:
SQLObject/trunk/sqlobject/inheritance/__init__.py
Log:
Added versioning
Modified: SQLObject/trunk/sqlobject/inheritance/__init__.py
===================================================================
--- SQLObject/trunk/sqlobject/inheritance/__init__.py 2006-12-28 20:41:20 UTC (rev 2163)
+++ SQLObject/trunk/sqlobject/inheritance/__init__.py 2006-12-28 20:52:41 UTC (rev 2164)
@@ -164,7 +164,22 @@
delJoin = classmethod(delJoin)
+ def getAllColumns(sqlmeta):
+ columns = sqlmeta.columns.copy()
+ sm = sqlmeta
+ while sm.parentClass:
+ columns.update(sm.parentClass.sqlmeta.columns)
+ sm = sm.parentClass.sqlmeta
+ return columns
+ def asDict(sqlmeta):
+ result = {}
+ for key in sqlmeta.getAllColumns():
+ result[key] = getattr(sqlmeta.instance, key)
+ result['id'] = sqlmeta.instance.id
+ return result
+
+
class InheritableSQLObject(SQLObject):
sqlmeta = InheritableSQLMeta
Added: SQLObject/trunk/sqlobject/versioning/__init__.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/__init__.py (rev 0)
+++ SQLObject/trunk/sqlobject/versioning/__init__.py 2006-12-28 20:52:41 UTC (rev 2164)
@@ -0,0 +1,65 @@
+from sqlobject import *
+from datetime import datetime
+
+class Version(SQLObject):
+ def restore(self):
+ values = self.sqlmeta.asDict()
+ del values['id']
+ del values['masterID']
+ del values['dateArchived']
+ self.masterClass.get(self.masterID).set(**values)
+
+def getColumns(columns, cls):
+ for column, defi in cls.sqlmeta.columnDefinitions.items():
+ columns[column] = defi.__class__()
+
+ #ascend heirarchy
+ if cls.sqlmeta.parentClass:
+ getColumns(columns, cls.sqlmeta.parentClass)
+
+
+class Versioning(object):
+ def __init__(self):
+ pass
+ def __addtoclass__(self, soClass, name):
+ self.name = name
+ self.soClass = soClass
+ self.versionClass = None
+ events.listen(self.createTable,
+ soClass, events.CreateTableSignal)
+ events.listen(self.rowUpdate, soClass,
+ events.RowUpdateSignal)
+
+ def createVersionTable(self, cls, conn):
+ columns = {'dateArchived': DateTimeCol(default=datetime.now),
+ 'masterID': IntCol(),
+ 'masterClass' : self.soClass,
+ }
+
+ getColumns (columns, self.soClass)
+
+ self.versionClass = type(self.soClass.__name__+'Versions',
+ (Version,),
+ columns)
+
+ self.versionClass.createTable(connection=conn)
+
+ def createTable(self, soClass, connection, extra_sql, post_funcs):
+ assert soClass is self.soClass
+ post_funcs.append(self.createVersionTable)
+
+ def rowUpdate(self, instance, kwargs):
+ if instance.childName and instance.childName != self.soClass.__name__:
+ return #if you want your child class versioned, version it.
+
+ values = instance.sqlmeta.asDict()
+ del values['id']
+ values['masterID'] = instance.id
+ self.versionClass(connection=instance._connection, **values)
+
+ def __get__(self, obj, type=None):
+ if obj is None:
+ return self
+ return self.versionClass.select(
+ self.versionClass.q.masterID==obj.id, connection=obj._connection)
+
Added: SQLObject/trunk/sqlobject/versioning/test/__init__.py
===================================================================
Added: SQLObject/trunk/sqlobject/versioning/test/test_version.py
===================================================================
--- SQLObject/trunk/sqlobject/versioning/test/test_version.py (rev 0)
+++ SQLObject/trunk/sqlobject/versioning/test/test_version.py 2006-12-28 20:52:41 UTC (rev 2164)
@@ -0,0 +1,97 @@
+from py.test import raises
+from sqlobject import *
+from sqlobject.tests.dbtest import *
+from sqlobject.inheritance import InheritableSQLObject
+from sqlobject.versioning import Versioning
+
+from datetime import datetime
+
+
+def setup():
+ setupClass(MyClass)
+ setupClass(Base)
+ setupClass(Child)
+ setupClass(Government)
+ setupClass(Monarchy)
+ setupClass(VChild)
+
+class MyClass(SQLObject):
+ name = StringCol()
+ versions = Versioning()
+
+class Base(InheritableSQLObject):
+ name = StringCol()
+ versions = Versioning()
+
+class Child(Base):
+ toy = StringCol()
+
+
+class Government(InheritableSQLObject):
+ name = StringCol()
+
+class Monarchy(Government):
+ monarch = StringCol()
+ versions = Versioning()
+
+class VChild(Base):
+ weapon = StringCol()
+ versions = Versioning()
+
+def test_versioning():
+
+ #the simple case
+ setup()
+ mc = MyClass(name='fleem')
+ mc.set(name='morx')
+ assert len(list(mc.versions)) == 1
+ assert mc.versions[0].name == "fleem"
+
+ assert len(list(MyClass.select())) == 1
+
+def test_inheritable_versioning():
+ setup()
+
+ #base versioned, child unversioned
+ base = Base(name='fleem')
+ base.set(name='morx')
+ assert len(list(base.versions)) == 1
+ assert base.versions[0].name == "fleem"
+ assert len(list(Base.select())) == 1
+
+ child = Child(name='child', toy='nintendo')
+ child.set(name='teenager', toy='guitar')
+ assert len(list(child.versions)) == 0
+
+
+ #child versioned, base unversioned
+ government = Government(name='canada')
+ assert not hasattr(government, 'versions')
+
+ monarchy = Monarchy(name='UK', monarch='king george iv')
+ monarchy.set(name='queen elisabeth ii')
+ assert len(list(monarchy.versions)) == 1
+ assert monarchy.versions[0].name == "UK"
+ assert len(list(Monarchy.select())) == 1
+
+ #both parent and child versioned
+ num_base_versions = len(list(base.versions))
+ vchild = VChild(name='kid', weapon='slingshot')
+ vchild.set(name='toon', weapon='dynamite')
+ assert len(list(base.versions)) == num_base_versions
+ assert len(list(vchild.versions)) == 1
+
+def test_restore():
+ setup()
+ base = Base(name='fleem')
+ base.set(name='morx')
+ assert base.name == "morx"
+ base.versions[0].restore()
+ assert base.name == "fleem"
+
+ monarchy = Monarchy(name='USA', monarch='Emperor Norton I')
+ monarchy.set(name='morx')
+ assert monarchy.name == "morx"
+ monarchy.versions[0].restore()
+ assert monarchy.name == "USA"
+ assert monarchy.monarch == "Emperor Norton I"
|
|
From: <sub...@co...> - 2006-12-28 20:41:28
|
Author: novalis Date: 2006-12-28 13:41:20 -0700 (Thu, 28 Dec 2006) New Revision: 2163 Modified: SQLObject/docs/DeveloperGuide.txt Log: Added notes on how to build documentation to DeveloperGuide.txt. Modified: SQLObject/docs/DeveloperGuide.txt =================================================================== --- SQLObject/docs/DeveloperGuide.txt 2006-12-28 20:29:01 UTC (rev 2162) +++ SQLObject/docs/DeveloperGuide.txt 2006-12-28 20:41:20 UTC (rev 2163) @@ -184,3 +184,10 @@ forced to write the test. That's no fun for me, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. + +Documentation ======= + +Please write documentation. Documentation should live in the docs/ +directory. Pudge converts documentation from Restructured Text to +HTML. It presently requires kid 0.9.3, which must be obtained +separately (for instance, from http://cheeseshop.python.org/pypi/kid/0.9.3) |
|
From: <sub...@co...> - 2006-12-28 20:29:08
|
Author: phd Date: 2006-12-28 13:29:01 -0700 (Thu, 28 Dec 2006) New Revision: 2162 Modified: SQLObject/docs/News.txt SQLObject/docs/TODO.txt Log: Use DBUtils. Modified: SQLObject/docs/News.txt =================================================================== --- SQLObject/docs/News.txt 2006-12-28 20:21:47 UTC (rev 2161) +++ SQLObject/docs/News.txt 2006-12-28 20:29:01 UTC (rev 2162) @@ -125,6 +125,8 @@ * The reference loop between SQLObject and SQLObjectState eliminated using weak references. +* Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE). + SQLObject 0.7.3 =============== @@ -135,8 +137,6 @@ * Psycopg1 requires port to be a string; psycopg2 requires port to be an int. -* Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE). - SQLObject 0.7.2 =============== Modified: SQLObject/docs/TODO.txt =================================================================== --- SQLObject/docs/TODO.txt 2006-12-28 20:21:47 UTC (rev 2161) +++ SQLObject/docs/TODO.txt 2006-12-28 20:29:01 UTC (rev 2162) @@ -1,12 +1,16 @@ TODO ---- +* Use DBUtils_, especially SolidConnection. + +.. _DBUtils: http://www.webwareforpython.org/DBUtils + * ``_fromDatabase`` currently doesn't support IDs that don't fit into the normal naming scheme. It should do so. You can still use ``_idName`` with ``_fromDatabase``. * More databases supported. There has been interest and some work in - the progress for Oracle. IWBN to have informix and DB2 drivers. + the progress for Oracle. IWBN to have Informix and DB2 drivers. * Better transaction support -- right now you can use transactions for the database, but the object isn't transaction-aware, so |
|
From: <sub...@co...> - 2006-12-28 20:21:54
|
Author: phd
Date: 2006-12-28 13:21:47 -0700 (Thu, 28 Dec 2006)
New Revision: 2161
Modified:
home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
Log:
Merged patches from the revisions 2157:2160 from the trunk
Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:20:41 UTC (rev 2160)
+++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:21:47 UTC (rev 2161)
@@ -88,7 +88,7 @@
else:
return DBAPI._executeRetry(self, conn, cursor, query)
except MySQLdb.OperationalError, e:
- if e.args[0] in (2006, 20013): # SERVER_GONE or SERVER_LOST error
+ if e.args[0] == 2013: # SERVER_LOST error
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2006-12-28 20:20:44
|
Author: phd Date: 2006-12-28 13:20:41 -0700 (Thu, 28 Dec 2006) New Revision: 2160 Modified: SQLObject/docs/News.txt Log: Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE). Modified: SQLObject/docs/News.txt =================================================================== --- SQLObject/docs/News.txt 2006-12-28 20:19:16 UTC (rev 2159) +++ SQLObject/docs/News.txt 2006-12-28 20:20:41 UTC (rev 2160) @@ -135,6 +135,8 @@ * Psycopg1 requires port to be a string; psycopg2 requires port to be an int. +* Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE). + SQLObject 0.7.2 =============== |
|
From: <sub...@co...> - 2006-12-28 20:19:28
|
Author: phd
Date: 2006-12-28 13:19:16 -0700 (Thu, 28 Dec 2006)
New Revision: 2159
Modified:
SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py
Log:
Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE).
Modified: SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:19:00 UTC (rev 2158)
+++ SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:19:16 UTC (rev 2159)
@@ -88,7 +88,7 @@
else:
return cursor.execute(query)
except MySQLdb.OperationalError, e:
- if e.args[0] in (2006, 20013): # SERVER_GONE or SERVER_LOST error
+ if e.args[0] == 2013: # SERVER_LOST error
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2006-12-28 20:19:08
|
Author: phd
Date: 2006-12-28 13:19:00 -0700 (Thu, 28 Dec 2006)
New Revision: 2158
Modified:
SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
Log:
Reverted the patch that incorrectly handles MySQL error 2006 (SERVER_GONE).
Modified: SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
+++ SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:19:00 UTC (rev 2158)
@@ -88,7 +88,7 @@
else:
return cursor.execute(query)
except MySQLdb.OperationalError, e:
- if e.args[0] in (2006, 20013): # SERVER_GONE or SERVER_LOST error
+ if e.args[0] == 2013: # SERVER_LOST error
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2006-12-28 20:12:14
|
Author: phd
Date: 2006-12-28 13:12:10 -0700 (Thu, 28 Dec 2006)
New Revision: 2157
Modified:
home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py
home/phd/SQLObject/paramstyles/sqlobject/main.py
home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py
home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py
home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py
home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py
home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py
home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py
Log:
Merged patches from the revisions 2153:2156 from the trunk
Modified: home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -161,10 +161,8 @@
self.query("DROP TABLE %s" % tableName)
self.query("DROP GENERATOR GEN_%s" % tableName)
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
"""
Modified: home/phd/SQLObject/paramstyles/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/main.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/main.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -493,7 +493,7 @@
if changeSchema:
conn = connection or soClass._connection
- conn.delColumn(sqlmeta.table, column)
+ conn.delColumn(sqlmeta, column)
if soClass._SO_finishedClassCreation:
unmakeProperties(soClass)
Modified: home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -211,10 +211,8 @@
(tableName,
column.maxdbCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
GET_COLUMNS = """
SELECT COLUMN_NAME, NULLABLE, DATA_DEFAULT, DATA_TYPE,
Modified: home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -181,10 +181,8 @@
(tableName,
column.mssqlCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (tableName.table, column.dbName))
# precision and scale is gotten from column table so that we can create
# decimal columns if needed
Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -177,10 +177,8 @@
(tableName,
column.mysqlCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
colData = self.queryAll("SHOW COLUMNS FROM %s"
Modified: home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -177,10 +177,8 @@
(tableName,
column.postgresCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -1,5 +1,6 @@
from sqlobject.dbconnection import DBAPI
from sqlobject.col import popKey
+from sqlobject import col, sqlbuilder
from sqlobject.dberrors import *
import thread
@@ -88,6 +89,7 @@
# use only one connection for sqlite - supports multiple)
# cursors per connection
self._connOptions = opts
+ self.use_table_info = popKey(kw, "use_table_info", False)
DBAPI.__init__(self, **kw)
self._threadPool = {}
self._threadOrigination = {}
@@ -241,9 +243,12 @@
return None
def createIDColumn(self, soClass):
- key_type = {int: "INTEGER", str: "TEXT"}[soClass.sqlmeta.idType]
- return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type)
+ return self._createIDColumn(soClass.sqlmeta)
+ def _createIDColumn(self, sqlmeta):
+ key_type = {int: "INTEGER", str: "TEXT"}[sqlmeta.idType]
+ return '%s %s PRIMARY KEY' % (sqlmeta.idName, key_type)
+
def joinSQLType(self, join):
return 'INT NOT NULL'
@@ -259,9 +264,98 @@
self.query('ALTER TABLE %s ADD COLUMN %s' %
(tableName,
column.sqliteCreateSQL()))
+ self.query('VACUUM %s' % tableName)
- def delColumn(self, tableName, column):
- pass # Oops! There is no DROP COLUMN in SQLite
+ def delColumn(self, sqlmeta, column):
+ self.recreateTableWithoutColumn(sqlmeta, column)
+ def recreateTableWithoutColumn(self, sqlmeta, column):
+ new_name = sqlmeta.table + '_ORIGINAL'
+ self.query('ALTER TABLE %s RENAME TO %s' % (sqlmeta.table, new_name))
+ cols = [self._createIDColumn(sqlmeta)] \
+ + [self.createColumn(None, col)
+ for col in sqlmeta.columnList if col.name != column.name]
+ cols = ",\n".join([" %s" % c for c in cols])
+ self.query('CREATE TABLE %s (\n%s\n)' % (sqlmeta.table, cols))
+ all_columns = ', '.join(['id'] + [col.dbName for col in sqlmeta.columnList])
+ self.query('INSERT INTO %s (%s) SELECT %s FROM %s' % (
+ sqlmeta.table, all_columns, all_columns, new_name))
+ self.query('DROP TABLE %s' % new_name)
+
+ def columnsFromSchema(self, tableName, soClass):
+ if self.use_table_info:
+ return self._columnsFromSchemaTableInfo(tableName, soClass)
+ else:
+ return self._columnsFromSchemaParse(tableName, soClass)
+
+ def _columnsFromSchemaTableInfo(self, tableName, soClass):
+ colData = self.queryAll("PRAGMA table_info(%s)" % tableName)
+ results = []
+ for index, field, t, nullAllowed, default, key in colData:
+ if field == 'id':
+ continue
+ colClass, kw = self.guessClass(t)
+ kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
+ kw['dbName'] = field
+ kw['notNone'] = not nullAllowed
+ kw['default'] = default
+ # @@ skip key...
+ # @@ skip extra...
+ results.append(colClass(**kw))
+ return results
+
+ def _columnsFromSchemaParse(self, tableName, soClass):
+ colData = self.queryOne("SELECT sql FROM sqlite_master WHERE type='table' AND name='%s'"
+ % tableName)
+ if not colData:
+ raise ValueError('The table %s ws not found in the database. Load failed.' % tableName)
+ colData = colData[0].split('(', 1)[1].strip()[:-2]
+ while colData.find('(') > -1:
+ st = colData.find('(')
+ en = colData.find(')')
+ colData = colData[:st] + colData[en+1:]
+ results = []
+ for colDesc in colData.split(','):
+ parts = colDesc.strip().split(' ', 2)
+ field = parts[0].strip()
+ # skip comments
+ if field.startswith('--'):
+ continue
+ # get rid of enclosing quotes
+ if field[0] == field[-1] == '"':
+ field = field[1:-1]
+ if field == getattr(soClass.sqlmeta, 'idName', 'id'):
+ continue
+ colClass, kw = self.guessClass(parts[1].strip())
+ if len(parts) == 2:
+ index_info = ''
+ else:
+ index_info = parts[2].strip().upper()
+ kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
+ import re
+ nullble = re.search(r'(\b\S*)\sNULL', index_info)
+ default = re.search(r"DEFAULT\s((?:\d[\dA-FX.]*)|(?:'[^']*')|(?:#[^#]*#))", index_info)
+ kw['notNone'] = nullble and nullble.group(1) == 'NOT'
+ kw['default'] = default and default.group(1)
+ # @@ skip key...
+ # @@ skip extra...
+ results.append(colClass(**kw))
+ return results
+
+ def guessClass(self, t):
+ t = t.upper()
+ if t.find('INT') > 0:
+ return col.IntCol, {}
+ elif t.find('TEXT') > 0 or t.find('CHAR') > 0 or t.find('CLOB') > 0:
+ return col.StringCol, {'length': 2**32-1}
+ elif t.find('BLOB') > 0:
+ return col.BLOBCol, {"length": 2**32-1}
+ elif t.find('REAL') > 0 or t.find('FLOAT') > 0:
+ return col.FloatCol, {}
+ elif t.find('DECIMAL') > 0:
+ return col.DecimalCol, {}
+ else:
+ return col.Col, {}
+
def stop_pysqlite2_converting_strings(s):
return s
Modified: home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -128,10 +128,8 @@
(tableName,
column.sybaseCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
SHOW_COLUMNS=('SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS '
'WHERE TABLE_NAME = \'%s\'')
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -36,7 +36,6 @@
'+exceptions': 'mysql sqlite',
'-transactions': 'mysql',
'-dropTableCascade': 'sybase mssql',
- '-fromDatabase': 'sqlite',
'-expressionIndex': 'mysql sqlite firebird mssql',
'-blobData': 'mssql',
'-decimalColumn': 'mssql',
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -107,6 +107,19 @@
)
"""
+ sqliteCreate = """
+ CREATE TABLE auto_test (
+ auto_id INTEGER PRIMARY KEY AUTOINCREMENT ,
+ first_name VARCHAR(100),
+ last_name VARCHAR(200) NOT NULL,
+ age INT DEFAULT NULL,
+ created DATETIME NOT NULL,
+ happy char(1) DEFAULT 'Y' NOT NULL,
+ long_field TEXT,
+ wannahavefun INT DEFAULT 0 NOT NULL
+ )
+ """
+
sybaseCreate = """
CREATE TABLE auto_test (
auto_id integer,
@@ -141,12 +154,8 @@
DROP TABLE auto_test
"""
- sybaseDrop = """
- DROP TABLE auto_test
- """
+ sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop
- mssqlDrop = sybaseDrop
-
def setup_method(self, meth):
conn = getConnection()
dbName = conn.dbName
@@ -162,8 +171,6 @@
conn.query(dropper)
def test_classCreate(self):
- if not supports('fromDatabase'):
- return
class AutoTest(SQLObject):
_connection = getConnection()
class sqlmeta(sqlmeta):
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -96,6 +96,19 @@
)
"""
+ sqliteCreate = """
+ CREATE TABLE old_auto_test (
+ auto_id INTEGER PRIMARY KEY AUTOINCREMENT ,
+ first_name VARCHAR(100),
+ last_name VARCHAR(200) NOT NULL,
+ age INT DEFAULT NULL,
+ created DATETIME NOT NULL,
+ happy char(1) DEFAULT 'Y' NOT NULL,
+ long_field TEXT,
+ wannahavefun INT DEFAULT 0 NOT NULL
+ )
+ """
+
sybaseCreate = """
CREATE TABLE old_auto_test (
auto_id integer,
@@ -129,13 +142,8 @@
DROP TABLE old_auto_test
"""
- sybaseDrop = """
- DROP TABLE old_auto_test
- """
+ sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop
- mssqlDrop = """
- DROP TABLE old_auto_test
- """
def setup_method(self, meth):
conn = getConnection()
dbName = conn.dbName
@@ -151,8 +159,6 @@
conn.query(dropper)
def test_classCreate(self):
- if not supports('fromDatabase'):
- return
class OldAutoTest(SQLObject):
_connection = getConnection()
class sqlmeta(sqlmeta):
|
|
From: <sub...@co...> - 2006-12-28 20:10:24
|
Author: phd Date: 2006-12-28 13:10:21 -0700 (Thu, 28 Dec 2006) New Revision: 2156 Modified: SQLObject/docs/News.txt Log: SQLite connection got columnsFromSchema() and delColumn(). Modified: SQLObject/docs/News.txt =================================================================== --- SQLObject/docs/News.txt 2006-12-28 20:09:12 UTC (rev 2155) +++ SQLObject/docs/News.txt 2006-12-28 20:10:21 UTC (rev 2156) @@ -15,6 +15,21 @@ * Support for Python 2.2 has been declared obsolete. +* SQLite connection got columnsFromSchema(). Now all connections fully support + fromDatabase. There are two version of columnsFromSchema() for SQLite - + one parses the result of "SELECT sql FROM sqlite_master" and the other + uses "PRAGMA table_info"; the user can choose one over the other by using + "use_table_info" parameter in DB URI; default is False as the pragma is + available only in the later versions of SQLite. + +* Changed connection.delColumn(): the first argument is sqlmeta, not + tableName (required for SQLite). + +* SQLite connection got delColumn(). Now all connections fully support + delColumn(). As SQLite backend doesn't implement "ALTER TABLE DROP COLUMN" + delColumn() is implemented by creating a new table without the column, + copying all data, dropping the original table and renaming the new table. + Small Features -------------- |
|
From: <sub...@co...> - 2006-12-28 20:09:22
|
Author: phd
Date: 2006-12-28 13:09:12 -0700 (Thu, 28 Dec 2006)
New Revision: 2155
Modified:
SQLObject/trunk/sqlobject/firebird/firebirdconnection.py
SQLObject/trunk/sqlobject/main.py
SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py
SQLObject/trunk/sqlobject/mssql/mssqlconnection.py
SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
SQLObject/trunk/sqlobject/postgres/pgconnection.py
SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py
SQLObject/trunk/sqlobject/sybase/sybaseconnection.py
Log:
Changed connection.delColumn(): the first argument is sqlmeta, not tableName (required for SQLite).
Modified: SQLObject/trunk/sqlobject/firebird/firebirdconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/firebird/firebirdconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/firebird/firebirdconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -161,10 +161,8 @@
self.query("DROP TABLE %s" % tableName)
self.query("DROP GENERATOR GEN_%s" % tableName)
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
"""
Modified: SQLObject/trunk/sqlobject/main.py
===================================================================
--- SQLObject/trunk/sqlobject/main.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/main.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -493,7 +493,7 @@
if changeSchema:
conn = connection or soClass._connection
- conn.delColumn(sqlmeta.table, column)
+ conn.delColumn(sqlmeta, column)
if soClass._SO_finishedClassCreation:
unmakeProperties(soClass)
Modified: SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -211,10 +211,8 @@
(tableName,
column.maxdbCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
GET_COLUMNS = """
SELECT COLUMN_NAME, NULLABLE, DATA_DEFAULT, DATA_TYPE,
Modified: SQLObject/trunk/sqlobject/mssql/mssqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mssql/mssqlconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/mssql/mssqlconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -181,10 +181,8 @@
(tableName,
column.mssqlCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (tableName.table, column.dbName))
# precision and scale is gotten from column table so that we can create
# decimal columns if needed
Modified: SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -177,10 +177,8 @@
(tableName,
column.mysqlCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
colData = self.queryAll("SHOW COLUMNS FROM %s"
Modified: SQLObject/trunk/sqlobject/postgres/pgconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/postgres/pgconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/postgres/pgconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -177,10 +177,8 @@
(tableName,
column.postgresCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
Modified: SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -268,10 +268,8 @@
column.sqliteCreateSQL()))
self.query('VACUUM %s' % tableName)
- def delColumn(self, tableName, column):
- # @@ Need an sqlmeta to call recreateTableWithoutColumn
- #~ self.recreateTableWithoutColumn(, column)
- pass # Oops! There is no DROP COLUMN in SQLite
+ def delColumn(self, sqlmeta, column):
+ self.recreateTableWithoutColumn(sqlmeta, column)
def recreateTableWithoutColumn(self, sqlmeta, column):
new_name = sqlmeta.table + '_ORIGINAL'
Modified: SQLObject/trunk/sqlobject/sybase/sybaseconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/sybase/sybaseconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
+++ SQLObject/trunk/sqlobject/sybase/sybaseconnection.py 2006-12-28 20:09:12 UTC (rev 2155)
@@ -128,10 +128,8 @@
(tableName,
column.sybaseCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
SHOW_COLUMNS=('SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS '
'WHERE TABLE_NAME = \'%s\'')
|
|
From: SourceForge.net <no...@so...> - 2006-12-28 19:51:50
|
Patches item #1539325, was opened at 2006-08-13 01:42 Message generated for change (Comment added) made by phd You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540674&aid=1539325&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: None >Status: Closed >Resolution: Accepted Priority: 5 Private: No Submitted By: Arlo Belshee (abelcodemonk) Assigned to: Oleg Broytmann (phd) Summary: fromDatabase and delColumn for sqlite Initial Comment: This patch implements both fromDatabase and delColumn for sqlite. I added sqlite to the appropriate existing tests; it passes them. fromDatabase is done by parsing the table creation sql from the sqlite_master table. This will work with any sqlite 3, and I think dates back into sqlite 2, but I'm not sure. delColumn is implemented by renaming the table, creating a new table without the one column, then copying all the data over. This is obviously not as efficient as on DBs that support drop column directly, but it works. This implementation of dropColumn does deal correctly with triggers, foreign keys, and indices that reference the table whose column is being dropped. It does not deal correctly with triggers & indices attached directly to the table being altered. Attached items will be lost. Extending the implementation to support re-creating those indices & triggers should be straightforward, but is beyond my needs. You are welcome to do so. Finally, this patch slightly improves the implementation of addColumn for sqlite. It performs a vacuum operation after each column add. See the sqlite documentation for why this is a good idea. ---------------------------------------------------------------------- >Comment By: Oleg Broytmann (phd) Date: 2006-12-28 22:51 Message: Logged In: YES user_id=4799 Originator: NO A version extended by Glenn and me has been committed in the revision 2154. Thank you for the job! ---------------------------------------------------------------------- Comment By: Oleg Broytmann (phd) Date: 2006-09-01 19:39 Message: Logged In: YES user_id=4799 The second patch is invalid because patch program doesn't understand svn ignore lists. This must be done manually if at all. I just run a script find . -name '*.py[co]' | xargs rm before commit. And what are the problems with SQLIte and transactions? All tests are now passed. Can you write a test script that demonstrates the problem(s)? ---------------------------------------------------------------------- Comment By: Arlo Belshee (abelcodemonk) Date: 2006-08-27 20:20 Message: Logged In: YES user_id=1027257 I've slightly update my previous patch. Feel free to use whichever version you'd like - I just want to get these new functions into the main code line as quickly as possible. I need them in order to support migrations in TurboGears. This update does two things: 1. svn:ignore *.pyc in a bunch of directories. 2. Add sqlite to the -transactions list in the supportsMatrix. Why: 1: I find it easier to see what needs to get added to svn if I don't have clutter on the various "modified files" lists. Thus, I make sure to always tell svn how to handle each file: ignore it or commit it. I find it reduces the chances of bad checkins. 2: sqlite fails several tests that require transactions. It really doesn't handle them well. This may be dues to my adding vacuuming to addColumn, or it may be new failures because I added sqlite to the list of DBs that support fromDatabase() and delColumn. In any case, I found this to be the fastest reasonable way to express what SQLite can do. Feel free to modify if you want to go another way. ---------------------------------------------------------------------- Comment By: Arlo Belshee (abelcodemonk) Date: 2006-08-27 20:09 Message: Logged In: YES user_id=1027257 Why vacuum after addColumn: According to SQLite's docs, alter table add column doesn't add the column to the table's main location in the file, but rather creates it at the end of the file and the DB then takes care of pretending that the column adjoins all the other columns. Unfortunately, older versions of SQLite don't do this pretending, so can't read a table that has had a column added. Vacuum re-creates the table as a single table, meaning that all versions can then read it. Delete column, being not supported directly by SQLite, doesn't do anything funny. Since my implementation is just to create a new table without the column being dropped, all the tables remain together without any weird extra space, and a vacuum is not needed. Why I added semicolons: No, they are not needed, if you are using pysqlite. However, they are required in the interactive SQLite interpreter. I added the semicolons so that I could quickly paste generated SQL statements into the interactive console while I was trying to get things working. Since the semicolons have no effect with pysqlite, I just left them in for the next time I wan't to do this. Feel free to take them out if you'd like. On the name of delColumn(): Feel free to name it delColumn. I gave the longer and clear name to the low-level implementation primarily to highlight the performance implications involved. The public-facing objects still expose delColumn; that is translated to a call to recreateTableWithoutColumn() if the sqliteconnection is being used. So, external programs use it as deleteColumn(), but my patch is easier to understand and the performance implications are clearer. Mostly, I was hoping that that would speed patch approval. ;) Feel free to name the function as you will. On transactions: Yeah, you can't vacuum in transactions. However, sqlite's support for transactions is already fairly problematic. I find I can't use transactions with SQLite on any real problems anyway, so I don't worry about it. When I need transactions, then I generally need a more full-featured DBMS than SQLite. If you have a different opinion on this, you could remove the call to vacuum in addColumn(). You are trading off read speed & the ability for older versions of sqlite to read such a modified table. Yer call. ---------------------------------------------------------------------- Comment By: Oleg Broytmann (phd) Date: 2006-08-15 17:08 Message: Logged In: YES user_id=4799 Thank you very much! recreateTableWithoutColumn() is an excellent solution! I have some questions about the patch. Why have you added semicolons? I think they are not needed. Why VACUUM after addColumn()? It is more logical to do VACUUM after delColumn(), I suppose. And, BTW, "This command will fail if there is an active transaction." (from the SQLite documentation). Your patch deletes .delColumn(). But I have a number of programs that relies on a presence of the method (even if it's empty). I think you could just call recreateTableWithoutColumn() from delColumn() or raise a warning or an exception. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540674&aid=1539325&group_id=74338 |
|
From: <sub...@co...> - 2006-12-28 19:50:10
|
Author: phd
Date: 2006-12-28 12:50:05 -0700 (Thu, 28 Dec 2006)
New Revision: 2154
Modified:
SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py
SQLObject/trunk/sqlobject/tests/dbtest.py
SQLObject/trunk/sqlobject/tests/test_auto.py
SQLObject/trunk/sqlobject/tests/test_auto_old.py
Log:
Applied the patch 1539325: fromDatabase and delColumn for sqlite, created by
Arlo Belshee and extended by Glenn and phd.
Modified: SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py 2006-12-28 04:15:37 UTC (rev 2153)
+++ SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py 2006-12-28 19:50:05 UTC (rev 2154)
@@ -1,5 +1,6 @@
from sqlobject.dbconnection import DBAPI
from sqlobject.col import popKey
+from sqlobject import col, sqlbuilder
from sqlobject.dberrors import *
import thread
@@ -88,6 +89,7 @@
# use only one connection for sqlite - supports multiple)
# cursors per connection
self._connOptions = opts
+ self.use_table_info = popKey(kw, "use_table_info", False)
DBAPI.__init__(self, **kw)
self._threadPool = {}
self._threadOrigination = {}
@@ -243,9 +245,12 @@
return None
def createIDColumn(self, soClass):
- key_type = {int: "INTEGER", str: "TEXT"}[soClass.sqlmeta.idType]
- return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type)
+ return self._createIDColumn(soClass.sqlmeta)
+ def _createIDColumn(self, sqlmeta):
+ key_type = {int: "INTEGER", str: "TEXT"}[sqlmeta.idType]
+ return '%s %s PRIMARY KEY' % (sqlmeta.idName, key_type)
+
def joinSQLType(self, join):
return 'INT NOT NULL'
@@ -261,9 +266,100 @@
self.query('ALTER TABLE %s ADD COLUMN %s' %
(tableName,
column.sqliteCreateSQL()))
+ self.query('VACUUM %s' % tableName)
def delColumn(self, tableName, column):
+ # @@ Need an sqlmeta to call recreateTableWithoutColumn
+ #~ self.recreateTableWithoutColumn(, column)
pass # Oops! There is no DROP COLUMN in SQLite
+ def recreateTableWithoutColumn(self, sqlmeta, column):
+ new_name = sqlmeta.table + '_ORIGINAL'
+ self.query('ALTER TABLE %s RENAME TO %s' % (sqlmeta.table, new_name))
+ cols = [self._createIDColumn(sqlmeta)] \
+ + [self.createColumn(None, col)
+ for col in sqlmeta.columnList if col.name != column.name]
+ cols = ",\n".join([" %s" % c for c in cols])
+ self.query('CREATE TABLE %s (\n%s\n)' % (sqlmeta.table, cols))
+ all_columns = ', '.join(['id'] + [col.dbName for col in sqlmeta.columnList])
+ self.query('INSERT INTO %s (%s) SELECT %s FROM %s' % (
+ sqlmeta.table, all_columns, all_columns, new_name))
+ self.query('DROP TABLE %s' % new_name)
+
+ def columnsFromSchema(self, tableName, soClass):
+ if self.use_table_info:
+ return self._columnsFromSchemaTableInfo(tableName, soClass)
+ else:
+ return self._columnsFromSchemaParse(tableName, soClass)
+
+ def _columnsFromSchemaTableInfo(self, tableName, soClass):
+ colData = self.queryAll("PRAGMA table_info(%s)" % tableName)
+ results = []
+ for index, field, t, nullAllowed, default, key in colData:
+ if field == 'id':
+ continue
+ colClass, kw = self.guessClass(t)
+ kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
+ kw['dbName'] = field
+ kw['notNone'] = not nullAllowed
+ kw['default'] = default
+ # @@ skip key...
+ # @@ skip extra...
+ results.append(colClass(**kw))
+ return results
+
+ def _columnsFromSchemaParse(self, tableName, soClass):
+ colData = self.queryOne("SELECT sql FROM sqlite_master WHERE type='table' AND name='%s'"
+ % tableName)
+ if not colData:
+ raise ValueError('The table %s ws not found in the database. Load failed.' % tableName)
+ colData = colData[0].split('(', 1)[1].strip()[:-2]
+ while colData.find('(') > -1:
+ st = colData.find('(')
+ en = colData.find(')')
+ colData = colData[:st] + colData[en+1:]
+ results = []
+ for colDesc in colData.split(','):
+ parts = colDesc.strip().split(' ', 2)
+ field = parts[0].strip()
+ # skip comments
+ if field.startswith('--'):
+ continue
+ # get rid of enclosing quotes
+ if field[0] == field[-1] == '"':
+ field = field[1:-1]
+ if field == getattr(soClass.sqlmeta, 'idName', 'id'):
+ continue
+ colClass, kw = self.guessClass(parts[1].strip())
+ if len(parts) == 2:
+ index_info = ''
+ else:
+ index_info = parts[2].strip().upper()
+ kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
+ import re
+ nullble = re.search(r'(\b\S*)\sNULL', index_info)
+ default = re.search(r"DEFAULT\s((?:\d[\dA-FX.]*)|(?:'[^']*')|(?:#[^#]*#))", index_info)
+ kw['notNone'] = nullble and nullble.group(1) == 'NOT'
+ kw['default'] = default and default.group(1)
+ # @@ skip key...
+ # @@ skip extra...
+ results.append(colClass(**kw))
+ return results
+
+ def guessClass(self, t):
+ t = t.upper()
+ if t.find('INT') > 0:
+ return col.IntCol, {}
+ elif t.find('TEXT') > 0 or t.find('CHAR') > 0 or t.find('CLOB') > 0:
+ return col.StringCol, {'length': 2**32-1}
+ elif t.find('BLOB') > 0:
+ return col.BLOBCol, {"length": 2**32-1}
+ elif t.find('REAL') > 0 or t.find('FLOAT') > 0:
+ return col.FloatCol, {}
+ elif t.find('DECIMAL') > 0:
+ return col.DecimalCol, {}
+ else:
+ return col.Col, {}
+
def stop_pysqlite2_converting_strings(s):
return s
Modified: SQLObject/trunk/sqlobject/tests/dbtest.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/dbtest.py 2006-12-28 04:15:37 UTC (rev 2153)
+++ SQLObject/trunk/sqlobject/tests/dbtest.py 2006-12-28 19:50:05 UTC (rev 2154)
@@ -36,7 +36,6 @@
'+exceptions': 'mysql sqlite',
'-transactions': 'mysql',
'-dropTableCascade': 'sybase mssql',
- '-fromDatabase': 'sqlite',
'-expressionIndex': 'mysql sqlite firebird mssql',
'-blobData': 'mssql',
'-decimalColumn': 'mssql',
Modified: SQLObject/trunk/sqlobject/tests/test_auto.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_auto.py 2006-12-28 04:15:37 UTC (rev 2153)
+++ SQLObject/trunk/sqlobject/tests/test_auto.py 2006-12-28 19:50:05 UTC (rev 2154)
@@ -107,6 +107,19 @@
)
"""
+ sqliteCreate = """
+ CREATE TABLE auto_test (
+ auto_id INTEGER PRIMARY KEY AUTOINCREMENT ,
+ first_name VARCHAR(100),
+ last_name VARCHAR(200) NOT NULL,
+ age INT DEFAULT NULL,
+ created DATETIME NOT NULL,
+ happy char(1) DEFAULT 'Y' NOT NULL,
+ long_field TEXT,
+ wannahavefun INT DEFAULT 0 NOT NULL
+ )
+ """
+
sybaseCreate = """
CREATE TABLE auto_test (
auto_id integer,
@@ -141,12 +154,8 @@
DROP TABLE auto_test
"""
- sybaseDrop = """
- DROP TABLE auto_test
- """
+ sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop
- mssqlDrop = sybaseDrop
-
def setup_method(self, meth):
conn = getConnection()
dbName = conn.dbName
@@ -162,8 +171,6 @@
conn.query(dropper)
def test_classCreate(self):
- if not supports('fromDatabase'):
- return
class AutoTest(SQLObject):
_connection = getConnection()
class sqlmeta(sqlmeta):
Modified: SQLObject/trunk/sqlobject/tests/test_auto_old.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_auto_old.py 2006-12-28 04:15:37 UTC (rev 2153)
+++ SQLObject/trunk/sqlobject/tests/test_auto_old.py 2006-12-28 19:50:05 UTC (rev 2154)
@@ -96,6 +96,19 @@
)
"""
+ sqliteCreate = """
+ CREATE TABLE old_auto_test (
+ auto_id INTEGER PRIMARY KEY AUTOINCREMENT ,
+ first_name VARCHAR(100),
+ last_name VARCHAR(200) NOT NULL,
+ age INT DEFAULT NULL,
+ created DATETIME NOT NULL,
+ happy char(1) DEFAULT 'Y' NOT NULL,
+ long_field TEXT,
+ wannahavefun INT DEFAULT 0 NOT NULL
+ )
+ """
+
sybaseCreate = """
CREATE TABLE old_auto_test (
auto_id integer,
@@ -129,13 +142,8 @@
DROP TABLE old_auto_test
"""
- sybaseDrop = """
- DROP TABLE old_auto_test
- """
+ sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop
- mssqlDrop = """
- DROP TABLE old_auto_test
- """
def setup_method(self, meth):
conn = getConnection()
dbName = conn.dbName
@@ -151,8 +159,6 @@
conn.query(dropper)
def test_classCreate(self):
- if not supports('fromDatabase'):
- return
class OldAutoTest(SQLObject):
_connection = getConnection()
class sqlmeta(sqlmeta):
|
|
From: SourceForge.net <no...@so...> - 2006-12-26 02:26:17
|
Bugs item #1622193, was opened at 2006-12-26 11:26 Message generated for change (Tracker Item Submitted) made by Item Submitter You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1622193&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: General Group: SQLObject release (specify) Status: Open Resolution: None Priority: 5 Private: No Submitted By: Tamakoshi Hiroki (tamakoshihiroki) Assigned to: Nobody/Anonymous (nobody) Summary: dbconnection close issue Initial Comment: Hi, I found a bug in DBAPI.close() method at line 683 in dbconnection.py. 'del conn' may be in the above for loop. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1622193&group_id=74338 |
|
From: SourceForge.net <no...@so...> - 2006-12-25 12:02:41
|
Bugs item #1621951, was opened at 2006-12-25 03:58 Message generated for change (Comment added) made by nobody You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1621951&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: SQLObject release (specify) Status: Open Resolution: None Priority: 5 Private: No Submitted By: Nobody/Anonymous (nobody) Assigned to: Nobody/Anonymous (nobody) Summary: StringCol can't treat other encoding except "ASCII" Initial Comment: Hi, I'm Chinese. I'm very like SQLObject. But, I found a encoding bug in the class StringValidator. This class is in the script "col.py". When I input a other encoding string input or output from database with StringCol it will raise a UnicodeEncodeError, because I use GBK encoding to access the string. But in StringValidator Only allow "acsii" encoding. I have fix it, the new code is below: import sys class StringValidator(validators.Validator): def to_python(self, value, state): if value is None: return None if isinstance(value, unicode): return value.encode(sys.getdefaultencoding()) return value def from_python(self, value, state): if value is None: return None if isinstance(value, str): return value if isinstance(value, unicode): return value.encode(sys.getdefaultencoding()) return value Then, I can use StringCol to access a "GBK" encoding string. Also I must set the default encoding before this: import sys reload(sys) sys.setdefaultencoding("GBK") Please fix it, Thanks. SQLObject 0.7.1 ---------------------------------------------------------------------- Comment By: Nobody/Anonymous (nobody) Date: 2006-12-25 04:02 Message: Logged In: NO It's very surperise that I can't login. My account is gashero, and my email is "har...@gm...". Thanks!!!!! ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1621951&group_id=74338 |
|
From: SourceForge.net <no...@so...> - 2006-12-25 11:58:36
|
Bugs item #1621951, was opened at 2006-12-25 03:58 Message generated for change (Tracker Item Submitted) made by Item Submitter You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1621951&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: SQLObject release (specify) Status: Open Resolution: None Priority: 5 Private: No Submitted By: Nobody/Anonymous (nobody) Assigned to: Nobody/Anonymous (nobody) Summary: StringCol can't treat other encoding except "ASCII" Initial Comment: Hi, I'm Chinese. I'm very like SQLObject. But, I found a encoding bug in the class StringValidator. This class is in the script "col.py". When I input a other encoding string input or output from database with StringCol it will raise a UnicodeEncodeError, because I use GBK encoding to access the string. But in StringValidator Only allow "acsii" encoding. I have fix it, the new code is below: import sys class StringValidator(validators.Validator): def to_python(self, value, state): if value is None: return None if isinstance(value, unicode): return value.encode(sys.getdefaultencoding()) return value def from_python(self, value, state): if value is None: return None if isinstance(value, str): return value if isinstance(value, unicode): return value.encode(sys.getdefaultencoding()) return value Then, I can use StringCol to access a "GBK" encoding string. Also I must set the default encoding before this: import sys reload(sys) sys.setdefaultencoding("GBK") Please fix it, Thanks. SQLObject 0.7.1 ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1621951&group_id=74338 |