sqlobject 3.13.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlobject/__init__.py +15 -0
- sqlobject/__version__.py +8 -0
- sqlobject/boundattributes.py +124 -0
- sqlobject/cache.py +376 -0
- sqlobject/classregistry.py +138 -0
- sqlobject/col.py +2187 -0
- sqlobject/compat.py +59 -0
- sqlobject/conftest.py +64 -0
- sqlobject/constraints.py +77 -0
- sqlobject/converters.py +278 -0
- sqlobject/dbconnection.py +1137 -0
- sqlobject/dberrors.py +54 -0
- sqlobject/declarative.py +211 -0
- sqlobject/events.py +365 -0
- sqlobject/firebird/__init__.py +8 -0
- sqlobject/firebird/firebirdconnection.py +463 -0
- sqlobject/include/__init__.py +1 -0
- sqlobject/include/hashcol.py +109 -0
- sqlobject/include/tests/__init__.py +1 -0
- sqlobject/include/tests/test_hashcol.py +84 -0
- sqlobject/index.py +189 -0
- sqlobject/inheritance/__init__.py +551 -0
- sqlobject/inheritance/iteration.py +106 -0
- sqlobject/inheritance/tests/__init__.py +1 -0
- sqlobject/inheritance/tests/test_aggregates.py +23 -0
- sqlobject/inheritance/tests/test_asdict.py +48 -0
- sqlobject/inheritance/tests/test_deep_inheritance.py +114 -0
- sqlobject/inheritance/tests/test_destroy_cascade.py +23 -0
- sqlobject/inheritance/tests/test_foreignKey.py +94 -0
- sqlobject/inheritance/tests/test_indexes.py +42 -0
- sqlobject/inheritance/tests/test_inheritance.py +164 -0
- sqlobject/inheritance/tests/test_inheritance_tree.py +50 -0
- sqlobject/joins.py +656 -0
- sqlobject/main.py +1880 -0
- sqlobject/manager/__init__.py +1 -0
- sqlobject/manager/command.py +1309 -0
- sqlobject/maxdb/__init__.py +8 -0
- sqlobject/maxdb/maxdbconnection.py +320 -0
- sqlobject/maxdb/readme.txt +27 -0
- sqlobject/mssql/__init__.py +8 -0
- sqlobject/mssql/mssqlconnection.py +417 -0
- sqlobject/mysql/__init__.py +8 -0
- sqlobject/mysql/mysqlconnection.py +562 -0
- sqlobject/postgres/__init__.py +8 -0
- sqlobject/postgres/pgconnection.py +619 -0
- sqlobject/sqlbuilder.py +1655 -0
- sqlobject/sqlite/__init__.py +8 -0
- sqlobject/sqlite/sqliteconnection.py +418 -0
- sqlobject/sresults.py +377 -0
- sqlobject/styles.py +174 -0
- sqlobject/sybase/__init__.py +8 -0
- sqlobject/sybase/sybaseconnection.py +183 -0
- sqlobject/tests/__init__.py +1 -0
- sqlobject/tests/dbtest.py +363 -0
- sqlobject/tests/test_ForeignKey.py +133 -0
- sqlobject/tests/test_ForeignKey_cascade.py +150 -0
- sqlobject/tests/test_NoneValuedResultItem.py +33 -0
- sqlobject/tests/test_SQLMultipleJoin.py +65 -0
- sqlobject/tests/test_SQLRelatedJoin.py +114 -0
- sqlobject/tests/test_SingleJoin.py +30 -0
- sqlobject/tests/test_aggregates.py +75 -0
- sqlobject/tests/test_aliases.py +49 -0
- sqlobject/tests/test_asdict.py +18 -0
- sqlobject/tests/test_auto.py +218 -0
- sqlobject/tests/test_basic.py +359 -0
- sqlobject/tests/test_blob.py +34 -0
- sqlobject/tests/test_boundattributes.py +67 -0
- sqlobject/tests/test_cache.py +57 -0
- sqlobject/tests/test_class_hash.py +22 -0
- sqlobject/tests/test_columns_order.py +18 -0
- sqlobject/tests/test_combining_joins.py +47 -0
- sqlobject/tests/test_comparison.py +24 -0
- sqlobject/tests/test_compat.py +10 -0
- sqlobject/tests/test_complex_sorting.py +77 -0
- sqlobject/tests/test_constraints.py +43 -0
- sqlobject/tests/test_converters.py +276 -0
- sqlobject/tests/test_create_drop.py +29 -0
- sqlobject/tests/test_csvexport.py +101 -0
- sqlobject/tests/test_csvimport.py +21 -0
- sqlobject/tests/test_cyclic_reference.py +55 -0
- sqlobject/tests/test_datetime.py +171 -0
- sqlobject/tests/test_dbconnection.py +17 -0
- sqlobject/tests/test_decimal.py +63 -0
- sqlobject/tests/test_declarative.py +83 -0
- sqlobject/tests/test_default_style.py +65 -0
- sqlobject/tests/test_delete.py +74 -0
- sqlobject/tests/test_distinct.py +36 -0
- sqlobject/tests/test_empty.py +22 -0
- sqlobject/tests/test_enum.py +75 -0
- sqlobject/tests/test_events.py +142 -0
- sqlobject/tests/test_exceptions.py +40 -0
- sqlobject/tests/test_expire.py +29 -0
- sqlobject/tests/test_groupBy.py +45 -0
- sqlobject/tests/test_identity.py +29 -0
- sqlobject/tests/test_indexes.py +100 -0
- sqlobject/tests/test_inheritance.py +35 -0
- sqlobject/tests/test_joins.py +160 -0
- sqlobject/tests/test_joins_conditional.py +143 -0
- sqlobject/tests/test_jsonbcol.py +53 -0
- sqlobject/tests/test_jsoncol.py +56 -0
- sqlobject/tests/test_lazy.py +165 -0
- sqlobject/tests/test_md5.py +13 -0
- sqlobject/tests/test_mysql.py +50 -0
- sqlobject/tests/test_new_joins.py +165 -0
- sqlobject/tests/test_parse_uri.py +147 -0
- sqlobject/tests/test_paste.py +92 -0
- sqlobject/tests/test_perConnection.py +20 -0
- sqlobject/tests/test_pickle.py +42 -0
- sqlobject/tests/test_picklecol.py +44 -0
- sqlobject/tests/test_postgres.py +82 -0
- sqlobject/tests/test_reparent_sqlmeta.py +33 -0
- sqlobject/tests/test_schema.py +30 -0
- sqlobject/tests/test_select.py +218 -0
- sqlobject/tests/test_select_through.py +63 -0
- sqlobject/tests/test_setters.py +23 -0
- sqlobject/tests/test_slice.py +59 -0
- sqlobject/tests/test_sorting.py +80 -0
- sqlobject/tests/test_sqlbuilder.py +134 -0
- sqlobject/tests/test_sqlbuilder_dbspecific.py +66 -0
- sqlobject/tests/test_sqlbuilder_importproxy.py +55 -0
- sqlobject/tests/test_sqlbuilder_joins_instances.py +90 -0
- sqlobject/tests/test_sqlite.py +160 -0
- sqlobject/tests/test_sqlmeta_idName.py +52 -0
- sqlobject/tests/test_sqlobject_admin.py +38 -0
- sqlobject/tests/test_string_id.py +79 -0
- sqlobject/tests/test_style.py +36 -0
- sqlobject/tests/test_subqueries.py +142 -0
- sqlobject/tests/test_transactions.py +122 -0
- sqlobject/tests/test_unicode.py +84 -0
- sqlobject/tests/test_uuidcol.py +40 -0
- sqlobject/tests/test_validation.py +125 -0
- sqlobject/tests/test_views.py +159 -0
- sqlobject/util/__init__.py +1 -0
- sqlobject/util/csvexport.py +210 -0
- sqlobject/util/csvimport.py +366 -0
- sqlobject/util/moduleloader.py +35 -0
- sqlobject/util/threadinglocal.py +6 -0
- sqlobject/versioning/__init__.py +120 -0
- sqlobject/versioning/test/__init__.py +0 -0
- sqlobject/versioning/test/test_version.py +183 -0
- sqlobject/views.py +151 -0
- sqlobject/wsgi_middleware.py +109 -0
- sqlobject-3.13.1.data/scripts/sqlobject-admin +36 -0
- sqlobject-3.13.1.data/scripts/sqlobject-convertOldURI +19 -0
- sqlobject-3.13.1.dist-info/METADATA +177 -0
- sqlobject-3.13.1.dist-info/RECORD +149 -0
- sqlobject-3.13.1.dist-info/WHEEL +6 -0
- sqlobject-3.13.1.dist-info/entry_points.txt +4 -0
- sqlobject-3.13.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
try:
|
|
3
|
+
from StringIO import StringIO
|
|
4
|
+
except ImportError:
|
|
5
|
+
from io import StringIO
|
|
6
|
+
|
|
7
|
+
from sqlobject import IntCol, SQLObject, StringCol
|
|
8
|
+
from sqlobject.util.csvexport import export_csv, export_csv_zip
|
|
9
|
+
from .dbtest import setupClass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def assert_export(result, *args, **kw):
|
|
13
|
+
f = StringIO()
|
|
14
|
+
kw['writer'] = f
|
|
15
|
+
export_csv(*args, **kw)
|
|
16
|
+
s = f.getvalue().replace('\r\n', '\n')
|
|
17
|
+
if result.strip() != s.strip():
|
|
18
|
+
print('**Expected:')
|
|
19
|
+
print(result)
|
|
20
|
+
print('**Got:')
|
|
21
|
+
print(s)
|
|
22
|
+
assert result.strip() == s.strip()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SimpleCSV(SQLObject):
|
|
26
|
+
|
|
27
|
+
name = StringCol()
|
|
28
|
+
address = StringCol()
|
|
29
|
+
address.csvTitle = 'Street Address'
|
|
30
|
+
hidden = StringCol()
|
|
31
|
+
hidden.noCSV = True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ComplexCSV(SQLObject):
|
|
35
|
+
|
|
36
|
+
fname = StringCol()
|
|
37
|
+
lname = StringCol()
|
|
38
|
+
age = IntCol()
|
|
39
|
+
extraCSVColumns = [('name', 'Full Name'), 'initials']
|
|
40
|
+
# initials should end up at the end then:
|
|
41
|
+
csvColumnOrder = ['name', 'fname', 'lname', 'age']
|
|
42
|
+
|
|
43
|
+
def _get_name(self):
|
|
44
|
+
return self.fname + ' ' + self.lname
|
|
45
|
+
|
|
46
|
+
def _get_initials(self):
|
|
47
|
+
return self.fname[0] + self.lname[0]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_simple():
|
|
51
|
+
setupClass(SimpleCSV)
|
|
52
|
+
SimpleCSV(name='Bob', address='432W', hidden='boo')
|
|
53
|
+
SimpleCSV(name='Joe', address='123W', hidden='arg')
|
|
54
|
+
assert_export("""\
|
|
55
|
+
name,Street Address
|
|
56
|
+
Bob,432W
|
|
57
|
+
Joe,123W
|
|
58
|
+
""", SimpleCSV, orderBy='name')
|
|
59
|
+
assert_export("""\
|
|
60
|
+
name,Street Address
|
|
61
|
+
Joe,123W
|
|
62
|
+
Bob,432W
|
|
63
|
+
""", SimpleCSV, orderBy='address')
|
|
64
|
+
assert_export("""\
|
|
65
|
+
name,Street Address
|
|
66
|
+
Joe,123W
|
|
67
|
+
""", SimpleCSV.selectBy(name='Joe'))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_complex():
|
|
71
|
+
setupClass(ComplexCSV)
|
|
72
|
+
ComplexCSV(fname='John', lname='Doe', age=40)
|
|
73
|
+
ComplexCSV(fname='Bob', lname='Dylan', age=60)
|
|
74
|
+
ComplexCSV(fname='Harriet', lname='Tubman', age=160)
|
|
75
|
+
assert_export("""\
|
|
76
|
+
Full Name,fname,lname,age,initials
|
|
77
|
+
John Doe,John,Doe,40,JD
|
|
78
|
+
Bob Dylan,Bob,Dylan,60,BD
|
|
79
|
+
Harriet Tubman,Harriet,Tubman,160,HT
|
|
80
|
+
""", ComplexCSV, orderBy='lname')
|
|
81
|
+
assert_export("""\
|
|
82
|
+
Full Name,fname,lname,age,initials
|
|
83
|
+
Bob Dylan,Bob,Dylan,60,BD
|
|
84
|
+
John Doe,John,Doe,40,JD
|
|
85
|
+
""", ComplexCSV.select(ComplexCSV.q.lname.startswith('D'), orderBy='fname'))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_zip():
|
|
89
|
+
# Just exercise tests, doesn't actually test results
|
|
90
|
+
setupClass(SimpleCSV)
|
|
91
|
+
SimpleCSV(name='Bob', address='432W', hidden='boo')
|
|
92
|
+
SimpleCSV(name='Joe', address='123W', hidden='arg')
|
|
93
|
+
|
|
94
|
+
setupClass(ComplexCSV)
|
|
95
|
+
ComplexCSV(fname='John', lname='Doe', age=40)
|
|
96
|
+
ComplexCSV(fname='Bob', lname='Dylan', age=60)
|
|
97
|
+
ComplexCSV(fname='Harriet', lname='Tubman', age=160)
|
|
98
|
+
s = export_csv_zip([SimpleCSV, ComplexCSV])
|
|
99
|
+
assert isinstance(s, bytes) and s
|
|
100
|
+
s = export_csv_zip([SimpleCSV.selectBy(name='Bob'),
|
|
101
|
+
(ComplexCSV, list(ComplexCSV.selectBy(fname='John')))])
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from sqlobject.util.csvimport import load_csv
|
|
4
|
+
|
|
5
|
+
csv_data = """\
|
|
6
|
+
name:str,age:datetime,value:int
|
|
7
|
+
Test,2000-01-01 21:44:33,42"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_load_csv():
|
|
11
|
+
loaded = load_csv(csv.reader(csv_data.split('\n')),
|
|
12
|
+
default_class='SQLObject')
|
|
13
|
+
assert loaded == {
|
|
14
|
+
'SQLObject': [
|
|
15
|
+
{
|
|
16
|
+
'age': datetime(2000, 1, 1, 21, 44, 33),
|
|
17
|
+
'name': 'Test',
|
|
18
|
+
'value': 42
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import BLOBCol, DateTimeCol, ForeignKey, IntCol, SQLObject, \
|
|
3
|
+
StringCol, sqlmeta
|
|
4
|
+
from sqlobject.tests.dbtest import getConnection, supports
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SOTestCyclicRefA(SQLObject):
|
|
8
|
+
class sqlmeta(sqlmeta):
|
|
9
|
+
idName = 'test_id_here'
|
|
10
|
+
table = 'test_cyclic_ref_a_table'
|
|
11
|
+
name = StringCol()
|
|
12
|
+
number = IntCol()
|
|
13
|
+
so_time = DateTimeCol()
|
|
14
|
+
short = StringCol(length=10)
|
|
15
|
+
blobcol = BLOBCol()
|
|
16
|
+
fkeyb = ForeignKey('SOTestCyclicRefB')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SOTestCyclicRefB(SQLObject):
|
|
20
|
+
class sqlmeta(sqlmeta):
|
|
21
|
+
idName = 'test_id_here'
|
|
22
|
+
table = 'test_cyclic_ref_b_table'
|
|
23
|
+
name = StringCol()
|
|
24
|
+
number = IntCol()
|
|
25
|
+
so_time = DateTimeCol()
|
|
26
|
+
short = StringCol(length=10)
|
|
27
|
+
blobcol = BLOBCol()
|
|
28
|
+
fkeya = ForeignKey('SOTestCyclicRefA')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_cyclic_reference():
|
|
32
|
+
if not supports('dropTableCascade'):
|
|
33
|
+
pytest.skip("dropTableCascade isn't supported")
|
|
34
|
+
conn = getConnection()
|
|
35
|
+
SOTestCyclicRefA.setConnection(conn)
|
|
36
|
+
SOTestCyclicRefB.setConnection(conn)
|
|
37
|
+
SOTestCyclicRefA.dropTable(ifExists=True, cascade=True)
|
|
38
|
+
assert not conn.tableExists(SOTestCyclicRefA.sqlmeta.table)
|
|
39
|
+
SOTestCyclicRefB.dropTable(ifExists=True, cascade=True)
|
|
40
|
+
assert not conn.tableExists(SOTestCyclicRefB.sqlmeta.table)
|
|
41
|
+
|
|
42
|
+
constraints = SOTestCyclicRefA.createTable(ifNotExists=True,
|
|
43
|
+
applyConstraints=False)
|
|
44
|
+
assert conn.tableExists(SOTestCyclicRefA.sqlmeta.table)
|
|
45
|
+
constraints += SOTestCyclicRefB.createTable(ifNotExists=True,
|
|
46
|
+
applyConstraints=False)
|
|
47
|
+
assert conn.tableExists(SOTestCyclicRefB.sqlmeta.table)
|
|
48
|
+
|
|
49
|
+
for constraint in constraints:
|
|
50
|
+
conn.query(constraint)
|
|
51
|
+
|
|
52
|
+
SOTestCyclicRefA.dropTable(ifExists=True, cascade=True)
|
|
53
|
+
assert not conn.tableExists(SOTestCyclicRefA.sqlmeta.table)
|
|
54
|
+
SOTestCyclicRefB.dropTable(ifExists=True, cascade=True)
|
|
55
|
+
assert not conn.tableExists(SOTestCyclicRefB.sqlmeta.table)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from datetime import datetime, date, time
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from sqlobject import SQLObject
|
|
5
|
+
from sqlobject import col
|
|
6
|
+
from sqlobject.col import DateCol, DateTimeCol, TimeCol, use_microseconds, \
|
|
7
|
+
DATETIME_IMPLEMENTATION, MXDATETIME_IMPLEMENTATION, mxdatetime_available, \
|
|
8
|
+
ZOPE_DATETIME_IMPLEMENTATION, zope_datetime_available
|
|
9
|
+
from sqlobject.tests.dbtest import getConnection, setupClass
|
|
10
|
+
from sqlobject.converters import pendulumDateTimeType
|
|
11
|
+
|
|
12
|
+
########################################
|
|
13
|
+
# Date/time columns
|
|
14
|
+
########################################
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
col.default_datetime_implementation = DATETIME_IMPLEMENTATION
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DateTime1(SQLObject):
|
|
21
|
+
col1 = DateTimeCol()
|
|
22
|
+
col2 = DateCol()
|
|
23
|
+
col3 = TimeCol()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_dateTime():
|
|
27
|
+
setupClass(DateTime1)
|
|
28
|
+
_now = datetime.now().replace(microsecond=0)
|
|
29
|
+
dt1 = DateTime1(col1=_now, col2=_now, col3=_now.time())
|
|
30
|
+
|
|
31
|
+
assert isinstance(dt1.col1, datetime)
|
|
32
|
+
assert dt1.col1.year == _now.year
|
|
33
|
+
assert dt1.col1.month == _now.month
|
|
34
|
+
assert dt1.col1.day == _now.day
|
|
35
|
+
assert dt1.col1.hour == _now.hour
|
|
36
|
+
assert dt1.col1.minute == _now.minute
|
|
37
|
+
assert dt1.col1.second == _now.second
|
|
38
|
+
|
|
39
|
+
assert isinstance(dt1.col2, date)
|
|
40
|
+
assert not isinstance(dt1.col2, datetime)
|
|
41
|
+
assert dt1.col2.year == _now.year
|
|
42
|
+
assert dt1.col2.month == _now.month
|
|
43
|
+
assert dt1.col2.day == _now.day
|
|
44
|
+
|
|
45
|
+
assert isinstance(dt1.col3, time)
|
|
46
|
+
assert dt1.col3.hour == _now.hour
|
|
47
|
+
assert dt1.col3.minute == _now.minute
|
|
48
|
+
assert dt1.col3.second == _now.second
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_microseconds():
|
|
52
|
+
connection = getConnection()
|
|
53
|
+
if not hasattr(connection, 'can_use_microseconds') or \
|
|
54
|
+
not connection.can_use_microseconds():
|
|
55
|
+
pytest.skip(
|
|
56
|
+
"The database doesn't support microseconds; "
|
|
57
|
+
"microseconds are supported by MariaDB since version 5.3.0, "
|
|
58
|
+
"by MySQL since version 5.6.4, "
|
|
59
|
+
"by MSSQL since MS SQL Server 2008.")
|
|
60
|
+
|
|
61
|
+
setupClass(DateTime1)
|
|
62
|
+
_now = datetime.now()
|
|
63
|
+
dt1 = DateTime1(col1=_now, col2=_now, col3=_now.time())
|
|
64
|
+
|
|
65
|
+
assert dt1.col1.microsecond == _now.microsecond
|
|
66
|
+
assert dt1.col3.microsecond == _now.microsecond
|
|
67
|
+
|
|
68
|
+
use_microseconds(False)
|
|
69
|
+
setupClass(DateTime1)
|
|
70
|
+
_now = datetime.now()
|
|
71
|
+
dt1 = DateTime1(col1=_now, col2=_now, col3=_now.time())
|
|
72
|
+
|
|
73
|
+
assert dt1.col1.microsecond == 0
|
|
74
|
+
assert dt1.col3.microsecond == 0
|
|
75
|
+
|
|
76
|
+
use_microseconds(True)
|
|
77
|
+
setupClass(DateTime1)
|
|
78
|
+
_now = datetime.now()
|
|
79
|
+
dt1 = DateTime1(col1=_now, col2=_now, col3=_now.time())
|
|
80
|
+
|
|
81
|
+
assert dt1.col1.microsecond == _now.microsecond
|
|
82
|
+
assert dt1.col3.microsecond == _now.microsecond
|
|
83
|
+
|
|
84
|
+
if mxdatetime_available:
|
|
85
|
+
col.default_datetime_implementation = MXDATETIME_IMPLEMENTATION
|
|
86
|
+
from mx.DateTime import now as mx_now, Time as mxTime
|
|
87
|
+
|
|
88
|
+
dateFormat = None # use default
|
|
89
|
+
try:
|
|
90
|
+
connection = getConnection()
|
|
91
|
+
except AttributeError:
|
|
92
|
+
# The module was imported during documentation building
|
|
93
|
+
pass
|
|
94
|
+
else:
|
|
95
|
+
if connection.dbName == "sqlite":
|
|
96
|
+
# mxDateTime sends and sqlite3 returns
|
|
97
|
+
# full date/time for dates
|
|
98
|
+
dateFormat = "%Y-%m-%d %H:%M:%S.%f"
|
|
99
|
+
|
|
100
|
+
class DateTime2(SQLObject):
|
|
101
|
+
col1 = DateTimeCol()
|
|
102
|
+
col2 = DateCol(dateFormat=dateFormat)
|
|
103
|
+
col3 = TimeCol()
|
|
104
|
+
|
|
105
|
+
def test_mxDateTime():
|
|
106
|
+
setupClass(DateTime2)
|
|
107
|
+
_now = mx_now()
|
|
108
|
+
dt2 = DateTime2(col1=_now, col2=_now.pydate(),
|
|
109
|
+
col3=mxTime(_now.hour, _now.minute, _now.second))
|
|
110
|
+
|
|
111
|
+
assert isinstance(dt2.col1, col.mxDateTimeType)
|
|
112
|
+
assert dt2.col1.year == _now.year
|
|
113
|
+
assert dt2.col1.month == _now.month
|
|
114
|
+
assert dt2.col1.day == _now.day
|
|
115
|
+
assert dt2.col1.hour == _now.hour
|
|
116
|
+
assert dt2.col1.minute == _now.minute
|
|
117
|
+
assert dt2.col1.second == int(_now.second)
|
|
118
|
+
|
|
119
|
+
assert isinstance(dt2.col2, col.mxDateTimeType)
|
|
120
|
+
assert dt2.col2.year == _now.year
|
|
121
|
+
assert dt2.col2.month == _now.month
|
|
122
|
+
assert dt2.col2.day == _now.day
|
|
123
|
+
assert dt2.col2.hour == 0
|
|
124
|
+
assert dt2.col2.minute == 0
|
|
125
|
+
assert dt2.col2.second == 0
|
|
126
|
+
|
|
127
|
+
assert isinstance(dt2.col3, (col.mxDateTimeType, col.mxTimeType))
|
|
128
|
+
assert dt2.col3.hour == _now.hour
|
|
129
|
+
assert dt2.col3.minute == _now.minute
|
|
130
|
+
assert dt2.col3.second == int(_now.second)
|
|
131
|
+
|
|
132
|
+
if pendulumDateTimeType:
|
|
133
|
+
col.default_datetime_implementation = DATETIME_IMPLEMENTATION
|
|
134
|
+
import pendulum
|
|
135
|
+
|
|
136
|
+
class DateTimePendulum(SQLObject):
|
|
137
|
+
col1 = DateTimeCol()
|
|
138
|
+
|
|
139
|
+
def test_PendulumDateTime():
|
|
140
|
+
setupClass(DateTimePendulum)
|
|
141
|
+
_now = pendulum.now()
|
|
142
|
+
dtp = DateTimePendulum(col1=_now)
|
|
143
|
+
|
|
144
|
+
assert isinstance(dtp.col1, datetime)
|
|
145
|
+
assert dtp.col1.year == _now.year
|
|
146
|
+
assert dtp.col1.month == _now.month
|
|
147
|
+
assert dtp.col1.day == _now.day
|
|
148
|
+
assert dtp.col1.hour == _now.hour
|
|
149
|
+
assert dtp.col1.minute == _now.minute
|
|
150
|
+
assert int(dtp.col1.second) == int(_now.second)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
if zope_datetime_available:
|
|
154
|
+
col.default_datetime_implementation = ZOPE_DATETIME_IMPLEMENTATION
|
|
155
|
+
from DateTime import DateTime as zopeDateTime
|
|
156
|
+
|
|
157
|
+
class DateTime3(SQLObject):
|
|
158
|
+
col1 = DateTimeCol()
|
|
159
|
+
|
|
160
|
+
def test_ZopeDateTime():
|
|
161
|
+
setupClass(DateTime3)
|
|
162
|
+
_now = zopeDateTime()
|
|
163
|
+
dt3 = DateTime3(col1=_now)
|
|
164
|
+
|
|
165
|
+
assert isinstance(dt3.col1, col.zopeDateTimeType)
|
|
166
|
+
assert dt3.col1.year() == _now.year()
|
|
167
|
+
assert dt3.col1.month() == _now.month()
|
|
168
|
+
assert dt3.col1.day() == _now.day()
|
|
169
|
+
assert dt3.col1.hour() == _now.hour()
|
|
170
|
+
assert dt3.col1.minute() == _now.minute()
|
|
171
|
+
assert int(dt3.col1.second()) == int(_now.second())
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from pytest import raises
|
|
2
|
+
from sqlobject.dbconnection import DBConnection
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_name():
|
|
6
|
+
connection = DBConnection(name='test')
|
|
7
|
+
connection.close = lambda: True
|
|
8
|
+
|
|
9
|
+
with raises(AssertionError) as error:
|
|
10
|
+
DBConnection(name='test')
|
|
11
|
+
assert str(error.value) == 'An instance has already been registered ' \
|
|
12
|
+
'with the name test'
|
|
13
|
+
|
|
14
|
+
with raises(AssertionError) as error:
|
|
15
|
+
DBConnection(name='test:test')
|
|
16
|
+
assert str(error.value) == "You cannot include ':' " \
|
|
17
|
+
"in your DB connection names ('test:test')"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
import pytest
|
|
3
|
+
from sqlobject import DecimalCol, DecimalStringCol, SQLObject, UnicodeCol
|
|
4
|
+
from sqlobject.tests.dbtest import setupClass, supports
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
########################################
|
|
8
|
+
# Decimal columns
|
|
9
|
+
########################################
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
support_decimal_column = supports('decimalColumn')
|
|
14
|
+
except NameError:
|
|
15
|
+
# The module was imported during documentation building
|
|
16
|
+
pass
|
|
17
|
+
else:
|
|
18
|
+
if not support_decimal_column:
|
|
19
|
+
pytestmark = pytest.mark.skip("These tests require Decimal support")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DecimalTable(SQLObject):
|
|
23
|
+
name = UnicodeCol(length=255)
|
|
24
|
+
col1 = DecimalCol(size=6, precision=4)
|
|
25
|
+
col2 = DecimalStringCol(size=6, precision=4)
|
|
26
|
+
col3 = DecimalStringCol(size=6, precision=4, quantize=True)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_1_decimal():
|
|
30
|
+
setupClass(DecimalTable)
|
|
31
|
+
d = DecimalTable(name='test', col1=21.12, col2='10.01', col3='10.01')
|
|
32
|
+
# psycopg2 returns float as Decimal
|
|
33
|
+
if isinstance(d.col1, Decimal):
|
|
34
|
+
assert d.col1 == Decimal("21.12")
|
|
35
|
+
else:
|
|
36
|
+
assert d.col1 == 21.12
|
|
37
|
+
assert d.col2 == Decimal("10.01")
|
|
38
|
+
assert DecimalTable.sqlmeta.columns['col2'].to_python(
|
|
39
|
+
'10.01', d._SO_validatorState) == Decimal("10.01")
|
|
40
|
+
assert DecimalTable.sqlmeta.columns['col2'].from_python(
|
|
41
|
+
'10.01', d._SO_validatorState) == "10.01"
|
|
42
|
+
assert d.col3 == Decimal("10.01")
|
|
43
|
+
assert DecimalTable.sqlmeta.columns['col3'].to_python(
|
|
44
|
+
'10.01', d._SO_validatorState) == Decimal("10.01")
|
|
45
|
+
assert DecimalTable.sqlmeta.columns['col3'].from_python(
|
|
46
|
+
'10.01', d._SO_validatorState) == "10.0100"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_2_decimal():
|
|
50
|
+
setupClass(DecimalTable)
|
|
51
|
+
d = DecimalTable(name='test', col1=Decimal("21.12"),
|
|
52
|
+
col2=Decimal('10.01'), col3=Decimal('10.01'))
|
|
53
|
+
assert d.col1 == Decimal("21.12")
|
|
54
|
+
assert d.col2 == Decimal("10.01")
|
|
55
|
+
assert DecimalTable.sqlmeta.columns['col2'].to_python(
|
|
56
|
+
Decimal('10.01'), d._SO_validatorState) == Decimal("10.01")
|
|
57
|
+
assert DecimalTable.sqlmeta.columns['col2'].from_python(
|
|
58
|
+
Decimal('10.01'), d._SO_validatorState) == "10.01"
|
|
59
|
+
assert d.col3 == Decimal("10.01")
|
|
60
|
+
assert DecimalTable.sqlmeta.columns['col3'].to_python(
|
|
61
|
+
Decimal('10.01'), d._SO_validatorState) == Decimal("10.01")
|
|
62
|
+
assert DecimalTable.sqlmeta.columns['col3'].from_python(
|
|
63
|
+
Decimal('10.01'), d._SO_validatorState) == "10.0100"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from sqlobject.declarative import Declarative
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class A1(Declarative):
|
|
5
|
+
|
|
6
|
+
a = 1
|
|
7
|
+
b = []
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class A2(A1):
|
|
11
|
+
|
|
12
|
+
a = 5
|
|
13
|
+
|
|
14
|
+
A3 = A2(b=5)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_a_classes():
|
|
18
|
+
assert A1.a == 1
|
|
19
|
+
assert A1.singleton().a == 1
|
|
20
|
+
assert A1.b is A2.b
|
|
21
|
+
assert A3.b == 5
|
|
22
|
+
assert A1.declarative_count == A1.singleton().declarative_count
|
|
23
|
+
assert A1.declarative_count < A2.declarative_count
|
|
24
|
+
assert A2.singleton() is not A1.singleton()
|
|
25
|
+
assert A3.singleton().b == A3.b
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class B1(Declarative):
|
|
29
|
+
|
|
30
|
+
attrs = []
|
|
31
|
+
|
|
32
|
+
def __classinit__(cls, new_attrs):
|
|
33
|
+
Declarative.__classinit__(cls, new_attrs)
|
|
34
|
+
cls.attrs = cls.add_attrs(cls.attrs, new_attrs)
|
|
35
|
+
|
|
36
|
+
def __instanceinit__(self, new_attrs):
|
|
37
|
+
Declarative.__instanceinit__(self, new_attrs)
|
|
38
|
+
self.attrs = self.add_attrs(self.attrs, new_attrs)
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def add_attrs(old_attrs, new_attrs):
|
|
42
|
+
old_attrs = old_attrs[:]
|
|
43
|
+
for name in new_attrs.keys():
|
|
44
|
+
if (name in old_attrs or name.startswith('_')
|
|
45
|
+
or name in ('add_attrs', 'declarative_count', 'attrs')):
|
|
46
|
+
continue
|
|
47
|
+
old_attrs.append(name)
|
|
48
|
+
old_attrs.sort()
|
|
49
|
+
return old_attrs
|
|
50
|
+
|
|
51
|
+
c = 1
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class B2(B1):
|
|
55
|
+
|
|
56
|
+
g = 3
|
|
57
|
+
|
|
58
|
+
def __classinit__(cls, new_attrs):
|
|
59
|
+
new_attrs['test'] = 'whatever'
|
|
60
|
+
B1.__classinit__(cls, new_attrs)
|
|
61
|
+
|
|
62
|
+
B3 = B2(c=5, d=3)
|
|
63
|
+
B4 = B3(d=5)
|
|
64
|
+
B5 = B1(a=1)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_b_classes():
|
|
68
|
+
assert B1.attrs == ['c']
|
|
69
|
+
assert B1.c == 1
|
|
70
|
+
assert B2.attrs == ['c', 'g', 'test']
|
|
71
|
+
assert B3.d == 3
|
|
72
|
+
assert B4.d == 5
|
|
73
|
+
assert B5.a == 1
|
|
74
|
+
assert B5.attrs == ['a', 'c']
|
|
75
|
+
assert B3.attrs == ['c', 'd', 'g', 'test']
|
|
76
|
+
assert B4.attrs == ['c', 'd', 'g', 'test']
|
|
77
|
+
order = [B1, B1.singleton(), B2, B2.singleton(),
|
|
78
|
+
B3, B3.singleton(), B4, B4.singleton(),
|
|
79
|
+
B5, B5.singleton()]
|
|
80
|
+
last = 0
|
|
81
|
+
for obj in order:
|
|
82
|
+
assert obj.declarative_count >= last
|
|
83
|
+
last = obj.declarative_count
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test the default styles, to guarantee consistency.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sqlobject import ForeignKey, MixedCaseStyle, MixedCaseUnderscoreStyle, \
|
|
6
|
+
SQLObject, StringCol, Style
|
|
7
|
+
|
|
8
|
+
# Hash of styles versus the database names resulting from 'columns' below.
|
|
9
|
+
columns = ["ABCUpper", "abc_lower", "ABCamelCaseColumn"]
|
|
10
|
+
styles = {
|
|
11
|
+
Style: columns,
|
|
12
|
+
MixedCaseUnderscoreStyle: ["abc_upper", "abc_lower",
|
|
13
|
+
"ab_camel_case_column"],
|
|
14
|
+
MixedCaseStyle: ["ABCUpper", "Abc_lower", "ABCamelCaseColumn"],
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Hash of styles versus the database names
|
|
18
|
+
# resulting from a foreign key named 'FKey'.
|
|
19
|
+
fkey = ForeignKey("DefaultStyleTest", name="FKey")
|
|
20
|
+
fkeys = {
|
|
21
|
+
Style: "FKeyID",
|
|
22
|
+
MixedCaseUnderscoreStyle: "f_key_id",
|
|
23
|
+
MixedCaseStyle: "FKeyID",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def make_columns():
|
|
28
|
+
global columns
|
|
29
|
+
columns = []
|
|
30
|
+
for col_name in columns:
|
|
31
|
+
columns.append(StringCol(name=col_name, length=10))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def do_col_test(DefaultStyleTest, style, dbnames):
|
|
35
|
+
DefaultStyleTest.sqlmeta.style = style()
|
|
36
|
+
for col, old_dbname in zip(columns, dbnames):
|
|
37
|
+
DefaultStyleTest.sqlmeta.addColumn(col)
|
|
38
|
+
try:
|
|
39
|
+
new_dbname = DefaultStyleTest.sqlmeta.columns[col.name].dbName
|
|
40
|
+
assert new_dbname == old_dbname
|
|
41
|
+
finally:
|
|
42
|
+
if col.name in DefaultStyleTest.sqlmeta.columns:
|
|
43
|
+
DefaultStyleTest.sqlmeta.delColumn(col)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def do_fkey_test(DefaultStyleTest, style, dbname):
|
|
47
|
+
DefaultStyleTest.sqlmeta.style = style()
|
|
48
|
+
DefaultStyleTest.sqlmeta.addColumn(fkey)
|
|
49
|
+
try:
|
|
50
|
+
assert list(DefaultStyleTest.sqlmeta.columns.keys())[0] == "FKeyID"
|
|
51
|
+
assert list(DefaultStyleTest.sqlmeta.columns.values())[0].dbName == \
|
|
52
|
+
dbname
|
|
53
|
+
finally:
|
|
54
|
+
DefaultStyleTest.sqlmeta.delColumn(fkey)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class DefaultStyleTest(SQLObject):
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_default_styles():
|
|
62
|
+
make_columns()
|
|
63
|
+
for style in styles:
|
|
64
|
+
do_col_test(DefaultStyleTest, style, styles[style])
|
|
65
|
+
do_fkey_test(DefaultStyleTest, style, fkeys[style])
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from sqlobject import OR, RelatedJoin, SQLObject, StringCol, cache
|
|
2
|
+
from sqlobject.tests.dbtest import setupClass
|
|
3
|
+
from .test_basic import SOTestSO1, setupGetters
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
########################################
|
|
7
|
+
# Delete during select
|
|
8
|
+
########################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def testSelect():
|
|
12
|
+
setupGetters(SOTestSO1)
|
|
13
|
+
for obj in SOTestSO1.select('all'):
|
|
14
|
+
obj.destroySelf()
|
|
15
|
+
assert list(SOTestSO1.select('all')) == []
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
########################################
|
|
19
|
+
# Delete many rows at once
|
|
20
|
+
########################################
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def testDeleteMany():
|
|
24
|
+
setupGetters(SOTestSO1)
|
|
25
|
+
SOTestSO1.deleteMany(OR(SOTestSO1.q.name == "bob",
|
|
26
|
+
SOTestSO1.q.name == "fred"))
|
|
27
|
+
assert len(list(SOTestSO1.select('all'))) == 2
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def testDeleteBy():
|
|
31
|
+
setupGetters(SOTestSO1)
|
|
32
|
+
SOTestSO1.deleteBy(name="dave")
|
|
33
|
+
assert len(list(SOTestSO1.select())) == 3
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
########################################
|
|
37
|
+
# Delete without caching
|
|
38
|
+
########################################
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class NoCache(SQLObject):
|
|
42
|
+
name = StringCol()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def testDestroySelf():
|
|
46
|
+
setupClass(NoCache)
|
|
47
|
+
old = NoCache._connection.cache
|
|
48
|
+
NoCache._connection.cache = cache.CacheSet(cache=False)
|
|
49
|
+
value = NoCache(name='test')
|
|
50
|
+
value.destroySelf()
|
|
51
|
+
NoCache._connection.cache = old
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
########################################
|
|
55
|
+
# Delete from related joins
|
|
56
|
+
########################################
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Service(SQLObject):
|
|
60
|
+
groups = RelatedJoin("ServiceGroup")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ServiceGroup(SQLObject):
|
|
64
|
+
services = RelatedJoin("Service")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def testDeleteRelatedJoins():
|
|
68
|
+
setupClass([Service, ServiceGroup])
|
|
69
|
+
service = Service()
|
|
70
|
+
service_group = ServiceGroup()
|
|
71
|
+
service.addServiceGroup(service_group)
|
|
72
|
+
service.destroySelf()
|
|
73
|
+
service_group = ServiceGroup.get(service_group.id)
|
|
74
|
+
assert len(service_group.services) == 0
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from sqlobject import ForeignKey, IntCol, SQLObject
|
|
2
|
+
from sqlobject.tests.dbtest import setupClass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
########################################
|
|
6
|
+
# Distinct
|
|
7
|
+
########################################
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Distinct1(SQLObject):
|
|
11
|
+
n = IntCol()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Distinct2(SQLObject):
|
|
15
|
+
other = ForeignKey('Distinct1')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def count(select):
|
|
19
|
+
result = {}
|
|
20
|
+
for ob in select:
|
|
21
|
+
result[int(ob.n)] = result.get(int(ob.n), 0) + 1
|
|
22
|
+
return result
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_distinct():
|
|
26
|
+
setupClass([Distinct1, Distinct2])
|
|
27
|
+
obs = [Distinct1(n=i) for i in range(3)]
|
|
28
|
+
Distinct2(other=obs[0])
|
|
29
|
+
Distinct2(other=obs[0])
|
|
30
|
+
Distinct2(other=obs[1])
|
|
31
|
+
|
|
32
|
+
query = (Distinct2.q.otherID == Distinct1.q.id)
|
|
33
|
+
sel = Distinct1.select(query)
|
|
34
|
+
assert count(sel) == {0: 2, 1: 1}
|
|
35
|
+
sel = Distinct1.select(query, distinct=True)
|
|
36
|
+
assert count(sel) == {0: 1, 1: 1}
|