sqlobject-cvs Mailing List for SQLObject (Page 156)
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-10-28 15:39:03
|
Author: phd Date: 2005-10-28 15:38:54 +0000 (Fri, 28 Oct 2005) New Revision: 1169 Modified: SQLObject/trunk/docs/News.txt Log: Updated News. Modified: SQLObject/trunk/docs/News.txt =================================================================== --- SQLObject/trunk/docs/News.txt 2005-10-28 15:35:21 UTC (rev 1168) +++ SQLObject/trunk/docs/News.txt 2005-10-28 15:38:54 UTC (rev 1169) @@ -21,8 +21,6 @@ Constraints (in the DBMSes that support constraints) are added after the tables have been created. -* Added ``TimeCol``. - * ``RelatedJoin`` and ``SQLRelatedJoin`` objects have a ``createRelatedTable`` keyword argument (default ``True``). If ``False``, then the related table won't be automatically created; @@ -36,6 +34,15 @@ Examples in sqlobject/tests/test_sqlobject_admin.py or at <http://sqlobject.org/sqlobject-admin.html#the-create-command> +SQLObject 0.7.1 +=============== + +* Added ``TimeCol``. + +* Added support for psycopg2_ + +.. _psycopg2: http://initd.org/projects/psycopg2 + SQLObject 0.7.0 =============== |
|
From: <sub...@co...> - 2005-10-28 15:35:30
|
Author: phd
Date: 2005-10-28 15:35:21 +0000 (Fri, 28 Oct 2005)
New Revision: 1168
Modified:
home/phd/SQLObject/paramstyles/sqlobject/col.py
home/phd/SQLObject/paramstyles/sqlobject/postgres/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py
Log:
Merged a patch from the revision 1156 from the trunk: adapted to psycopg2.
Modified: home/phd/SQLObject/paramstyles/sqlobject/col.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/col.py 2005-10-28 15:35:08 UTC (rev 1167)
+++ home/phd/SQLObject/paramstyles/sqlobject/col.py 2005-10-28 15:35:21 UTC (rev 1168)
@@ -30,7 +30,7 @@
from formencode import compound
from formencode import validators
from classregistry import findClass
-from converters import array_type
+from converters import array_type, buffer_type
from util.backports import count
NoDefault = sqlbuilder.NoDefault
@@ -1162,7 +1162,7 @@
if module.__name__ == "sqlite":
value = module.decode(value)
return value
- if isinstance(value, state.soObject._connection._binaryType):
+ if isinstance(value, (buffer_type, state.soObject._connection._binaryType)):
cachedValue = self._cachedValue
if cachedValue and cachedValue[1] == value:
return cachedValue[0]
Modified: home/phd/SQLObject/paramstyles/sqlobject/postgres/__init__.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/postgres/__init__.py 2005-10-28 15:35:08 UTC (rev 1167)
+++ home/phd/SQLObject/paramstyles/sqlobject/postgres/__init__.py 2005-10-28 15:35:21 UTC (rev 1168)
@@ -6,9 +6,12 @@
def isSupported():
try:
- import psycopg
+ import psycopg2
except ImportError:
- return False
+ try:
+ import psycopg
+ except ImportError:
+ return False
return True
registerConnection(['postgres', 'postgresql', 'psycopg'],
Modified: home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2005-10-28 15:35:08 UTC (rev 1167)
+++ home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2005-10-28 15:35:21 UTC (rev 1168)
@@ -23,7 +23,10 @@
self.module = pgdb
else:
if psycopg is None:
- import psycopg
+ try:
+ import psycopg2 as psycopg
+ except ImportError:
+ import psycopg
self.module = psycopg
# Register a converter for psycopg Binary type.
|
|
From: <sub...@co...> - 2005-10-28 15:35:13
|
Author: phd
Date: 2005-10-28 15:35:08 +0000 (Fri, 28 Oct 2005)
New Revision: 1167
Modified:
SQLObject/branches/0.7-bugfix/sqlobject/col.py
SQLObject/branches/0.7-bugfix/sqlobject/postgres/__init__.py
SQLObject/branches/0.7-bugfix/sqlobject/postgres/pgconnection.py
Log:
Merged a patch from the revision 1156 from the trunk: adapted to psycopg2.
Modified: SQLObject/branches/0.7-bugfix/sqlobject/col.py
===================================================================
--- SQLObject/branches/0.7-bugfix/sqlobject/col.py 2005-10-28 15:34:24 UTC (rev 1166)
+++ SQLObject/branches/0.7-bugfix/sqlobject/col.py 2005-10-28 15:35:08 UTC (rev 1167)
@@ -30,7 +30,7 @@
from formencode import compound
from formencode import validators
from classregistry import findClass
-from converters import array_type
+from converters import array_type, buffer_type
from util.backports import count
NoDefault = sqlbuilder.NoDefault
@@ -1096,7 +1096,7 @@
if module.__name__ == "sqlite":
value = module.decode(value)
return value
- if isinstance(value, state.soObject._connection._binaryType):
+ if isinstance(value, (buffer_type, state.soObject._connection._binaryType)):
cachedValue = self._cachedValue
if cachedValue and cachedValue[1] == value:
return cachedValue[0]
Modified: SQLObject/branches/0.7-bugfix/sqlobject/postgres/__init__.py
===================================================================
--- SQLObject/branches/0.7-bugfix/sqlobject/postgres/__init__.py 2005-10-28 15:34:24 UTC (rev 1166)
+++ SQLObject/branches/0.7-bugfix/sqlobject/postgres/__init__.py 2005-10-28 15:35:08 UTC (rev 1167)
@@ -6,9 +6,12 @@
def isSupported():
try:
- import psycopg
+ import psycopg2
except ImportError:
- return False
+ try:
+ import psycopg
+ except ImportError:
+ return False
return True
registerConnection(['postgres', 'postgresql', 'psycopg'],
Modified: SQLObject/branches/0.7-bugfix/sqlobject/postgres/pgconnection.py
===================================================================
--- SQLObject/branches/0.7-bugfix/sqlobject/postgres/pgconnection.py 2005-10-28 15:34:24 UTC (rev 1166)
+++ SQLObject/branches/0.7-bugfix/sqlobject/postgres/pgconnection.py 2005-10-28 15:35:08 UTC (rev 1167)
@@ -23,7 +23,10 @@
self.module = pgdb
else:
if psycopg is None:
- import psycopg
+ try:
+ import psycopg2 as psycopg
+ except ImportError:
+ import psycopg
self.module = psycopg
# Register a converter for psycopg Binary type.
|
|
From: <sub...@co...> - 2005-10-28 15:34:35
|
Author: phd
Date: 2005-10-28 15:34:24 +0000 (Fri, 28 Oct 2005)
New Revision: 1166
Modified:
SQLObject/trunk/sqlobject/col.py
SQLObject/trunk/sqlobject/postgres/__init__.py
SQLObject/trunk/sqlobject/postgres/pgconnection.py
Log:
Adapted to psycopg2.
Modified: SQLObject/trunk/sqlobject/col.py
===================================================================
--- SQLObject/trunk/sqlobject/col.py 2005-10-28 12:46:06 UTC (rev 1165)
+++ SQLObject/trunk/sqlobject/col.py 2005-10-28 15:34:24 UTC (rev 1166)
@@ -30,7 +30,7 @@
from formencode import compound
from formencode import validators
from classregistry import findClass
-from converters import array_type
+from converters import array_type, buffer_type
from util.backports import count
NoDefault = sqlbuilder.NoDefault
@@ -1162,7 +1162,7 @@
if module.__name__ == "sqlite":
value = module.decode(value)
return value
- if isinstance(value, state.soObject._connection._binaryType):
+ if isinstance(value, (buffer_type, state.soObject._connection._binaryType)):
cachedValue = self._cachedValue
if cachedValue and cachedValue[1] == value:
return cachedValue[0]
Modified: SQLObject/trunk/sqlobject/postgres/__init__.py
===================================================================
--- SQLObject/trunk/sqlobject/postgres/__init__.py 2005-10-28 12:46:06 UTC (rev 1165)
+++ SQLObject/trunk/sqlobject/postgres/__init__.py 2005-10-28 15:34:24 UTC (rev 1166)
@@ -6,9 +6,12 @@
def isSupported():
try:
- import psycopg
+ import psycopg2
except ImportError:
- return False
+ try:
+ import psycopg
+ except ImportError:
+ return False
return True
registerConnection(['postgres', 'postgresql', 'psycopg'],
Modified: SQLObject/trunk/sqlobject/postgres/pgconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/postgres/pgconnection.py 2005-10-28 12:46:06 UTC (rev 1165)
+++ SQLObject/trunk/sqlobject/postgres/pgconnection.py 2005-10-28 15:34:24 UTC (rev 1166)
@@ -23,7 +23,10 @@
self.module = pgdb
else:
if psycopg is None:
- import psycopg
+ try:
+ import psycopg2 as psycopg
+ except ImportError:
+ import psycopg
self.module = psycopg
# Register a converter for psycopg Binary type.
|
|
From: <sub...@co...> - 2005-10-28 12:46:12
|
Author: phd
Date: 2005-10-28 12:46:06 +0000 (Fri, 28 Oct 2005)
New Revision: 1165
Modified:
home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_joins_conditional.py
Log:
Merged a patch 1163 from the trunk: fixed a number of bugs with JOIN syntax; added a test.
Modified: home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py 2005-10-28 12:45:30 UTC (rev 1164)
+++ home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py 2005-10-28 12:46:06 UTC (rev 1165)
@@ -387,8 +387,7 @@
q = "SELECT %s" % ", ".join([str(expression) for expression in expressions])
q += " FROM %s" % ", ".join(tables)
if join:
- if tables: q += ','
- q += self._addJoins(select)
+ q += self._addJoins(select, tables)
q += " WHERE"
q = self._addWhereClause(select, q, limit=0, order=0)
val = self.queryOne(q)
@@ -425,8 +424,7 @@
", ".join(tables))
if join:
- if tables: q += ','
- q += self._addJoins(select)
+ q += self._addJoins(select, tables)
q += " WHERE"
return self._addWhereClause(select, q)
@@ -447,16 +445,24 @@
if j.table2 in tables: tables.remove(j.table2)
return tables
- def _addJoins(self, select):
+ def _addJoins(self, select, tables):
ops = select.ops
join = ops.get('join')
if type(join) is str:
- pass
+ join_str = ' ' + join
elif isinstance(join, sqlbuilder.SQLJoin):
- join_str = self.sqlrepr(join)
+ if tables and join.table1:
+ join_str = ", "
+ else:
+ join_str = ' '
+ join_str += self.sqlrepr(join)
else:
- join_str = ", ".join([self.sqlrepr(j) for j in join])
- return ' ' + join_str
+ if tables and join[0].table1:
+ join_str = ", "
+ else:
+ join_str = ' '
+ join_str += " ".join([self.sqlrepr(j) for j in join])
+ return join_str
def _addWhereClause(self, select, startSelect, limit=1, order=1):
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_joins_conditional.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_joins_conditional.py 2005-10-28 12:45:30 UTC (rev 1164)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_joins_conditional.py 2005-10-28 12:46:06 UTC (rev 1165)
@@ -59,3 +59,13 @@
)
assert str(select) == \
"SELECT test_join1.id, test_join1.col1 FROM test_join1, test_join2 LEFT JOIN test_join3 WHERE 1 = 1"
+
+def test_5join_3tables_syntax2():
+ setup()
+ setupClass(TestJoin3)
+
+ select = TestJoin1.select(
+ join=(LEFTJOIN(None, TestJoin2), LEFTJOIN(None, TestJoin3))
+ )
+ assert str(select) == \
+ "SELECT test_join1.id, test_join1.col1 FROM test_join1 LEFT JOIN test_join2 LEFT JOIN test_join3 WHERE 1 = 1"
|
|
From: <sub...@co...> - 2005-10-28 12:45:34
|
Author: phd
Date: 2005-10-28 12:45:30 +0000 (Fri, 28 Oct 2005)
New Revision: 1164
Modified:
SQLObject/branches/0.7-bugfix/sqlobject/dbconnection.py
SQLObject/branches/0.7-bugfix/sqlobject/tests/test_joins_conditional.py
Log:
Merged a patch 1163 from the trunk: fixed a number of bugs with JOIN syntax; added a test.
Modified: SQLObject/branches/0.7-bugfix/sqlobject/dbconnection.py
===================================================================
--- SQLObject/branches/0.7-bugfix/sqlobject/dbconnection.py 2005-10-28 12:44:48 UTC (rev 1163)
+++ SQLObject/branches/0.7-bugfix/sqlobject/dbconnection.py 2005-10-28 12:45:30 UTC (rev 1164)
@@ -373,8 +373,7 @@
q = "SELECT %s" % ", ".join([str(expression) for expression in expressions])
q += " FROM %s" % ", ".join(tables)
if join:
- if tables: q += ','
- q += self._addJoins(select)
+ q += self._addJoins(select, tables)
q += " WHERE"
q = self._addWhereClause(select, q, limit=0, order=0)
val = self.queryOne(q)
@@ -411,8 +410,7 @@
", ".join(tables))
if join:
- if tables: q += ','
- q += self._addJoins(select)
+ q += self._addJoins(select, tables)
q += " WHERE"
return self._addWhereClause(select, q)
@@ -433,16 +431,24 @@
if j.table2 in tables: tables.remove(j.table2)
return tables
- def _addJoins(self, select):
+ def _addJoins(self, select, tables):
ops = select.ops
join = ops.get('join')
if type(join) is str:
- pass
+ join_str = ' ' + join
elif isinstance(join, sqlbuilder.SQLJoin):
- join_str = self.sqlrepr(join)
+ if tables and join.table1:
+ join_str = ", "
+ else:
+ join_str = ' '
+ join_str += self.sqlrepr(join)
else:
- join_str = ", ".join([self.sqlrepr(j) for j in join])
- return ' ' + join_str
+ if tables and join[0].table1:
+ join_str = ", "
+ else:
+ join_str = ' '
+ join_str += " ".join([self.sqlrepr(j) for j in join])
+ return join_str
def _addWhereClause(self, select, startSelect, limit=1, order=1):
Modified: SQLObject/branches/0.7-bugfix/sqlobject/tests/test_joins_conditional.py
===================================================================
--- SQLObject/branches/0.7-bugfix/sqlobject/tests/test_joins_conditional.py 2005-10-28 12:44:48 UTC (rev 1163)
+++ SQLObject/branches/0.7-bugfix/sqlobject/tests/test_joins_conditional.py 2005-10-28 12:45:30 UTC (rev 1164)
@@ -59,3 +59,13 @@
)
assert str(select) == \
"SELECT test_join1.id, test_join1.col1 FROM test_join1, test_join2 LEFT JOIN test_join3 WHERE 1 = 1"
+
+def test_5join_3tables_syntax2():
+ setup()
+ setupClass(TestJoin3)
+
+ select = TestJoin1.select(
+ join=(LEFTJOIN(None, TestJoin2), LEFTJOIN(None, TestJoin3))
+ )
+ assert str(select) == \
+ "SELECT test_join1.id, test_join1.col1 FROM test_join1 LEFT JOIN test_join2 LEFT JOIN test_join3 WHERE 1 = 1"
|
|
From: <sub...@co...> - 2005-10-28 12:45:04
|
Author: phd
Date: 2005-10-28 12:44:48 +0000 (Fri, 28 Oct 2005)
New Revision: 1163
Modified:
SQLObject/trunk/sqlobject/dbconnection.py
SQLObject/trunk/sqlobject/tests/test_joins_conditional.py
Log:
Fixed a number of bugs with JOIN syntax. Added a test.
Modified: SQLObject/trunk/sqlobject/dbconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/dbconnection.py 2005-10-28 11:41:40 UTC (rev 1162)
+++ SQLObject/trunk/sqlobject/dbconnection.py 2005-10-28 12:44:48 UTC (rev 1163)
@@ -373,8 +373,7 @@
q = "SELECT %s" % ", ".join([str(expression) for expression in expressions])
q += " FROM %s" % ", ".join(tables)
if join:
- if tables: q += ','
- q += self._addJoins(select)
+ q += self._addJoins(select, tables)
q += " WHERE"
q = self._addWhereClause(select, q, limit=0, order=0)
val = self.queryOne(q)
@@ -411,8 +410,7 @@
", ".join(tables))
if join:
- if tables: q += ','
- q += self._addJoins(select)
+ q += self._addJoins(select, tables)
q += " WHERE"
return self._addWhereClause(select, q)
@@ -433,16 +431,24 @@
if j.table2 in tables: tables.remove(j.table2)
return tables
- def _addJoins(self, select):
+ def _addJoins(self, select, tables):
ops = select.ops
join = ops.get('join')
if type(join) is str:
- pass
+ join_str = ' ' + join
elif isinstance(join, sqlbuilder.SQLJoin):
- join_str = self.sqlrepr(join)
+ if tables and join.table1:
+ join_str = ", "
+ else:
+ join_str = ' '
+ join_str += self.sqlrepr(join)
else:
- join_str = ", ".join([self.sqlrepr(j) for j in join])
- return ' ' + join_str
+ if tables and join[0].table1:
+ join_str = ", "
+ else:
+ join_str = ' '
+ join_str += " ".join([self.sqlrepr(j) for j in join])
+ return join_str
def _addWhereClause(self, select, startSelect, limit=1, order=1):
Modified: SQLObject/trunk/sqlobject/tests/test_joins_conditional.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_joins_conditional.py 2005-10-28 11:41:40 UTC (rev 1162)
+++ SQLObject/trunk/sqlobject/tests/test_joins_conditional.py 2005-10-28 12:44:48 UTC (rev 1163)
@@ -59,3 +59,13 @@
)
assert str(select) == \
"SELECT test_join1.id, test_join1.col1 FROM test_join1, test_join2 LEFT JOIN test_join3 WHERE 1 = 1"
+
+def test_5join_3tables_syntax2():
+ setup()
+ setupClass(TestJoin3)
+
+ select = TestJoin1.select(
+ join=(LEFTJOIN(None, TestJoin2), LEFTJOIN(None, TestJoin3))
+ )
+ assert str(select) == \
+ "SELECT test_join1.id, test_join1.col1 FROM test_join1 LEFT JOIN test_join2 LEFT JOIN test_join3 WHERE 1 = 1"
|
|
From: <sub...@co...> - 2005-10-28 11:41:44
|
Author: phd
Date: 2005-10-28 11:41:40 +0000 (Fri, 28 Oct 2005)
New Revision: 1162
Modified:
home/phd/SQLObject/paramstyles/setup.py
Log:
Added 'include' subpackage.
Modified: home/phd/SQLObject/paramstyles/setup.py
===================================================================
--- home/phd/SQLObject/paramstyles/setup.py 2005-10-28 11:41:14 UTC (rev 1161)
+++ home/phd/SQLObject/paramstyles/setup.py 2005-10-28 11:41:40 UTC (rev 1162)
@@ -7,9 +7,8 @@
except ImportError:
from distutils.core import setup
-subpackages = ['firebird', 'inheritance', 'mysql', 'postgres',
- 'sqlite', 'sybase', 'maxdb', 'util', 'manager',
- 'mssql']
+subpackages = ['firebird', 'include', 'inheritance', 'mysql', 'postgres',
+ 'sqlite', 'sybase', 'maxdb', 'util', 'manager', 'mssql']
import sys
# patch distutils if it can't cope with the "classifiers" keyword
|
|
From: <sub...@co...> - 2005-10-28 11:41:20
|
Author: phd
Date: 2005-10-28 11:41:14 +0000 (Fri, 28 Oct 2005)
New Revision: 1161
Modified:
home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py
Log:
Use DBAPI._executeRetry().
Modified: home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2005-10-28 11:34:54 UTC (rev 1160)
+++ home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2005-10-28 11:41:14 UTC (rev 1161)
@@ -116,7 +116,7 @@
q = self._insertSQL(table, names, values)
if self.debug:
print 'QueryIns: %s' % q
- c.execute(q)
+ DBAPI._executeRetry(self, conn, c, q)
if has_identity:
c.execute('SET IDENTITY_INSERT %s OFF' % table)
|
|
From: <sub...@co...> - 2005-10-28 11:34:58
|
Author: phd Date: 2005-10-28 11:34:54 +0000 (Fri, 28 Oct 2005) New Revision: 1160 Modified: home/phd/SQLObject/paramstyles/docs/News.txt home/phd/SQLObject/paramstyles/docs/sqlobject-admin.txt home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py Log: Merged revisions 1154:1159 from the trunk Modified: home/phd/SQLObject/paramstyles/docs/News.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/News.txt 2005-10-28 11:31:50 UTC (rev 1159) +++ home/phd/SQLObject/paramstyles/docs/News.txt 2005-10-28 11:34:54 UTC (rev 1160) @@ -29,6 +29,13 @@ instead you must manually create it (e.g., with explicit SQLObject classes for the joins). +* Added ``createSQL`` as an option for sqlmeta. Here you can add related SQL + you want executed by sqlobject-admin create after table creation. createSQL + expects a string, list, or dictionary. If using a dictionary the key should + be a dbName value (ex. 'postgres') and the value should be a string or list. + Examples in sqlobject/tests/test_sqlobject_admin.py or at + <http://sqlobject.org/sqlobject-admin.html#the-create-command> + SQLObject 0.7.0 =============== Modified: home/phd/SQLObject/paramstyles/docs/sqlobject-admin.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/sqlobject-admin.txt 2005-10-28 11:31:50 UTC (rev 1159) +++ home/phd/SQLObject/paramstyles/docs/sqlobject-admin.txt 2005-10-28 11:34:54 UTC (rev 1160) @@ -94,6 +94,19 @@ This finds the tables and creates them. Any tables that exist are simply skipped. +It also collects data from sqlmeta.createSQL and runs the queries +after table creation. createSQL can be a string with a single SQL +command, a list of SQL commands, or a dictionary with keys that are +dbNames and values that are either single SQL command string or a list +of SQL commands. An example follows:: + + class MyTable(SQLObject): + class sqlmeta: + createSQL = {'postgres': [ + "ALTER TABLE my_table ADD CHECK(my_field != '');", + ]} + myField = StringCol() + The ``sql`` Command ------------------- Modified: home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2005-10-28 11:31:50 UTC (rev 1159) +++ home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2005-10-28 11:34:54 UTC (rev 1160) @@ -16,14 +16,25 @@ if not sqlmodule: try: import adodbapi as sqlmodule - self.dbconnection = sqlmodule.Connection - self.make_conn_str = lambda keys: \ - ["Provider=SQLOLEDB;Data Source=%s;User Id=%s;Password=%s;Initial Catalog=%s" % ( - keys.host, keys.user, keys.password, keys.db)] - except: + self.dbconnection = sqlmodule.connect + # ADO uses unicode only (AFAIK) + self.usingUnicodeStrings = True + # MSDE does not allow SQL server login + if "sspi" in kw and kw["sspi"]: + self.make_conn_str = lambda keys: \ + ["Provider=SQLOLEDB;Data Source=%s;Initial Catalog=%s;Integrated Security=SSPI;Persist Security Info=False" % ( + keys.host, keys.db)] + del kw["sspi"] + else: + self.make_conn_str = lambda keys: \ + ["Provider=SQLOLEDB;Data Source=%s;User Id=%s;Password=%s;Initial Catalog=%s" % ( + keys.host, keys.user, keys.password, keys.db)] + except ImportError: # raise the exceptions other than ImportError for adodbapi absence import pymssql as sqlmodule self.dbconnection = sqlmodule.connect sqlmodule.Binary = lambda st: str(st) + # don't know whether pymssql uses unicode + self.usingUnicodeStrings = False self.make_conn_str = lambda keys: \ ["", keys.user, keys.password, keys.host, keys.db] self.autoCommit=autoCommit @@ -155,6 +166,8 @@ (tableName, column.dbName)) + # precision and scale is gotten from column table so that we can create + # decimal columns if needed SHOW_COLUMNS = """ select name, @@ -163,6 +176,8 @@ from systypes where cast(xusertype as int)= cast(sc.xtype as int) ) datatype, + prec, + scale, isnullable, cdefault, m.text default_text, @@ -181,11 +196,12 @@ colData = self.queryAll(self.SHOW_COLUMNS % tableName) results = [] - for field, size, t, nullAllowed, default, defaultText, is_identity in colData: + for field, size, t, precision, scale, nullAllowed, default, defaultText, is_identity in colData: # Seems strange to skip the pk column? What if it's not 'id'? if field == 'id': continue - colClass, kw = self.guessClass(t, size) + # precision is needed for decimal columns + colClass, kw = self.guessClass(t, size, precision, scale) kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field) kw['notNone'] = not nullAllowed if (defaultText): @@ -213,21 +229,30 @@ if auto == 0: option = "OFF" c = conn.cursor() - c.execute("SET AUTOCOMMIT "+option) + c.execute("SET AUTOCOMMIT " + option) conn.setconnectoption(SQL.AUTOCOMMIT, option) - def guessClass(self, t, size): + # precision and scale is needed for decimal columns + def guessClass(self, t, size, precision, scale): """ Here we take raw values coming out of syscolumns and map to SQLObject class types. """ if t.startswith('int'): return col.IntCol, {} elif t.startswith('varchar'): + if self.usingUnicodeStrings: + return col.UnicodeCol, {'length': size} return col.StringCol, {'length': size} elif t.startswith('char'): + if self.usingUnicodeStrings: + return col.UnicodeCol, {'length': size, + 'varchar': False} return col.StringCol, {'length': size, 'varchar': False} elif t.startswith('datetime'): return col.DateTimeCol, {} + elif t.startswith('decimal'): + return col.DecimalCol, {'size': precision, # be careful for awkward naming + 'precision': scale} else: return col.Col, {} Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py 2005-10-28 11:31:50 UTC (rev 1159) +++ home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py 2005-10-28 11:34:54 UTC (rev 1160) @@ -72,11 +72,14 @@ import re, fnmatch import operator import threading +import types + from converters import sqlrepr, registerConverter, TRUE, FALSE safeSQLRE = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_\.]*$') def sqlIdentifier(obj): - return type(obj) is type("") and not not safeSQLRE.search(obj.strip()) + # some db drivers return unicode column names + return isinstance(obj, types.StringTypes) and bool(safeSQLRE.search(obj.strip())) def execute(expr, executor): |
|
From: <sub...@co...> - 2005-10-28 11:31:58
|
Author: phd
Date: 2005-10-28 11:31:50 +0000 (Fri, 28 Oct 2005)
New Revision: 1159
Modified:
SQLObject/trunk/sqlobject/mssql/mssqlconnection.py
SQLObject/trunk/sqlobject/sqlbuilder.py
Log:
Applied a patch by Murat Ozsoyler <mur...@is...>.
Modified: SQLObject/trunk/sqlobject/mssql/mssqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mssql/mssqlconnection.py 2005-10-27 22:53:56 UTC (rev 1158)
+++ SQLObject/trunk/sqlobject/mssql/mssqlconnection.py 2005-10-28 11:31:50 UTC (rev 1159)
@@ -16,14 +16,25 @@
if not sqlmodule:
try:
import adodbapi as sqlmodule
- self.dbconnection = sqlmodule.Connection
- self.make_conn_str = lambda keys: \
- ["Provider=SQLOLEDB;Data Source=%s;User Id=%s;Password=%s;Initial Catalog=%s" % (
- keys.host, keys.user, keys.password, keys.db)]
- except:
+ self.dbconnection = sqlmodule.connect
+ # ADO uses unicode only (AFAIK)
+ self.usingUnicodeStrings = True
+ # MSDE does not allow SQL server login
+ if "sspi" in kw and kw["sspi"]:
+ self.make_conn_str = lambda keys: \
+ ["Provider=SQLOLEDB;Data Source=%s;Initial Catalog=%s;Integrated Security=SSPI;Persist Security Info=False" % (
+ keys.host, keys.db)]
+ del kw["sspi"]
+ else:
+ self.make_conn_str = lambda keys: \
+ ["Provider=SQLOLEDB;Data Source=%s;User Id=%s;Password=%s;Initial Catalog=%s" % (
+ keys.host, keys.user, keys.password, keys.db)]
+ except ImportError: # raise the exceptions other than ImportError for adodbapi absence
import pymssql as sqlmodule
self.dbconnection = sqlmodule.connect
sqlmodule.Binary = lambda st: str(st)
+ # don't know whether pymssql uses unicode
+ self.usingUnicodeStrings = False
self.make_conn_str = lambda keys: \
["", keys.user, keys.password, keys.host, keys.db]
self.autoCommit=autoCommit
@@ -155,6 +166,8 @@
(tableName,
column.dbName))
+ # precision and scale is gotten from column table so that we can create
+ # decimal columns if needed
SHOW_COLUMNS = """
select
name,
@@ -163,6 +176,8 @@
from systypes
where cast(xusertype as int)= cast(sc.xtype as int)
) datatype,
+ prec,
+ scale,
isnullable,
cdefault,
m.text default_text,
@@ -181,11 +196,12 @@
colData = self.queryAll(self.SHOW_COLUMNS
% tableName)
results = []
- for field, size, t, nullAllowed, default, defaultText, is_identity in colData:
+ for field, size, t, precision, scale, nullAllowed, default, defaultText, is_identity in colData:
# Seems strange to skip the pk column? What if it's not 'id'?
if field == 'id':
continue
- colClass, kw = self.guessClass(t, size)
+ # precision is needed for decimal columns
+ colClass, kw = self.guessClass(t, size, precision, scale)
kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
kw['notNone'] = not nullAllowed
if (defaultText):
@@ -213,21 +229,30 @@
if auto == 0:
option = "OFF"
c = conn.cursor()
- c.execute("SET AUTOCOMMIT "+option)
+ c.execute("SET AUTOCOMMIT " + option)
conn.setconnectoption(SQL.AUTOCOMMIT, option)
- def guessClass(self, t, size):
+ # precision and scale is needed for decimal columns
+ def guessClass(self, t, size, precision, scale):
"""
Here we take raw values coming out of syscolumns and map to SQLObject class types.
"""
if t.startswith('int'):
return col.IntCol, {}
elif t.startswith('varchar'):
+ if self.usingUnicodeStrings:
+ return col.UnicodeCol, {'length': size}
return col.StringCol, {'length': size}
elif t.startswith('char'):
+ if self.usingUnicodeStrings:
+ return col.UnicodeCol, {'length': size,
+ 'varchar': False}
return col.StringCol, {'length': size,
'varchar': False}
elif t.startswith('datetime'):
return col.DateTimeCol, {}
+ elif t.startswith('decimal'):
+ return col.DecimalCol, {'size': precision, # be careful for awkward naming
+ 'precision': scale}
else:
return col.Col, {}
Modified: SQLObject/trunk/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/trunk/sqlobject/sqlbuilder.py 2005-10-27 22:53:56 UTC (rev 1158)
+++ SQLObject/trunk/sqlobject/sqlbuilder.py 2005-10-28 11:31:50 UTC (rev 1159)
@@ -72,11 +72,14 @@
import re, fnmatch
import operator
import threading
+import types
+
from converters import sqlrepr, registerConverter, TRUE, FALSE
safeSQLRE = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_\.]*$')
def sqlIdentifier(obj):
- return type(obj) is type("") and not not safeSQLRE.search(obj.strip())
+ # some db drivers return unicode column names
+ return isinstance(obj, types.StringTypes) and bool(safeSQLRE.search(obj.strip()))
def execute(expr, executor):
|
|
From: <sub...@co...> - 2005-10-27 22:54:02
|
Author: test
Date: 2005-10-27 22:53:56 +0000 (Thu, 27 Oct 2005)
New Revision: 1158
Modified:
SQLObject/trunk/docs/sqlobject-admin.txt
Log:
Little layout fix
Modified: SQLObject/trunk/docs/sqlobject-admin.txt
===================================================================
--- SQLObject/trunk/docs/sqlobject-admin.txt 2005-10-27 18:09:39 UTC (rev 1157)
+++ SQLObject/trunk/docs/sqlobject-admin.txt 2005-10-27 22:53:56 UTC (rev 1158)
@@ -98,12 +98,13 @@
after table creation. createSQL can be a string with a single SQL
command, a list of SQL commands, or a dictionary with keys that are
dbNames and values that are either single SQL command string or a list
-of SQL commands. An example follows:
+of SQL commands. An example follows::
-::
class MyTable(SQLObject):
class sqlmeta:
- createSQL = {'postgres': ["ALTER TABLE my_table ADD CHECK(my_field != '');"]}
+ createSQL = {'postgres': [
+ "ALTER TABLE my_table ADD CHECK(my_field != '');",
+ ]}
myField = StringCol()
The ``sql`` Command
|
|
From: <sub...@co...> - 2005-10-27 16:37:11
|
Author: phd
Date: 2005-10-27 16:37:05 +0000 (Thu, 27 Oct 2005)
New Revision: 1156
Modified:
SQLObject/trunk/sqlobject/mssql/mssqlconnection.py
Log:
Removed trailing spaces.
Modified: SQLObject/trunk/sqlobject/mssql/mssqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mssql/mssqlconnection.py 2005-10-27 16:32:02 UTC (rev 1155)
+++ SQLObject/trunk/sqlobject/mssql/mssqlconnection.py 2005-10-27 16:37:05 UTC (rev 1156)
@@ -67,7 +67,7 @@
ON obj.id = col.id
WHERE obj.name = '%s'
and col.autoval is not null
-
+
"""
def _hasIdentity(self, conn, table):
query = self.HAS_IDENTITY % table
@@ -95,7 +95,7 @@
del values[i]
except ValueError:
pass
-
+
if has_identity:
if id is not None:
c.execute('SET IDENTITY_INSERT %s ON' % table)
@@ -156,11 +156,11 @@
column.dbName))
SHOW_COLUMNS = """
- select
- name,
- length,
- ( select name
- from systypes
+ select
+ name,
+ length,
+ ( select name
+ from systypes
where cast(xusertype as int)= cast(sc.xtype as int)
) datatype,
isnullable,
@@ -170,13 +170,13 @@
from syscolumns sc
LEFT OUTER JOIN syscomments m on sc.cdefault = m.id
AND m.colid = 1
- where
- sc.id in (select id
- from sysobjects
+ where
+ sc.id in (select id
+ from sysobjects
where name = '%s')
order by
colorder"""
-
+
def columnsFromSchema(self, tableName, soClass):
colData = self.queryAll(self.SHOW_COLUMNS
% tableName)
@@ -189,7 +189,7 @@
kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
kw['notNone'] = not nullAllowed
if (defaultText):
- # Strip ( and )
+ # Strip ( and )
defaultText = defaultText[1:-1]
if defaultText[0] == "'":
defaultText = defaultText[1:-1]
|
|
From: <sub...@co...> - 2005-10-27 16:32:13
|
Author: ianb Date: 2005-10-27 16:32:02 +0000 (Thu, 27 Oct 2005) New Revision: 1155 Modified: SQLObject/trunk/docs/News.txt Log: added blurb about createSQL option for sqlmeta data. Modified: SQLObject/trunk/docs/News.txt =================================================================== --- SQLObject/trunk/docs/News.txt 2005-10-27 16:27:58 UTC (rev 1154) +++ SQLObject/trunk/docs/News.txt 2005-10-27 16:32:02 UTC (rev 1155) @@ -29,6 +29,13 @@ instead you must manually create it (e.g., with explicit SQLObject classes for the joins). +* Added ``createSQL`` as an option for sqlmeta. Here you can add related SQL + you want executed by sqlobject-admin create after table creation. createSQL + expects a string, list, or dictionary. If using a dictionary the key should + be a dbName value (ex. 'postgres') and the value should be a string or list. + Examples in sqlobject/tests/test_sqlobject_admin.py or at + <http://sqlobject.org/sqlobject-admin.html#the-create-command> + SQLObject 0.7.0 =============== |
Author: phd Date: 2005-10-27 16:27:58 +0000 (Thu, 27 Oct 2005) New Revision: 1154 Added: home/phd/SQLObject/paramstyles/sqlobject/tests/test_csvexport.py home/phd/SQLObject/paramstyles/sqlobject/tests/test_string_id.py home/phd/SQLObject/paramstyles/sqlobject/util/csvexport.py Modified: home/phd/SQLObject/paramstyles/docs/DeveloperGuide.txt home/phd/SQLObject/paramstyles/docs/FAQ.txt home/phd/SQLObject/paramstyles/docs/News.txt home/phd/SQLObject/paramstyles/docs/SQLBuilder.txt home/phd/SQLObject/paramstyles/docs/SQLObject.txt home/phd/SQLObject/paramstyles/docs/interface.py home/phd/SQLObject/paramstyles/setup.cfg home/phd/SQLObject/paramstyles/sqlobject/col.py home/phd/SQLObject/paramstyles/sqlobject/conftest.py home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py home/phd/SQLObject/paramstyles/sqlobject/joins.py home/phd/SQLObject/paramstyles/sqlobject/main.py home/phd/SQLObject/paramstyles/sqlobject/manager/command.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/sresults.py home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py home/phd/SQLObject/paramstyles/sqlobject/tests/test_basic.py Log: Merged patches from revisions 1073:1150 from the trunk Modified: home/phd/SQLObject/paramstyles/docs/DeveloperGuide.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/DeveloperGuide.txt 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/docs/DeveloperGuide.txt 2005-10-27 16:27:58 UTC (rev 1154) @@ -25,7 +25,7 @@ Then do the same for SQLObject:: - $ svn co http://svn.colorstudy.com/trunk/SQLObject SQLObject + $ svn co http://svn.colorstudy.com/SQLObject/trunk SQLObject $ cd SQLObject $ sudo python setup.py develop @@ -149,7 +149,7 @@ its `getting started`_ document for more. .. __: http://codespeak.net/py/current/doc/test.html -.. _getting started: http://codespeak.net/py/current/doc/getting_started.html +.. _getting started: http://codespeak.net/py/current/doc/getting-started.html To actually run the test, you have to give it a database to connect to. You do this with the ``TESTDB`` environmental variable (right now Modified: home/phd/SQLObject/paramstyles/docs/FAQ.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/FAQ.txt 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/docs/FAQ.txt 2005-10-27 16:27:58 UTC (rev 1154) @@ -279,14 +279,13 @@ Non-Integer IDs --------------- -Yes, you can use non-integer IDs, but only in CVS_ now. +Yes, you can use non-integer IDs. -.. _CVS: http://sqlobject.org/#anonymous-cvs +If you use non-integer IDs, you will not be able to use automatic ``CREATE +TABLE`` generation (i.e., ``createTable``); SQLObject can create tables +with int or str IDs. You also will have to give your own ID values when +creating an object, like:: -If you use non-integer IDs, you will not be able to use automatic -``CREATE TABLE`` generation (i.e., ``createTable``). You also will -have to give your own ID values when creating an object, like:: - color = Something(id="blue", r=0, b=100, g=0) IDs are, and always will in future versions, be considered immutable. @@ -308,7 +307,7 @@ This will be resolved in a future version when ID column types can be declared like other columns. -Additionally you can set _idType = str in you SQLObject class. +Additionally you can set idType=str in you SQLObject class. Binary Values Modified: home/phd/SQLObject/paramstyles/docs/News.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/News.txt 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/docs/News.txt 2005-10-27 16:27:58 UTC (rev 1154) @@ -23,6 +23,12 @@ * Added ``TimeCol``. +* ``RelatedJoin`` and ``SQLRelatedJoin`` objects have a + ``createRelatedTable`` keyword argument (default ``True``). If + ``False``, then the related table won't be automatically created; + instead you must manually create it (e.g., with explicit SQLObject + classes for the joins). + SQLObject 0.7.0 =============== Modified: home/phd/SQLObject/paramstyles/docs/SQLBuilder.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/SQLBuilder.txt 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/docs/SQLBuilder.txt 2005-10-27 16:27:58 UTC (rev 1154) @@ -3,7 +3,7 @@ `````````` A number of variables from SQLBuilder are included with ``from -SQLObject import *`` -- see the `relevant SQLObject documentation`_ +sqlobject import *`` -- see the `relevant SQLObject documentation`_ for more. Its functionality is also available through the special ``q`` attribute of `SQLObject` classes. @@ -20,7 +20,7 @@ of a table class -- this gives you an object that represents the field. Maybe explanations aren't as good. Here's some examples:: - >>> from SQLBuilder import * + >>> from sqlobject.sqlbuilder import * >>> person = table.person # person is now equivalent to the Person.q object from the SQLObject # documentation @@ -43,7 +43,7 @@ # This isn't what you want: >> person.first_name == 'John' & person.last_name == 'Doe' - (person.first_name = ('John' AND person.last_name)) = 'Doe' + (person.first_name = ('John' AND person.last_name)) = 'Doe') # This is: >> (person.first_name == 'John') & (person.last_name == 'Doe') ((person.first_name = 'John') AND (person.last_name == 'Doe')) Modified: home/phd/SQLObject/paramstyles/docs/SQLObject.txt =================================================================== --- home/phd/SQLObject/paramstyles/docs/SQLObject.txt 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/docs/SQLObject.txt 2005-10-27 16:27:58 UTC (rev 1154) @@ -1396,11 +1396,12 @@ Non-Integer Keys ---------------- -While not strictly a legacy database issue, this fits into the -category of "irregularities". If you use non-integer keys, all -primary key management is up to you. You must create the table -yourself, and when you create instances you must pass a ``id`` keyword -argument into constructor (like ``Person(id='555-55-5555', ...)``). +While not strictly a legacy database issue, this fits into the category of +"irregularities". If you use non-integer keys, all primary key management +is up to you. You must create the table yourself (SQLObject can create +tables with int or str IDs), and when you create instances you must pass a +``id`` keyword argument into constructor +(like ``Person(id='555-55-5555', ...)``). DBConnection: Database Connections ================================== @@ -1667,6 +1668,15 @@ and ALL(). The last 3 are used with comparison operators, like this: "somevalue = ANY(Select(...))". +Utilities +--------- + +Some useful utility functions are included with SQLObject. For more +information see their module docstrings. + +* `sqlobject.util.csvexport + <http://sqlobject.org/module-sqlobject.util.csvexport.html>`_ + SQLBuilder ---------- Modified: home/phd/SQLObject/paramstyles/docs/interface.py =================================================================== --- home/phd/SQLObject/paramstyles/docs/interface.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/docs/interface.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -254,7 +254,22 @@ Adds the index to the class. """ + def asDict(): + """ + Returns the SQLObject instance as a dictionary (column names + as keys, column values as values). + Use like:: + + ASQLObjectClass(a=1, b=2).asDict() + + Which should return ``{'a': 1, 'b': 2}``. + + Note: this is a *copy* of the object's columns; changing the + dictionary will not effect the object it was created from. + """ + + class ICol(Interface): def __init__(name=None, **kw): Modified: home/phd/SQLObject/paramstyles/setup.cfg =================================================================== --- home/phd/SQLObject/paramstyles/setup.cfg 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/setup.cfg 2005-10-27 16:27:58 UTC (rev 1154) @@ -31,5 +31,9 @@ [publish] doc-dir = docs/html -doc-dest = scp://ianbicking@shell.sf.net/home/groups/s/sq/sqlobject/htdocs/ make-dirs = 1 + +## For live documentation: +# doc-dest = scp://ianbicking@shell.sf.net/home/groups/s/sq/sqlobject/htdocs/ +## For in-development documentation: +doc-dest = scp://ianbicking@shell.sf.net/home/groups/s/sq/sqlobject/htdocs/devel/ Modified: home/phd/SQLObject/paramstyles/sqlobject/col.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/col.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/col.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -687,31 +687,22 @@ class SOKeyCol(SOCol): + key_type = {int: "INT", str: "TEXT"} # 3-03 @@: this should have a simplified constructor # Should provide foreign key information for other DBs. - def _mysqlType(self): - return 'INT' + def _sqlType(self): + return self.key_type[self.soClass.sqlmeta.idType] - def _sqliteType(self): - return 'INT' - - def _postgresType(self): - return 'INT' - def _sybaseType(self): - return 'NUMERIC(18,0) NULL' + key_type = {int: "NUMERIC(18,0) NULL", str: "TEXT"} + return key_type[self.soClass.sqlmeta.idType] def _mssqlType(self): - return 'INT NULL' + key_type = {int: "INT NULL", str: "TEXT"} + return key_type[self.soClass.sqlmeta.idType] - def _firebirdType(self): - return 'INT' - - def _maxdbType(self): - return 'INT' - class KeyCol(Col): baseClass = SOKeyCol @@ -758,6 +749,31 @@ 'sTName': sTName}) return constraint + def mysqlCreateSQL(self): + sql = SOKeyCol.mysqlCreateSQL(self) + other = findClass(self.foreignKey, self.soClass.sqlmeta.registry) + tName = other.sqlmeta.table + idName = other.sqlmeta.idName + if self.cascade is not None: + if self.cascade == 'null': + action = 'ON DELETE SET NULL' + elif self.cascade: + action = 'ON DELETE CASCADE' + else: + action = 'ON DELETE RESTRICT' + else: + action = '' + constraint = ('CONSTRAINT %(colName)s_exists ' + 'FOREIGN KEY (%(colName)s) ' + 'REFERENCES %(tName)s (%(idName)s) ' + '%(action)s' % + {'tName': tName, + 'colName': self.dbName, + 'idName': idName, + 'action': action}) + sql = ', '.join([sql, constraint]) + return sql + def sybaseCreateSQL(self): sql = SOKeyCol.sybaseCreateSQL(self) other = findClass(self.foreignKey) Modified: home/phd/SQLObject/paramstyles/sqlobject/conftest.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/conftest.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/conftest.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -17,7 +17,7 @@ 'postgres': 'postgres:///test', 'postgresql': 'postgres:///test', 'pygresql': 'pygresql://localhost/test', - 'sqlite': 'sqlite:///%s/data/sqlite.data' % os.getcwd(), + 'sqlite': 'sqlite:/:memory:', 'sybase': 'sybase://test:test123@sybase/test?autoCommit=0', 'firebird': 'firebird://sysdba:masterkey@localhost/var/lib/firebird/data/test.gdb', 'mssql': 'mssql://sa:@127.0.0.1/test' Modified: home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -131,7 +131,8 @@ return col.firebirdCreateSQL() def createIDColumn(self, soClass): - return '%s INT NOT NULL PRIMARY KEY' % soClass.sqlmeta.idName + key_type = {int: "INT", str: "TEXT"}[soClass.sqlmeta.idType] + return '%s %s NOT NULL PRIMARY KEY' % (soClass.sqlmeta.idName, key_type) def createIndexSQL(self, soClass, index): return index.firebirdCreateIndexSQL(soClass) Modified: home/phd/SQLObject/paramstyles/sqlobject/joins.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/joins.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/joins.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -154,9 +154,12 @@ def __init__(self, otherColumn=None, - intermediateTable=None, **kw): + intermediateTable=None, + createRelatedTable=True, + **kw): self.intermediateTable = intermediateTable self.otherColumn = otherColumn + self.createRelatedTable = createRelatedTable SOMultipleJoin.__init__(self, **kw) classregistry.registry( self.soClass.sqlmeta.registry).addClassCallback( Modified: home/phd/SQLObject/paramstyles/sqlobject/main.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/main.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/main.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -7,15 +7,17 @@ SQLObject is a object-relational mapper. See SQLObject.html or SQLObject.txt for more. -Modified by +Modified by: - Daniel Savard, Xsoli Inc <sqlobject xsoli.com> 7 Feb 2004 - - Added support for simple table inheritance. +* Daniel Savard, Xsoli Inc <sqlobject xsoli.com> 7 Feb 2004 + Added support for simple table inheritance. - Oleg Broytmann, SIA "ANK" <ph...@ph...> 3 Feb 2005 - - Split inheritance support into a number of separate modules and classes - - InheritableSQLObject at al. +* Oleg Broytmann, SIA "ANK" <ph...@ph...> 3 Feb 2005 + Split inheritance support into a number of separate modules and classes - + InheritableSQLObject at al. +* And others... + This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the @@ -562,6 +564,16 @@ cls.indexes.append(index) addIndex = classmethod(addIndex) + ######################################## + ## Utility methods + ######################################## + + def asDict(self): + result = {} + for key in self.columns: + result[key] = getattr(self.instance, key) + return result + sqlhub = dbconnection.ConnectionHub() class _sqlmeta_attr(object): @@ -1329,6 +1341,9 @@ def createJoinTables(cls, ifNotExists=False, connection=None): conn = connection or cls._connection for join in cls._getJoinsToCreate(): + if not getattr(join, 'createRelatedTable', True): + # This join has requested not to be created + continue if (ifNotExists and conn.tableExists(join.intermediateTable)): continue @@ -1339,6 +1354,9 @@ conn = connection or cls._connection sql = [] for join in cls._getJoinsToCreate(): + if not getattr(join, 'createRelatedTable', True): + # This join has requested not to be created + continue sql.append(conn._SO_createJoinTableSQL(join)) return '\n'.join(sql) createJoinTablesSQL = classmethod(createJoinTablesSQL) Modified: home/phd/SQLObject/paramstyles/sqlobject/manager/command.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/manager/command.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/manager/command.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -427,7 +427,7 @@ if not dist.has_metadata('sqlobject.txt'): if warn_no_sqlobject: print 'No sqlobject.txt in %s egg info' % egg_spec - return {} + return None, {} result = {} for line in dist.get_metadata_lines('sqlobject.txt'): line = line.strip() @@ -436,7 +436,7 @@ name, value = line.split('=', 1) name = name.strip().lower() if name in result: - print 'Warning: %s appears more than one in sqlobject.txt' % name + print 'Warning: %s appears more than once in sqlobject.txt' % name result[name.strip().lower()] = value.strip() return dist, result @@ -859,6 +859,12 @@ + '_' + dbName + '.sql') if sim: continue + create, constraints = cls.createTableSQL() + if constraints: + constraints = '\n-- Constraints:\n%s\n' % ( + '\n'.join(constraints)) + else: + constraints = '' files[fn] = ''.join([ '-- Exported definition from %s\n' % time.strftime('%Y-%m-%dT%H:%M:%S'), @@ -866,8 +872,9 @@ % (cls.__module__, cls.__name__), '-- Database: %s\n' % dbName, - cls.createTableSQL().strip(), - '\n']) + create.strip(), + '\n', + constraints]) last_version_dir = self.find_last_version() if last_version_dir and not self.options.force_create: if v > 1: Modified: home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -1,16 +1,17 @@ """ -Contributed by Edigram SAS,Paris France -Tel:01 44 77 94 00 +Contributed by Edigram SAS, Paris France Tel:01 44 77 94 00 Ahmed MOHAMED ALI <ahm...@ya...> 27 April 2004 -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -connection creation sample -__connection__ = DBConnection.maxdbConnection( - host=hostname, database=dbname, - user=user_name, password=user_password,autoCommit=1,debug=1) +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +connection creation sample:: + + __connection__ = DBConnection.maxdbConnection( + host=hostname, database=dbname, + user=user_name, password=user_password,autoCommit=1,debug=1) """ from sqlobject.dbconnection import DBAPI from sqlobject import col @@ -172,7 +173,8 @@ return col.maxdbCreateSQL() def createIDColumn(self, soClass): - return '%s INT PRIMARY KEY' % soClass.sqlmeta.idName + key_type = {int: "INT", str: "TEXT"}[soClass.sqlmeta.idType] + return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type) def createIndexSQL(self, soClass, index): return index.maxdbCreateIndexSQL(soClass) Modified: home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -72,7 +72,7 @@ def _hasIdentity(self, conn, table): query = self.HAS_IDENTITY % table c = conn.cursor() - DBAPI._executeRetry(self, conn, c, query) + c.execute(query) r = c.fetchone() return r is not None @@ -105,7 +105,7 @@ q = self._insertSQL(table, names, values) if self.debug: print 'QueryIns: %s' % q - DBAPI._executeRetry(self, conn, c, q) + c.execute(q) if has_identity: c.execute('SET IDENTITY_INSERT %s OFF' % table) @@ -129,7 +129,8 @@ return col.mssqlCreateSQL() def createIDColumn(self, soClass): - return '%s INT IDENTITY UNIQUE' % soClass.sqlmeta.idName + key_type = {int: "INT", str: "TEXT"}[soClass.sqlmeta.idType] + return '%s %s IDENTITY UNIQUE' % (soClass.sqlmeta.idName, key_type) def createIndexSQL(self, soClass, index): return index.mssqlCreateIndexSQL(soClass) @@ -212,7 +213,7 @@ if auto == 0: option = "OFF" c = conn.cursor() - c.execute("SET AUTOCOMMIT " + option) + c.execute("SET AUTOCOMMIT "+option) conn.setconnectoption(SQL.AUTOCOMMIT, option) def guessClass(self, t, size): Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -99,6 +99,8 @@ return index.mysqlCreateIndexSQL(soClass) def createIDColumn(self, soClass): + if soClass.sqlmeta.idType == str: + return '%s TEXT PRIMARY KEY' % soClass.sqlmeta.idName return '%s INT PRIMARY KEY AUTO_INCREMENT' % soClass.sqlmeta.idName def joinSQLType(self, join): Modified: home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -145,7 +145,8 @@ return index.postgresCreateIndexSQL(soClass) def createIDColumn(self, soClass): - return '%s SERIAL PRIMARY KEY' % soClass.sqlmeta.idName + key_type = {int: "SERIAL", str: "TEXT"}[soClass.sqlmeta.idType] + return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type) def dropTable(self, tableName, cascade=False): if self.server_version[:3] <= "7.2": @@ -248,7 +249,7 @@ def guessClass(self, t): if t.count('int'): return col.IntCol, {} - elif t.count('varying'): + elif t.count('varying') or t.count('varchar'): if '(' in t: return col.StringCol, {'length': int(t[t.index('(')+1:-1])} else: # varchar without length in Postgres means any length @@ -256,10 +257,16 @@ elif t.startswith('character('): return col.StringCol, {'length': int(t[t.index('(')+1:-1]), 'varchar': False} + elif t.count('float') or t.count('real') or t.count('double'): + return col.FloatCol, {} elif t == 'text': return col.StringCol, {} + elif t.startswith('timestamp'): + return col.DateTimeCol, {} elif t.startswith('datetime'): return col.DateTimeCol, {} + elif t.startswith('date'): + return col.DateCol, {} elif t.startswith('bool'): return col.BoolCol, {} elif t.startswith('bytea'): Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -120,7 +120,8 @@ return None def createIDColumn(self, soClass): - return '%s INTEGER PRIMARY KEY' % soClass.sqlmeta.idName + key_type = {int: "INTEGER", str: "TEXT"}[soClass.sqlmeta.idType] + return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type) def joinSQLType(self, join): return 'INT NOT NULL' Modified: home/phd/SQLObject/paramstyles/sqlobject/sresults.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/sresults.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/sresults.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -91,7 +91,13 @@ self.clauseTables, **self.ops) def filter(self, filter_clause): - return self.newClause(sqlbuilder.AND(self.clause, filter_clause)) + if filter_clause is None: + # None doesn't filter anything, it's just a no-op: + return self + clause = self.clause + if isinstance(clause, (str, unicode)): + clause = sqlbuilder.SQLConstant('(%s)' % self.clause) + return self.newClause(sqlbuilder.AND(clause, filter_clause)) def __getitem__(self, value): if type(value) is type(slice(1)): Modified: home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -102,7 +102,8 @@ return col.sybaseCreateSQL() def createIDColumn(self, soClass): - return '%s NUMERIC(18,0) IDENTITY UNIQUE' % soClass.sqlmeta.idName + key_type = {int: "NUMERIC(18,0)", str: "TEXT"}[soClass.sqlmeta.idType] + return '%s %s IDENTITY UNIQUE' % (soClass.sqlmeta.idName, key_type) def createIndexSQL(self, soClass, index): return index.sybaseCreateIndexSQL(soClass) Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -211,15 +211,17 @@ def d(**kw): """ - Because dict(**kw) doesn't work in Python 2.2, this is a + Because ``dict(**kw)`` doesn't work in Python 2.2, this is a replacement. """ return kw def inserts(cls, data, schema=None): """ - Creates a bunch of rows. You can use it like:: + Creates a bunch of rows. + You can use it like:: + inserts(Person, [{'fname': 'blah', 'lname': 'doe'}, ...]) Or:: Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_basic.py =================================================================== --- home/phd/SQLObject/paramstyles/sqlobject/tests/test_basic.py 2005-10-27 16:24:26 UTC (rev 1153) +++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_basic.py 2005-10-27 16:27:58 UTC (rev 1154) @@ -275,3 +275,9 @@ assert dep1.other is None assert dep2.other is None assert dep3.other is obj2 + +def testAsDict(): + setupGetters(TestSO1) + bob = TestSO1.selectBy(name='bob')[0] + assert bob.sqlmeta.asDict() == {'passwd': 'tbq', 'name': 'bob'} + Copied: home/phd/SQLObject/paramstyles/sqlobject/tests/test_csvexport.py (from rev 1150, SQLObject/trunk/sqlobject/tests/test_csvexport.py) Copied: home/phd/SQLObject/paramstyles/sqlobject/tests/test_string_id.py (from rev 1150, SQLObject/trunk/sqlobject/tests/test_string_id.py) Copied: home/phd/SQLObject/paramstyles/sqlobject/util/csvexport.py (from rev 1150, SQLObject/trunk/sqlobject/util/csvexport.py) |
|
From: <sub...@co...> - 2005-10-27 16:24:34
|
Author: ianb
Date: 2005-10-27 16:24:26 +0000 (Thu, 27 Oct 2005)
New Revision: 1153
Added:
SQLObject/trunk/sqlobject/tests/test_sqlobject_admin.py
Log:
added some test examples for createSQL that are not yet enabled, but are a useful reference.
Added: SQLObject/trunk/sqlobject/tests/test_sqlobject_admin.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_sqlobject_admin.py 2005-10-27 16:20:12 UTC (rev 1152)
+++ SQLObject/trunk/sqlobject/tests/test_sqlobject_admin.py 2005-10-27 16:24:26 UTC (rev 1153)
@@ -0,0 +1,42 @@
+"""
+These Tests are not enabled yet, but here are some working examples of using createSQL so far.
+"""
+
+from sqlobject import *
+
+sqlhub.processConnection = connectionForURI('postgres://pgsql@/db_test')
+
+class Test1(SQLObject):
+ class sqlmeta:
+ createSQL = "CREATE SEQUENCE db_test1_seq;"
+ test1 = StringCol()
+
+class Test2(SQLObject):
+ class sqlmeta:
+ createSQL = ["CREATE SEQUENCE db_test2_seq;",
+ "ALTER TABLE test2 ADD CHECK(test2 != '');"
+ ]
+ test2 = StringCol()
+
+
+class Test3(SQLObject):
+ class sqlmeta:
+ createSQL = {'postgres': 'CREATE SEQUENCE db_test3_seq;',
+ 'mysql': 'CREATE SEQUENCE db_test3_seq;'}
+ test3 = StringCol()
+
+
+class Test4(SQLObject):
+ class sqlmeta:
+ createSQL = {'postgres': ['CREATE SEQUENCE db_test4_seq;',
+ "ALTER TABLE test4 ADD CHECK(test4 != '');"
+ ],
+ 'mysql': 'CREATE SEQUENCE db_test4_seq;'}
+ test4 = StringCol()
+
+
+class Test5(SQLObject):
+ class sqlmeta:
+ createSQL = {'mysql': 'CREATE SEQUENCE db_test5_seq;'}
+ test5 = StringCol()
+
|
|
From: <sub...@co...> - 2005-10-27 16:20:26
|
Author: ianb
Date: 2005-10-27 16:20:12 +0000 (Thu, 27 Oct 2005)
New Revision: 1152
Modified:
SQLObject/trunk/docs/sqlobject-admin.txt
Log:
added an example of using createSQL
Modified: SQLObject/trunk/docs/sqlobject-admin.txt
===================================================================
--- SQLObject/trunk/docs/sqlobject-admin.txt 2005-10-27 16:03:44 UTC (rev 1151)
+++ SQLObject/trunk/docs/sqlobject-admin.txt 2005-10-27 16:20:12 UTC (rev 1152)
@@ -94,6 +94,18 @@
This finds the tables and creates them. Any tables that exist are
simply skipped.
+It also collects data from sqlmeta.createSQL and runs the queries
+after table creation. createSQL can be a string with a single SQL
+command, a list of SQL commands, or a dictionary with keys that are
+dbNames and values that are either single SQL command string or a list
+of SQL commands. An example follows:
+
+::
+ class MyTable(SQLObject):
+ class sqlmeta:
+ createSQL = {'postgres': ["ALTER TABLE my_table ADD CHECK(my_field != '');"]}
+ myField = StringCol()
+
The ``sql`` Command
-------------------
|
|
From: <sub...@co...> - 2005-10-27 16:03:54
|
Author: ianb
Date: 2005-10-27 16:03:44 +0000 (Thu, 27 Oct 2005)
New Revision: 1151
Modified:
SQLObject/trunk/sqlobject/manager/command.py
Log:
added code to CommandCreate that collects data from sqlmeta.createSQL and runs the queries after table creation. createSQL can be a string with a single SQL command, a list of SQL commands, or a dictionary with keys that are dbNames and a single SQL command string or a list of SQL commands as strings.
Modified: SQLObject/trunk/sqlobject/manager/command.py
===================================================================
--- SQLObject/trunk/sqlobject/manager/command.py 2005-10-27 02:55:52 UTC (rev 1150)
+++ SQLObject/trunk/sqlobject/manager/command.py 2005-10-27 16:03:44 UTC (rev 1151)
@@ -550,6 +550,7 @@
existing = 0
dbs_created = []
constraints = {}
+ createSQLs = {}
for soClass in self.classes(require_some=True):
if (self.options.create_db
and soClass._connection not in dbs_created):
@@ -560,6 +561,8 @@
dbs_created.append(soClass._connection)
if soClass._connection not in constraints.keys():
constraints[soClass._connection] = []
+ if soClass._connection not in createSQLs.keys():
+ createSQLs[soClass._connection] = []
exists = soClass._connection.tableExists(soClass.sqlmeta.table)
if v >= 1:
if exists:
@@ -577,7 +580,16 @@
tableConstraints = soClass.createTable()
if tableConstraints:
constraints[soClass._connection].append(tableConstraints)
-
+ tableCreateSQLs = getattr(soClass.sqlmeta, 'createSQL', None)
+ if tableCreateSQLs:
+ assert isinstance(tableCreateSQLs,(str,list,dict)), (
+ '%s.sqlmeta.createSQL must be a str, list or dict.' %
+ (soClass.__name__))
+ if isinstance(tableCreateSQLs, dict):
+ tableCreateSQLs = tableCreateSQLs.get(soClass._connection.dbName, [])
+ if isinstance(tableCreateSQLs, str):
+ tableCreateSQLs = [tableCreateSQLs]
+ createSQLs[soClass._connection].append(tableCreateSQLs)
else:
print 'Cancelled'
else:
@@ -585,11 +597,26 @@
tableConstraints = soClass.createTable()
if tableConstraints:
constraints[soClass._connection].append(tableConstraints)
+ tableCreateSQLs = getattr(soClass.sqlmeta, 'createSQL', None)
+ if tableCreateSQLs:
+ assert isinstance(tableCreateSQLs,(str,list,dict)), (
+ '%s.sqlmeta.createSQL must be a str, list or dict.' %
+ (soClass.__name__))
+ if isinstance(tableCreateSQLs, dict):
+ tableCreateSQLs = tableCreateSQLs.get(soClass._connection.dbName, [])
+ if isinstance(tableCreateSQLs, str):
+ tableCreateSQLs = [tableCreateSQLs]
+ createSQLs[soClass._connection].append(tableCreateSQLs)
for connection in constraints.keys():
for constraintList in constraints[connection]:
for constraint in constraintList:
if constraint:
connection.query(constraint)
+ for connection in createSQLs.keys():
+ for createSQLsList in createSQLs[connection]:
+ for createSQL in createSQLsList:
+ if createSQL:
+ connection.query(createSQL)
if v >= 1:
print '%i tables created (%i already exist)' % (
created, existing)
|
|
From: <sub...@co...> - 2005-10-26 23:40:45
|
Author: test Date: 2005-10-26 23:40:41 +0000 (Wed, 26 Oct 2005) New Revision: 1149 Modified: SQLObject/trunk/sqlobject/main.py SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py SQLObject/trunk/sqlobject/tests/dbtest.py Log: Fix up some docstrings for better reSTability Modified: SQLObject/trunk/sqlobject/main.py =================================================================== --- SQLObject/trunk/sqlobject/main.py 2005-10-26 23:40:00 UTC (rev 1148) +++ SQLObject/trunk/sqlobject/main.py 2005-10-26 23:40:41 UTC (rev 1149) @@ -7,15 +7,17 @@ SQLObject is a object-relational mapper. See SQLObject.html or SQLObject.txt for more. -Modified by +Modified by: - Daniel Savard, Xsoli Inc <sqlobject xsoli.com> 7 Feb 2004 - - Added support for simple table inheritance. +* Daniel Savard, Xsoli Inc <sqlobject xsoli.com> 7 Feb 2004 + Added support for simple table inheritance. - Oleg Broytmann, SIA "ANK" <ph...@ph...> 3 Feb 2005 - - Split inheritance support into a number of separate modules and classes - - InheritableSQLObject at al. +* Oleg Broytmann, SIA "ANK" <ph...@ph...> 3 Feb 2005 + Split inheritance support into a number of separate modules and classes - + InheritableSQLObject at al. +* And others... + This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the Modified: SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py =================================================================== --- SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py 2005-10-26 23:40:00 UTC (rev 1148) +++ SQLObject/trunk/sqlobject/maxdb/maxdbconnection.py 2005-10-26 23:40:41 UTC (rev 1149) @@ -1,16 +1,17 @@ """ -Contributed by Edigram SAS,Paris France -Tel:01 44 77 94 00 +Contributed by Edigram SAS, Paris France Tel:01 44 77 94 00 Ahmed MOHAMED ALI <ahm...@ya...> 27 April 2004 -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -connection creation sample -__connection__ = DBConnection.maxdbConnection( - host=hostname, database=dbname, - user=user_name, password=user_password,autoCommit=1,debug=1) +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +connection creation sample:: + + __connection__ = DBConnection.maxdbConnection( + host=hostname, database=dbname, + user=user_name, password=user_password,autoCommit=1,debug=1) """ from sqlobject.dbconnection import DBAPI from sqlobject import col Modified: SQLObject/trunk/sqlobject/tests/dbtest.py =================================================================== --- SQLObject/trunk/sqlobject/tests/dbtest.py 2005-10-26 23:40:00 UTC (rev 1148) +++ SQLObject/trunk/sqlobject/tests/dbtest.py 2005-10-26 23:40:41 UTC (rev 1149) @@ -211,15 +211,17 @@ def d(**kw): """ - Because dict(**kw) doesn't work in Python 2.2, this is a + Because ``dict(**kw)`` doesn't work in Python 2.2, this is a replacement. """ return kw def inserts(cls, data, schema=None): """ - Creates a bunch of rows. You can use it like:: + Creates a bunch of rows. + You can use it like:: + inserts(Person, [{'fname': 'blah', 'lname': 'doe'}, ...]) Or:: |
|
From: <sub...@co...> - 2005-10-26 23:40:09
|
Author: test
Date: 2005-10-26 23:40:00 +0000 (Wed, 26 Oct 2005)
New Revision: 1148
Modified:
SQLObject/trunk/sqlobject/conftest.py
Log:
Make sqlite memory database the default, since it's spiffy and fast
Modified: SQLObject/trunk/sqlobject/conftest.py
===================================================================
--- SQLObject/trunk/sqlobject/conftest.py 2005-10-26 23:38:31 UTC (rev 1147)
+++ SQLObject/trunk/sqlobject/conftest.py 2005-10-26 23:40:00 UTC (rev 1148)
@@ -17,7 +17,7 @@
'postgres': 'postgres:///test',
'postgresql': 'postgres:///test',
'pygresql': 'pygresql://localhost/test',
- 'sqlite': 'sqlite:///%s/data/sqlite.data' % os.getcwd(),
+ 'sqlite': 'sqlite:/:memory:',
'sybase': 'sybase://test:test123@sybase/test?autoCommit=0',
'firebird': 'firebird://sysdba:masterkey@localhost/var/lib/firebird/data/test.gdb',
'mssql': 'mssql://sa:@127.0.0.1/test'
|
|
From: <sub...@co...> - 2005-10-26 23:38:35
|
Author: test Date: 2005-10-26 23:38:31 +0000 (Wed, 26 Oct 2005) New Revision: 1147 Modified: SQLObject/trunk/setup.cfg Log: Publish in-development generated docs to different location Modified: SQLObject/trunk/setup.cfg =================================================================== --- SQLObject/trunk/setup.cfg 2005-10-26 23:14:35 UTC (rev 1146) +++ SQLObject/trunk/setup.cfg 2005-10-26 23:38:31 UTC (rev 1147) @@ -31,5 +31,9 @@ [publish] doc-dir = docs/html -doc-dest = scp://ianbicking@shell.sf.net/home/groups/s/sq/sqlobject/htdocs/ make-dirs = 1 + +## For live documentation: +# doc-dest = scp://ianbicking@shell.sf.net/home/groups/s/sq/sqlobject/htdocs/ +## For in-development documentation: +doc-dest = scp://ianbicking@shell.sf.net/home/groups/s/sq/sqlobject/htdocs/devel/ |
|
From: <sub...@co...> - 2005-10-26 23:14:38
|
Author: test
Date: 2005-10-26 23:14:35 +0000 (Wed, 26 Oct 2005)
New Revision: 1146
Modified:
SQLObject/trunk/docs/interface.py
Log:
Added note to interface
Modified: SQLObject/trunk/docs/interface.py
===================================================================
--- SQLObject/trunk/docs/interface.py 2005-10-26 23:13:17 UTC (rev 1145)
+++ SQLObject/trunk/docs/interface.py 2005-10-26 23:14:35 UTC (rev 1146)
@@ -264,6 +264,9 @@
ASQLObjectClass(a=1, b=2).asDict()
Which should return ``{'a': 1, 'b': 2}``.
+
+ Note: this is a *copy* of the object's columns; changing the
+ dictionary will not effect the object it was created from.
"""
|
|
From: <sub...@co...> - 2005-10-26 23:13:23
|
Author: test
Date: 2005-10-26 23:13:17 +0000 (Wed, 26 Oct 2005)
New Revision: 1145
Modified:
SQLObject/trunk/docs/interface.py
SQLObject/trunk/sqlobject/main.py
SQLObject/trunk/sqlobject/tests/test_basic.py
Log:
Added .sqlmeta.asDict() method
Modified: SQLObject/trunk/docs/interface.py
===================================================================
--- SQLObject/trunk/docs/interface.py 2005-10-26 23:06:11 UTC (rev 1144)
+++ SQLObject/trunk/docs/interface.py 2005-10-26 23:13:17 UTC (rev 1145)
@@ -254,7 +254,19 @@
Adds the index to the class.
"""
+ def asDict():
+ """
+ Returns the SQLObject instance as a dictionary (column names
+ as keys, column values as values).
+ Use like::
+
+ ASQLObjectClass(a=1, b=2).asDict()
+
+ Which should return ``{'a': 1, 'b': 2}``.
+ """
+
+
class ICol(Interface):
def __init__(name=None, **kw):
Modified: SQLObject/trunk/sqlobject/main.py
===================================================================
--- SQLObject/trunk/sqlobject/main.py 2005-10-26 23:06:11 UTC (rev 1144)
+++ SQLObject/trunk/sqlobject/main.py 2005-10-26 23:13:17 UTC (rev 1145)
@@ -562,6 +562,16 @@
cls.indexes.append(index)
addIndex = classmethod(addIndex)
+ ########################################
+ ## Utility methods
+ ########################################
+
+ def asDict(self):
+ result = {}
+ for key in self.columns:
+ result[key] = getattr(self.instance, key)
+ return result
+
sqlhub = dbconnection.ConnectionHub()
class _sqlmeta_attr(object):
Modified: SQLObject/trunk/sqlobject/tests/test_basic.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_basic.py 2005-10-26 23:06:11 UTC (rev 1144)
+++ SQLObject/trunk/sqlobject/tests/test_basic.py 2005-10-26 23:13:17 UTC (rev 1145)
@@ -275,3 +275,9 @@
assert dep1.other is None
assert dep2.other is None
assert dep3.other is obj2
+
+def testAsDict():
+ setupGetters(TestSO1)
+ bob = TestSO1.selectBy(name='bob')[0]
+ assert bob.sqlmeta.asDict() == {'passwd': 'tbq', 'name': 'bob'}
+
|
|
From: <sub...@co...> - 2005-10-26 23:06:17
|
Author: test
Date: 2005-10-26 23:06:11 +0000 (Wed, 26 Oct 2005)
New Revision: 1144
Modified:
SQLObject/trunk/docs/SQLBuilder.txt
Log:
Fixed import statements, per bug 1338107
Modified: SQLObject/trunk/docs/SQLBuilder.txt
===================================================================
--- SQLObject/trunk/docs/SQLBuilder.txt 2005-10-26 22:57:59 UTC (rev 1143)
+++ SQLObject/trunk/docs/SQLBuilder.txt 2005-10-26 23:06:11 UTC (rev 1144)
@@ -3,7 +3,7 @@
``````````
A number of variables from SQLBuilder are included with ``from
-SQLObject import *`` -- see the `relevant SQLObject documentation`_
+sqlobject import *`` -- see the `relevant SQLObject documentation`_
for more. Its functionality is also available through the special
``q`` attribute of `SQLObject` classes.
@@ -20,7 +20,7 @@
of a table class -- this gives you an object that represents the
field. Maybe explanations aren't as good. Here's some examples::
- >>> from SQLBuilder import *
+ >>> from sqlobject.sqlbuilder import *
>>> person = table.person
# person is now equivalent to the Person.q object from the SQLObject
# documentation
@@ -43,7 +43,7 @@
# This isn't what you want:
>> person.first_name == 'John' & person.last_name == 'Doe'
- (person.first_name = ('John' AND person.last_name)) = 'Doe'
+ (person.first_name = ('John' AND person.last_name)) = 'Doe')
# This is:
>> (person.first_name == 'John') & (person.last_name == 'Doe')
((person.first_name = 'John') AND (person.last_name == 'Doe'))
|
|
From: <sub...@co...> - 2005-10-26 22:58:06
|
Author: test Date: 2005-10-26 22:57:59 +0000 (Wed, 26 Oct 2005) New Revision: 1143 Added: SQLObject/trunk/sqlobject/tests/test_csvexport.py SQLObject/trunk/sqlobject/util/csvexport.py Modified: SQLObject/trunk/docs/SQLObject.txt Log: Added routine for doing CSV exports Modified: SQLObject/trunk/docs/SQLObject.txt =================================================================== --- SQLObject/trunk/docs/SQLObject.txt 2005-10-26 22:40:08 UTC (rev 1142) +++ SQLObject/trunk/docs/SQLObject.txt 2005-10-26 22:57:59 UTC (rev 1143) @@ -1668,6 +1668,15 @@ and ALL(). The last 3 are used with comparison operators, like this: "somevalue = ANY(Select(...))". +Utilities +--------- + +Some useful utility functions are included with SQLObject. For more +information see their module docstrings. + +* `sqlobject.util.csvexport + <http://sqlobject.org/module-sqlobject.util.csvexport.html>`_ + SQLBuilder ---------- Added: SQLObject/trunk/sqlobject/tests/test_csvexport.py =================================================================== --- SQLObject/trunk/sqlobject/tests/test_csvexport.py 2005-10-26 22:40:08 UTC (rev 1142) +++ SQLObject/trunk/sqlobject/tests/test_csvexport.py 2005-10-26 22:57:59 UTC (rev 1143) @@ -0,0 +1,90 @@ +from sqlobject import * +from dbtest import * +import csv +from StringIO import StringIO +from sqlobject.util.csvexport import export_csv, export_csv_zip + +def assert_export(result, *args, **kw): + f = StringIO() + kw['writer'] = f + export_csv(*args, **kw) + s = f.getvalue().replace('\r\n', '\n') + if result.strip() != s.strip(): + print '**Expected:' + print result + print '**Got:' + print s + assert result.strip() == s.strip() + +class Simple(SQLObject): + + name = StringCol() + address = StringCol() + address.csvTitle = 'Street Address' + hidden = StringCol() + hidden.noCSV = True + +class Complex(SQLObject): + + fname = StringCol() + lname = StringCol() + age = IntCol() + extraCSVColumns = [('name', 'Full Name'), 'initials'] + # initials should end up at the end then: + csvColumnOrder = ['name', 'fname', 'lname', 'age'] + def _get_name(self): + return self.fname + ' ' + self.lname + def _get_initials(self): + return self.fname[0] + self.lname[0] + +def test_simple(): + setupClass(Simple) + Simple(name='Bob', address='432W', hidden='boo') + Simple(name='Joe', address='123W', hidden='arg') + assert_export("""\ +name,Street Address +Bob,432W +Joe,123W +""", Simple, orderBy='name') + assert_export("""\ +name,Street Address +Joe,123W +Bob,432W +""", Simple, orderBy='address') + assert_export("""\ +name,Street Address +Joe,123W +""", Simple.selectBy(name='Joe')) + +def test_complex(): + setupClass(Complex) + Complex(fname='John', lname='Doe', age=40) + Complex(fname='Bob', lname='Dylan', age=60) + Complex(fname='Harriet', lname='Tubman', age=160) + assert_export("""\ +Full Name,fname,lname,age,initials +John Doe,John,Doe,40,JD +Bob Dylan,Bob,Dylan,60,BD +Harriet Tubman,Harriet,Tubman,160,HT +""", Complex, orderBy='lname') + assert_export("""\ +Full Name,fname,lname,age,initials +Bob Dylan,Bob,Dylan,60,BD +John Doe,John,Doe,40,JD +""", Complex.select(Complex.q.lname.startswith('D'), orderBy='fname')) + +def test_zip(): + # Just exercise tests, doesn't actually test results + setupClass(Simple) + Simple(name='Bob', address='432W', hidden='boo') + Simple(name='Joe', address='123W', hidden='arg') + + setupClass(Complex) + Complex(fname='John', lname='Doe', age=40) + Complex(fname='Bob', lname='Dylan', age=60) + Complex(fname='Harriet', lname='Tubman', age=160) + s = export_csv_zip([Simple, Complex]) + assert isinstance(s, str) and s + s = export_csv_zip([Simple.selectBy(name='Bob'), + (Complex, list(Complex.selectBy(fname='John')))]) + Added: SQLObject/trunk/sqlobject/util/csvexport.py =================================================================== --- SQLObject/trunk/sqlobject/util/csvexport.py 2005-10-26 22:40:08 UTC (rev 1142) +++ SQLObject/trunk/sqlobject/util/csvexport.py 2005-10-26 22:57:59 UTC (rev 1143) @@ -0,0 +1,196 @@ +""" +Exports a SQLObject class (possibly annotated) to a CSV file. +""" +import os +import csv +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO +import sqlobject + +__all__ = ['export_csv', 'export_csv_zip'] + +def export_csv(soClass, select=None, writer=None, connection=None, + orderBy=None): + """ + Export the SQLObject class ``soClass`` to a CSV file. + + ``soClass`` can also be a SelectResult object, as returned by + ``.select()``. If it is a class, all objects will be retrieved, + ordered by ``orderBy`` if given, or the ``.csvOrderBy`` attribute + if present (but csvOrderBy will only be applied when no select + result is given). + + You can also pass in select results (or simply a list of + instances) in ``select`` -- if you have a list of objects (not a + SelectResult instance, as produced by ``.select()``) then you must + pass it in with ``select`` and pass the class in as the first + argument. + + ``writer`` is a ``csv.writer()`` object, or a file-like object. + If not given, the string of the file will be returned. + + Uses ``connection`` as the data source, if given, otherwise the + default connection. + + Columns can be annotated with ``.csvTitle`` attributes, which will + form the attributes of the columns, or 'title' (secondarily), or + if nothing then the column attribute name. + + If a column has a ``.noCSV`` attribute which is true, then the + column will be suppressed. + + Additionally a class can have an ``.extraCSVColumns`` attribute, + which should be a list of strings/tuples. If a tuple, it should + be like ``(attribute, title)``, otherwise it is the attribute, + which will also be the title. These will be appended to the end + of the CSV file; the attribute will be retrieved from instances. + + Also a ``.csvColumnOrder`` attribute can be on the class, which is + the string names of attributes in the order they should be + presented. + """ + + return_fileobj = None + if not writer: + return_fileobj = StringIO() + writer = csv.writer(return_fileobj) + elif not hasattr(writer, 'writerow'): + writer = csv.writer(writer) + + if isinstance(soClass, sqlobject.SQLObject.SelectResultsClass): + assert not select, ( + "You cannot pass in a select argument (%r) and a SelectResult argument (%r) for soClass" + % (select, soClass)) + select = soClass + soClass = select.sourceClass + elif not select: + select = soClass.select() + if getattr(soClass, 'csvOrderBy', None): + select = select.orderBy(soClass.csvOrderBy) + + if orderBy: + select = select.orderBy(orderBy) + if connection: + select = select.connection(connection) + + _actually_export_csv(soClass, select, writer) + + if return_fileobj: + # They didn't pass any writer or file object in, so we return + # the string result: + return return_fileobj.getvalue() + +def _actually_export_csv(soClass, select, writer): + attributes, titles = _find_columns(soClass) + writer.writerow(titles) + for soInstance in select: + row = [getattr(soInstance, attr) + for attr in attributes] + writer.writerow(row) + +def _find_columns(soClass): + order = [] + attrs = {} + for col in soClass.sqlmeta.columnList: + if getattr(col, 'noCSV', False): + continue + order.append(col.name) + title = col.name + if hasattr(col, 'csvTitle'): + title = col.csvTitle + elif getattr(col, 'title', None) is not None: + title = col.title + attrs[col.name] = title + + for attrDesc in getattr(soClass, 'extraCSVColumns', []): + if isinstance(attrDesc, (list, tuple)): + attr, title = attrDesc + else: + attr = title = attrDesc + order.append(attr) + attrs[attr] = title + + if hasattr(soClass, 'csvColumnOrder'): + oldOrder = order + order = soClass.csvColumnOrder + for attr in order: + if attr not in oldOrder: + raise KeyError( + "Attribute %r in csvColumnOrder (on class %r) does not exist as a column or in .extraCSVColumns (I have: %r)" + % (attr, soClass, oldOrder)) + oldOrder.remove(attr) + order.extend(oldOrder) + + titles = [attrs[attr] for attr in order] + return order, titles + + +def export_csv_zip(soClasses, file=None, zip=None, filename_prefix='', + connection=None): + """ + Export several SQLObject classes into a .zip file. Each + item in the ``soClasses`` list may be a SQLObject class, + select result, or ``(soClass, select)`` tuple. + + Each file in the zip will be named after the class name (with + ``.csv`` appended), or using the filename in the ``.csvFilename`` + attribute. + + If ``file`` is given, the zip will be written to that. ``file`` + may be a string (a filename) or a file-like object. If not given, + a string will be returnd. + + If ``zip`` is given, then the files will be written to that zip + file. + + All filenames will be prefixed with ``filename_prefix`` (which may + be a directory name, for instance). + """ + import zipfile + close_file_when_finished = False + close_zip_when_finished = True + return_when_finished = False + if file: + if isinstance(file, (str, unicode)): + close_when_finished = True + file = open(file, 'wb') + elif zip: + close_zip_when_finished = False + else: + return_when_finished = True + file = StringIO() + + if not zip: + zip = zipfile.ZipFile(file, mode='w') + + try: + _actually_export_classes(soClasses, zip, filename_prefix, + connection) + finally: + if close_zip_when_finished: + zip.close() + if close_file_when_finished: + file.close() + + if return_when_finished: + return file.getvalue() + +def _actually_export_classes(soClasses, zip, filename_prefix, + connection): + for classDesc in soClasses: + if isinstance(classDesc, (tuple, list)): + soClass, select = classDesc + elif isinstance(classDesc, sqlobject.SQLObject.SelectResultsClass): + select = classDesc + soClass = select.sourceClass + else: + soClass = classDesc + select = None + filename = getattr(soClass, 'csvFilename', soClass.__name__) + if not os.path.splitext(filename)[1]: + filename += '.csv' + filename = filename_prefix + filename + zip.writestr(filename, + export_csv(soClass, select, connection=connection)) |