
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Then kimchi source code can make use of it Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> --- src/kimchi/utils.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tests/utils.py | 47 ++--------------------------------------------- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index f7eda93..bf2a760 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -84,3 +84,49 @@ def import_class(class_path): def import_module(module_name): return __import__(module_name, fromlist=['']) + + +class RollbackContext(object): + ''' + A context manager for recording and playing rollback. + The first exception will be remembered and re-raised after rollback + + Sample usage: + with RollbackContext() as rollback: + step1() + rollback.prependDefer(lambda: undo step1) + def undoStep2(arg): pass + step2() + rollback.prependDefer(undoStep2, arg) + ''' + def __init__(self, *args): + self._finally = [] + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + firstException = exc_value + + for undo, args, kwargs in self._finally: + try: + undo(*args, **kwargs) + except Exception as e: + # keep the earliest exception info + if not firstException: + firstException = e + # keep the original traceback info + traceback = sys.exc_info()[2] + + # re-raise the earliest exception + if firstException is not None: + if type(firstException) is str: + sys.stderr.write(firstException) + else: + raise firstException, None, traceback + + def defer(self, func, *args, **kwargs): + self._finally.append((func, args, kwargs)) + + def prependDefer(self, func, *args, **kwargs): + self._finally.insert(0, (func, args, kwargs)) diff --git a/tests/utils.py b/tests/utils.py index c114813..e8acb2b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -32,6 +32,8 @@ from contextlib import closing import unittest import base64 +from kimchi.utils import RollbackContext + import kimchi.server import kimchi.model @@ -137,51 +139,6 @@ def https_request(host, port, path, data=None, method='GET', headers=None): return _request(conn, path, data, method, headers) -class RollbackContext(object): - ''' - A context manager for recording and playing rollback. - The first exception will be remembered and re-raised after rollback - - Sample usage: - with RollbackContext() as rollback: - step1() - rollback.prependDefer(lambda: undo step1) - def undoStep2(arg): pass - step2() - rollback.prependDefer(undoStep2, arg) - ''' - def __init__(self, *args): - self._finally = [] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - firstException = exc_value - - for undo, args, kwargs in self._finally: - try: - undo(*args, **kwargs) - except Exception as e: - # keep the earliest exception info - if not firstException: - firstException = e - # keep the original traceback info - traceback = sys.exc_info()[2] - - # re-raise the earliest exception - if firstException is not None: - if type(firstException) is str: - sys.stderr.write(firstException) - else: - raise firstException, None, traceback - - def defer(self, func, *args, **kwargs): - self._finally.append((func, args, kwargs)) - - def prependDefer(self, func, *args, **kwargs): - self._finally.insert(0, (func, args, kwargs)) - def patch_auth(): """ Override the authenticate function with a simple test against an -- 1.8.4.2