1
from __future__ import with_statement
4
from nose import SkipTest
5
from ..util import decorator
11
class skip_if(object):
12
def __init__(self, predicate, reason=None):
13
self.predicate = _as_predicate(predicate)
20
return not self.predicate()
22
@contextlib.contextmanager
23
def fail_if(self, name='block'):
28
print ("%s failed as expected (%s): %s " % (
29
name, self.predicate, str(ex)))
35
"Unexpected success for '%s' (%s)" %
36
(name, self.predicate))
38
def __call__(self, fn):
40
def decorate(fn, *args, **kw):
49
fn.__name__, self.predicate
54
with self._fails_on.fail_if(name=fn.__name__):
55
return fn(*args, **kw)
57
return fn(*args, **kw)
60
def fails_on(self, other, reason=None):
61
self._fails_on = skip_if(other, reason)
65
class fails_if(skip_if):
66
def __call__(self, fn):
68
def decorate(fn, *args, **kw):
69
with self.fail_if(name=fn.__name__):
70
return fn(*args, **kw)
74
def only_if(predicate, reason=None):
75
predicate = _as_predicate(predicate)
76
return skip_if(NotPredicate(predicate), reason)
79
def succeeds_if(predicate, reason=None):
80
predicate = _as_predicate(predicate)
81
return fails_if(NotPredicate(predicate), reason)
84
class Predicate(object):
86
def as_predicate(cls, predicate):
87
if isinstance(predicate, skip_if):
88
return predicate.predicate
89
elif isinstance(predicate, Predicate):
91
elif isinstance(predicate, list):
92
return OrPredicate([cls.as_predicate(pred) for pred in predicate])
93
elif isinstance(predicate, tuple):
94
return SpecPredicate(*predicate)
95
elif isinstance(predicate, basestring):
96
return SpecPredicate(predicate, None, None)
97
elif util.callable(predicate):
98
return LambdaPredicate(predicate)
100
assert False, "unknown predicate type: %s" % predicate
103
class BooleanPredicate(Predicate):
104
def __init__(self, value, description=None):
106
self.description = description or "boolean %s" % value
111
def _as_string(self, negate=False):
113
return "not " + self.description
115
return self.description
118
return self._as_string()
121
class SpecPredicate(Predicate):
122
def __init__(self, db, op=None, spec=None, description=None):
126
self.description = description
135
'in': operator.contains,
136
'between': lambda val, pair: val >= pair[0] and val <= pair[1],
139
def __call__(self, engine=None):
144
dialect, driver = self.db.split('+')
146
dialect, driver = self.db, None
148
if dialect and engine.name != dialect:
150
if driver is not None and engine.driver != driver:
153
if self.op is not None:
154
assert driver is None, "DBAPI version specs not supported yet"
156
version = _server_version(engine)
157
oper = hasattr(self.op, '__call__') and self.op \
158
or self._ops[self.op]
159
return oper(version, self.spec)
163
def _as_string(self, negate=False):
164
if self.description is not None:
165
return self.description
166
elif self.op is None:
168
return "not %s" % self.db
170
return "%s" % self.db
173
return "not %s %s %s" % (
179
return "%s %s %s" % (
186
return self._as_string()
189
class LambdaPredicate(Predicate):
190
def __init__(self, lambda_, description=None, args=None, kw=None):
191
self.lambda_ = lambda_
192
self.args = args or ()
195
self.description = description
196
elif lambda_.__doc__:
197
self.description = lambda_.__doc__
199
self.description = "custom function"
202
return self.lambda_(*self.args, **self.kw)
204
def _as_string(self, negate=False):
206
return "not " + self.description
208
return self.description
211
return self._as_string()
214
class NotPredicate(Predicate):
215
def __init__(self, predicate):
216
self.predicate = predicate
218
def __call__(self, *arg, **kw):
219
return not self.predicate(*arg, **kw)
222
return self.predicate._as_string(True)
225
class OrPredicate(Predicate):
226
def __init__(self, predicates, description=None):
227
self.predicates = predicates
228
self.description = description
230
def __call__(self, *arg, **kw):
231
for pred in self.predicates:
239
def _eval_str(self, negate=False):
240
if self._str is None:
242
conjunction = " and "
245
return conjunction.join(p._as_string(negate=negate)
246
for p in self.predicates)
248
return self._str._as_string(negate=negate)
250
def _negation_str(self):
251
if self.description is not None:
252
return "Not " + (self.description % {"spec": self._str})
254
return self._eval_str(negate=True)
256
def _as_string(self, negate=False):
258
return self._negation_str()
260
if self.description is not None:
261
return self.description % {"spec": self._str}
263
return self._eval_str()
266
return self._as_string()
268
_as_predicate = Predicate.as_predicate
271
def _is_excluded(db, op, spec):
272
return SpecPredicate(db, op, spec)()
275
def _server_version(engine):
276
"""Return a server_version_info tuple."""
278
# force metadata to be retrieved
279
conn = engine.connect()
280
version = getattr(engine.dialect, 'server_version_info', ())
287
Predicate.as_predicate(db) for db in dbs
292
return skip_if(BooleanPredicate(False, "mark as execute"))
296
return skip_if(BooleanPredicate(True, "marked as skip"))
300
def future(fn, *args, **kw):
301
return fails_if(LambdaPredicate(fn, *args, **kw), "Future feature")
304
def fails_on(db, reason=None):
305
return fails_if(SpecPredicate(db), reason)
308
def fails_on_everything_except(*dbs):
311
SpecPredicate(db) for db in dbs
316
def skip(db, reason=None):
317
return skip_if(SpecPredicate(db), reason)
320
def only_on(dbs, reason=None):
322
OrPredicate([SpecPredicate(db) for db in util.to_list(dbs)])
326
def exclude(db, op, spec, reason=None):
327
return skip_if(SpecPredicate(db, op, spec), reason)
330
def against(*queries):
332
Predicate.as_predicate(query)