From: Jason Kirtland Date: Fri, 2 Nov 2007 00:27:40 +0000 (+0000) Subject: More improvements to testlib's mapper decorator X-Git-Tag: rel_0_4_1~76 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ceb782ba49f494c5aca0c31a60f77d87373ae2ea;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git More improvements to testlib's mapper decorator --- diff --git a/test/testlib/orm.py b/test/testlib/orm.py index 3a10b08629..f7d761b36b 100644 --- a/test/testlib/orm.py +++ b/test/testlib/orm.py @@ -1,32 +1,91 @@ import testbase from testlib import config -import inspect +import inspect, re orm = None __all__ = 'mapper', +_whitespace = re.compile(r'^(\s+)') + +def _find_pragma(lines, current): + m = _whitespace.match(lines[current]) + basis = m and m.group() or '' + + for line in reversed(lines[0:current]): + if 'testlib.pragma' in line: + return line + m = _whitespace.match(line) + indent = m and m.group() or '' + + # simplistic detection: + + # >> # testlib.pragma foo + # >> center_line() + if indent == basis: + break + # >> # testlib.pragma foo + # >> if fleem: + # >> center_line() + if line.endswith(':'): + break + return None + def _make_blocker(method_name, fallback): + """Creates tripwired variant of a method, raising when called. + + To excempt an invocation from blockage, there are two options. + + 1) add a pragma in a comment:: + + # testlib.pragma exempt:methodname + offending_line() + + 2) add a magic cookie to the function's namespace:: + __sa_baremethodname_exempt__ = True + ... + offending_line() + another_offending_lines() + + The second is useful for testing and development. + """ + + if method_name.startswith('__') and method_name.endswith('__'): + frame_marker = '__sa_%s_exempt__' % method_name[2:-2] + else: + frame_marker = '__sa_%s_exempt__' % method_name + pragma_marker = 'exempt:' + method_name + def method(self, *args, **kw): frame_r = None try: - frame_r = inspect.stack()[1] - module = frame_r[0].f_globals.get('__name__', '') + frame = inspect.stack()[1][0] + frame_r = inspect.getframeinfo(frame, 9) + + module = frame.f_globals.get('__name__', '') type_ = type(self) - if not module.startswith('sqlalchemy'): + pragma = _find_pragma(*frame_r[3:5]) + + exempt = ( + (not module.startswith('sqlalchemy')) or + (pragma and pragma_marker in pragma) or + (frame_marker in frame.f_locals)) + + if exempt: supermeth = getattr(super(type_, self), method_name, None) - if supermeth is None or supermeth.im_func is method: + if (supermeth is None or + getattr(supermeth, 'im_func', None) is method): return fallback(self, *args, **kw) else: return supermeth(*args, **kw) else: raise AssertionError( "%s.%s called in %s, line %s in %s" % ( - type_.__name__, method_name, module, frame_r[2], frame_r[3])) + type_.__name__, method_name, module, frame_r[1], frame_r[2])) finally: - del frame_r + del frame method.__name__ = method_name return method @@ -36,8 +95,8 @@ def mapper(type_, *args, **kw): from sqlalchemy import orm forbidden = [ - ('__hash__', 'unhashable', None), - ('__eq__', 'noncomparable', lambda s, x, y: x is y), + ('__hash__', 'unhashable', lambda s: id(s)), + ('__eq__', 'noncomparable', lambda s, o: s is o), ('__nonzero__', 'truthless', lambda s: 1), ] if type_.__bases__ == (object,):