Source

sqlalchemy-1418 / test / lib / requires.py

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
"""Global database feature support policy.

Provides decorators to mark tests requiring specific feature support from the
target database.

"""

from testing import \
     _block_unconditionally as no_support, \
     _chain_decorators_on, \
     exclude, \
     emits_warning_on,\
     skip_if,\
     only_on,\
     fails_on,\
     fails_on_everything_except,\
     fails_if
from sqlalchemy import util
from test.lib import config
import testing
import sys

def deferrable_or_no_constraints(fn):
    """Target database must support derferable constraints."""
    return _chain_decorators_on(
        fn,
        no_support('firebird', 'not supported by database'),
        no_support('mysql', 'not supported by database'),
        no_support('mssql', 'not supported by database'),
        )

def foreign_keys(fn):
    """Target database must support foreign keys."""
    return _chain_decorators_on(
        fn,
        no_support('sqlite', 'not supported by database'),
        )


def unbounded_varchar(fn):
    """Target database must support VARCHAR with no length"""
    return _chain_decorators_on(
        fn,
        no_support('firebird', 'not supported by database'),
        no_support('oracle', 'not supported by database'),
        no_support('mysql', 'not supported by database'),
    )

def boolean_col_expressions(fn):
    """Target database must support boolean expressions as columns"""
    return _chain_decorators_on(
        fn,
        no_support('firebird', 'not supported by database'),
        no_support('oracle', 'not supported by database'),
        no_support('mssql', 'not supported by database'),
        no_support('sybase', 'not supported by database'),
        no_support('maxdb', 'FIXME: verify not supported by database'),
        no_support('informix', 'not supported by database'),
    )

def identity(fn):
    """Target database must support GENERATED AS IDENTITY or a facsimile.

    Includes GENERATED AS IDENTITY, AUTOINCREMENT, AUTO_INCREMENT, or other
    column DDL feature that fills in a DB-generated identifier at INSERT-time
    without requiring pre-execution of a SEQUENCE or other artifact.

    """
    return _chain_decorators_on(
        fn,
        no_support('firebird', 'not supported by database'),
        no_support('oracle', 'not supported by database'),
        no_support('postgresql', 'not supported by database'),
        no_support('sybase', 'not supported by database'),
        )

def independent_cursors(fn):
    """Target must support simultaneous, independent database cursors on a single connection."""

    return _chain_decorators_on(
        fn,
        no_support('mssql+pyodbc', 'no driver support'),
        no_support('mssql+mxodbc', 'no driver support'),
        )

def independent_connections(fn):
    """Target must support simultaneous, independent database connections."""

    # This is also true of some configurations of UnixODBC and probably win32
    # ODBC as well.
    return _chain_decorators_on(
        fn,
        no_support('sqlite', 'Independent connections disabled when '
                            ':memory: connections are used'),
        exclude('mssql', '<', (9, 0, 0),
                'SQL Server 2005+ is required for independent connections'),
        )

def updateable_autoincrement_pks(fn):
    """Target must support UPDATE on autoincrement/integer primary key."""
    return _chain_decorators_on(
        fn,
        no_support('mssql', "IDENTITY cols can't be updated"),
        no_support('sybase', "IDENTITY cols can't be updated"),
    )

def isolation_level(fn):
    return _chain_decorators_on(
        fn,
        only_on(('postgresql', 'sqlite', 'mysql'), "DBAPI has no isolation level support"),
        fails_on('postgresql+pypostgresql',
                      'pypostgresql bombs on multiple isolation level calls')
    )

def row_triggers(fn):
    """Target must support standard statement-running EACH ROW triggers."""
    return _chain_decorators_on(
        fn,
        # no access to same table
        no_support('mysql', 'requires SUPER priv'),
        exclude('mysql', '<', (5, 0, 10), 'not supported by database'),

        # huh?  TODO: implement triggers for PG tests, remove this
        no_support('postgresql', 'PG triggers need to be implemented for tests'),
        )

def correlated_outer_joins(fn):
    """Target must support an outer join to a subquery which correlates to the parent."""

    return _chain_decorators_on(
        fn,
        no_support('oracle', 'Raises "ORA-01799: a column may not be outer-joined to a subquery"')
    )

def update_from(fn):
    """Target must support UPDATE..FROM syntax"""
    return _chain_decorators_on(
        fn,
        only_on(('postgresql', 'mssql', 'mysql'), 
            "Backend does not support UPDATE..FROM")
    )

def savepoints(fn):
    """Target database must support savepoints."""
    return _chain_decorators_on(
        fn,
        no_support('access', 'savepoints not supported'),
        no_support('sqlite', 'savepoints not supported'),
        no_support('sybase', 'savepoints not supported'),
        exclude('mysql', '<', (5, 0, 3), 'savepoints not supported'),
        exclude('informix', '<', (11, 55, 'xC3'), 'savepoints not supported'),
        )

def denormalized_names(fn):
    """Target database must have 'denormalized', i.e. UPPERCASE as case insensitive names."""

    return skip_if(
                lambda: not testing.db.dialect.requires_name_normalize,
                "Backend does not require denomralized names."
            )(fn)

def schemas(fn):
    """Target database must support external schemas, and have one named 'test_schema'."""

    return _chain_decorators_on(
        fn,
        no_support('sqlite', 'no schema support'),
        no_support('firebird', 'no schema support')
    )

def sequences(fn):
    """Target database must support SEQUENCEs."""
    return _chain_decorators_on(
        fn,
        no_support('access', 'no SEQUENCE support'),
        no_support('drizzle', 'no SEQUENCE support'),
        no_support('mssql', 'no SEQUENCE support'),
        no_support('mysql', 'no SEQUENCE support'),
        no_support('sqlite', 'no SEQUENCE support'),
        no_support('sybase', 'no SEQUENCE support'),
        no_support('informix', 'no SEQUENCE support'),
        )

def update_nowait(fn):
    """Target database must support SELECT...FOR UPDATE NOWAIT"""
    return _chain_decorators_on(
        fn,
        no_support('access', 'no FOR UPDATE NOWAIT support'),
        no_support('firebird', 'no FOR UPDATE NOWAIT support'),
        no_support('mssql', 'no FOR UPDATE NOWAIT support'),
        no_support('mysql', 'no FOR UPDATE NOWAIT support'),
        no_support('sqlite', 'no FOR UPDATE NOWAIT support'),
        no_support('sybase', 'no FOR UPDATE NOWAIT support'),
    )

def subqueries(fn):
    """Target database must support subqueries."""
    return _chain_decorators_on(
        fn,
        exclude('mysql', '<', (4, 1, 1), 'no subquery support'),
        )

def intersect(fn):
    """Target database must support INTERSECT or equivalent."""
    return _chain_decorators_on(
        fn,
        fails_on('firebird', 'no support for INTERSECT'),
        fails_on('mysql', 'no support for INTERSECT'),
        fails_on('sybase', 'no support for INTERSECT'),
        fails_on('informix', 'no support for INTERSECT'),
    )

def except_(fn):
    """Target database must support EXCEPT or equivalent (i.e. MINUS)."""
    return _chain_decorators_on(
        fn,
        fails_on('firebird', 'no support for EXCEPT'),
        fails_on('mysql', 'no support for EXCEPT'),
        fails_on('sybase', 'no support for EXCEPT'),
        fails_on('informix', 'no support for EXCEPT'),
    )

def offset(fn):
    """Target database must support some method of adding OFFSET or equivalent to a result set."""
    return _chain_decorators_on(
        fn,
        fails_on('sybase', 'no support for OFFSET or equivalent'),
    )

def window_functions(fn):
    return _chain_decorators_on(
        fn,
        only_on(('postgresql', 'mssql', 'oracle'),
                "Backend does not support window functions"),
    )

def returning(fn):
    return _chain_decorators_on(
        fn,
        no_support('access', "'returning' not supported by database"),
        no_support('sqlite', "'returning' not supported by database"),
        no_support('mysql', "'returning' not supported by database"),
        no_support('maxdb', "'returning' not supported by database"),
        no_support('sybase', "'returning' not supported by database"),
        no_support('informix', "'returning' not supported by database"),
    )

def two_phase_transactions(fn):
    """Target database must support two-phase transactions."""
    return _chain_decorators_on(
        fn,
        no_support('access', 'not supported by database'),
        no_support('firebird', 'no SA implementation'),
        no_support('maxdb', 'not supported by database'),
        no_support('mssql', 'FIXME: guessing, needs confirmation'),
        no_support('oracle', 'no SA implementation'),
        no_support('drizzle', 'not supported by database'),
        no_support('sqlite', 'not supported by database'),
        no_support('sybase', 'FIXME: guessing, needs confirmation'),
        no_support('postgresql+zxjdbc', 'FIXME: JDBC driver confuses the transaction state, may '
                   'need separate XA implementation'),
        exclude('mysql', '<', (5, 0, 3), 'not supported by database'),
        )

def views(fn):
    """Target database must support VIEWs."""
    return _chain_decorators_on(
        fn,
        no_support('drizzle', 'no VIEW support'),
        )

def unicode_connections(fn):
    """Target driver must support some encoding of Unicode across the wire."""
    # TODO: expand to exclude MySQLdb versions w/ broken unicode
    return _chain_decorators_on(
        fn,
        exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'),
        )

def unicode_ddl(fn):
    """Target driver must support some encoding of Unicode across the wire."""
    # TODO: expand to exclude MySQLdb versions w/ broken unicode
    return _chain_decorators_on(
        fn,
        no_support('maxdb', 'database support flakey'),
        no_support('oracle', 'FIXME: no support in database?'),
        no_support('sybase', 'FIXME: guessing, needs confirmation'),
        no_support('mssql+pymssql', 'no FreeTDS support'),
        exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'),
        )

def sane_rowcount(fn):
    return _chain_decorators_on(
        fn,
        skip_if(lambda: not testing.db.dialect.supports_sane_rowcount)
    )

def cextensions(fn):
    return _chain_decorators_on(
        fn,
        skip_if(lambda: not _has_cextensions(), "C extensions not installed")
    )

def dbapi_lastrowid(fn):
    if util.pypy:
        return _chain_decorators_on(
            fn,
            fails_if(lambda:True)
        )
    else:
        return _chain_decorators_on(
            fn,
            fails_on_everything_except('mysql+mysqldb', 'mysql+oursql',
                                       'sqlite+pysqlite', 'mysql+pymysql'),
        )

def sane_multi_rowcount(fn):
    return _chain_decorators_on(
        fn,
        skip_if(lambda: not testing.db.dialect.supports_sane_multi_rowcount)
    )

def nullsordering(fn):
    """Target backends that support nulls ordering."""
    return _chain_decorators_on(
        fn,
        fails_on_everything_except('postgresql', 'oracle', 'firebird')
    )

def reflects_pk_names(fn):
    """Target driver reflects the name of primary key constraints."""
    return _chain_decorators_on(
        fn,
        fails_on_everything_except('postgresql', 'oracle')
    )

def python2(fn):
    return _chain_decorators_on(
        fn,
        skip_if(
            lambda: sys.version_info >= (3,),
            "Python version 2.xx is required."
            )
    )

def python3(fn):
    return _chain_decorators_on(
        fn,
        skip_if(
            lambda: sys.version_info < (3,),
            "Python version 3.xx is required."
            )
    )

def python26(fn):
    return _chain_decorators_on(
        fn,
        skip_if(
            lambda: sys.version_info < (2, 6),
            "Python version 2.6 or greater is required"
        )
    )

def python25(fn):
    return _chain_decorators_on(
        fn,
        skip_if(
            lambda: sys.version_info < (2, 5),
            "Python version 2.5 or greater is required"
        )
    )

def cpython(fn):
    return _chain_decorators_on(
         fn,
         skip_if(lambda: util.jython or util.pypy, 
           "cPython interpreter needed"
         )
    )

def _has_cextensions():
    try:
        from sqlalchemy import cresultproxy, cprocessors
        return True
    except ImportError:
        return False

def _has_sqlite():
    from sqlalchemy import create_engine
    try:
        e = create_engine('sqlite://')
        return True
    except ImportError:
        return False

def _has_mysql_on_windows():
    return testing.against('mysql') and \
            testing.db.dialect._server_casing == 1

def _has_mysql_fully_case_sensitive():
    return testing.against('mysql') and \
            testing.db.dialect._server_casing == 0

def sqlite(fn):
    return _chain_decorators_on(
        fn,
        skip_if(lambda: not _has_sqlite())
    )

def ad_hoc_engines(fn):
    """Test environment must allow ad-hoc engine/connection creation.
    
    DBs that scale poorly for many connections, even when closed, i.e.
    Oracle, may use the "--low-connections" option which flags this requirement
    as not present.
    
    """
    return _chain_decorators_on(
        fn,
        skip_if(lambda: config.options.low_connections)
    )

def skip_mysql_on_windows(fn):
    """Catchall for a large variety of MySQL on Windows failures"""

    return _chain_decorators_on(
        fn,
        skip_if(_has_mysql_on_windows,
            "Not supported on MySQL + Windows"
        )
    )

def english_locale_on_postgresql(fn):
    return _chain_decorators_on(
        fn,
        skip_if(lambda: testing.against('postgresql') \
                and not testing.db.scalar('SHOW LC_COLLATE').startswith('en'))
    )