diff options
Diffstat (limited to 'lib/python2.7/site-packages/django/db/transaction.py')
-rw-r--r-- | lib/python2.7/site-packages/django/db/transaction.py | 541 |
1 files changed, 0 insertions, 541 deletions
diff --git a/lib/python2.7/site-packages/django/db/transaction.py b/lib/python2.7/site-packages/django/db/transaction.py deleted file mode 100644 index f75137a..0000000 --- a/lib/python2.7/site-packages/django/db/transaction.py +++ /dev/null @@ -1,541 +0,0 @@ -""" -This module implements a transaction manager that can be used to define -transaction handling in a request or view function. It is used by transaction -control middleware and decorators. - -The transaction manager can be in managed or in auto state. Auto state means the -system is using a commit-on-save strategy (actually it's more like -commit-on-change). As soon as the .save() or .delete() (or related) methods are -called, a commit is made. - -Managed transactions don't do those commits, but will need some kind of manual -or implicit commits or rollbacks. -""" - -import warnings - -from functools import wraps - -from django.db import ( - connections, DEFAULT_DB_ALIAS, - DatabaseError, Error, ProgrammingError) -from django.utils.decorators import available_attrs - - -class TransactionManagementError(ProgrammingError): - """ - This exception is thrown when transaction management is used improperly. - """ - pass - -################ -# Private APIs # -################ - -def get_connection(using=None): - """ - Get a database connection by name, or the default database connection - if no name is provided. - """ - if using is None: - using = DEFAULT_DB_ALIAS - return connections[using] - -########################### -# Deprecated private APIs # -########################### - -def abort(using=None): - """ - Roll back any ongoing transactions and clean the transaction management - state of the connection. - - This method is to be used only in cases where using balanced - leave_transaction_management() calls isn't possible. For example after a - request has finished, the transaction state isn't known, yet the connection - must be cleaned up for the next request. - """ - get_connection(using).abort() - -def enter_transaction_management(managed=True, using=None, forced=False): - """ - Enters transaction management for a running thread. It must be balanced with - the appropriate leave_transaction_management call, since the actual state is - managed as a stack. - - The state and dirty flag are carried over from the surrounding block or - from the settings, if there is no surrounding block (dirty is always false - when no current block is running). - """ - get_connection(using).enter_transaction_management(managed, forced) - -def leave_transaction_management(using=None): - """ - Leaves transaction management for a running thread. A dirty flag is carried - over to the surrounding block, as a commit will commit all changes, even - those from outside. (Commits are on connection level.) - """ - get_connection(using).leave_transaction_management() - -def is_dirty(using=None): - """ - Returns True if the current transaction requires a commit for changes to - happen. - """ - return get_connection(using).is_dirty() - -def set_dirty(using=None): - """ - Sets a dirty flag for the current thread and code streak. This can be used - to decide in a managed block of code to decide whether there are open - changes waiting for commit. - """ - get_connection(using).set_dirty() - -def set_clean(using=None): - """ - Resets a dirty flag for the current thread and code streak. This can be used - to decide in a managed block of code to decide whether a commit or rollback - should happen. - """ - get_connection(using).set_clean() - -def is_managed(using=None): - warnings.warn("'is_managed' is deprecated.", - PendingDeprecationWarning, stacklevel=2) - -def managed(flag=True, using=None): - warnings.warn("'managed' no longer serves a purpose.", - PendingDeprecationWarning, stacklevel=2) - -def commit_unless_managed(using=None): - warnings.warn("'commit_unless_managed' is now a no-op.", - PendingDeprecationWarning, stacklevel=2) - -def rollback_unless_managed(using=None): - warnings.warn("'rollback_unless_managed' is now a no-op.", - PendingDeprecationWarning, stacklevel=2) - -############### -# Public APIs # -############### - -def get_autocommit(using=None): - """ - Get the autocommit status of the connection. - """ - return get_connection(using).get_autocommit() - -def set_autocommit(autocommit, using=None): - """ - Set the autocommit status of the connection. - """ - return get_connection(using).set_autocommit(autocommit) - -def commit(using=None): - """ - Commits a transaction and resets the dirty flag. - """ - get_connection(using).commit() - -def rollback(using=None): - """ - Rolls back a transaction and resets the dirty flag. - """ - get_connection(using).rollback() - -def savepoint(using=None): - """ - Creates a savepoint (if supported and required by the backend) inside the - current transaction. Returns an identifier for the savepoint that will be - used for the subsequent rollback or commit. - """ - return get_connection(using).savepoint() - -def savepoint_rollback(sid, using=None): - """ - Rolls back the most recent savepoint (if one exists). Does nothing if - savepoints are not supported. - """ - get_connection(using).savepoint_rollback(sid) - -def savepoint_commit(sid, using=None): - """ - Commits the most recent savepoint (if one exists). Does nothing if - savepoints are not supported. - """ - get_connection(using).savepoint_commit(sid) - -def clean_savepoints(using=None): - """ - Resets the counter used to generate unique savepoint ids in this thread. - """ - get_connection(using).clean_savepoints() - -def get_rollback(using=None): - """ - Gets the "needs rollback" flag -- for *advanced use* only. - """ - return get_connection(using).get_rollback() - -def set_rollback(rollback, using=None): - """ - Sets or unsets the "needs rollback" flag -- for *advanced use* only. - - When `rollback` is `True`, it triggers a rollback when exiting the - innermost enclosing atomic block that has `savepoint=True` (that's the - default). Use this to force a rollback without raising an exception. - - When `rollback` is `False`, it prevents such a rollback. Use this only - after rolling back to a known-good state! Otherwise, you break the atomic - block and data corruption may occur. - """ - return get_connection(using).set_rollback(rollback) - -################################# -# Decorators / context managers # -################################# - -class Atomic(object): - """ - This class guarantees the atomic execution of a given block. - - An instance can be used either as a decorator or as a context manager. - - When it's used as a decorator, __call__ wraps the execution of the - decorated function in the instance itself, used as a context manager. - - When it's used as a context manager, __enter__ creates a transaction or a - savepoint, depending on whether a transaction is already in progress, and - __exit__ commits the transaction or releases the savepoint on normal exit, - and rolls back the transaction or to the savepoint on exceptions. - - It's possible to disable the creation of savepoints if the goal is to - ensure that some code runs within a transaction without creating overhead. - - A stack of savepoints identifiers is maintained as an attribute of the - connection. None denotes the absence of a savepoint. - - This allows reentrancy even if the same AtomicWrapper is reused. For - example, it's possible to define `oa = @atomic('other')` and use `@oa` or - `with oa:` multiple times. - - Since database connections are thread-local, this is thread-safe. - """ - - def __init__(self, using, savepoint): - self.using = using - self.savepoint = savepoint - - def __enter__(self): - connection = get_connection(self.using) - - if not connection.in_atomic_block: - # Reset state when entering an outermost atomic block. - connection.commit_on_exit = True - connection.needs_rollback = False - if not connection.get_autocommit(): - # Some database adapters (namely sqlite3) don't handle - # transactions and savepoints properly when autocommit is off. - # Turning autocommit back on isn't an option; it would trigger - # a premature commit. Give up if that happens. - if connection.features.autocommits_when_autocommit_is_off: - raise TransactionManagementError( - "Your database backend doesn't behave properly when " - "autocommit is off. Turn it on before using 'atomic'.") - # When entering an atomic block with autocommit turned off, - # Django should only use savepoints and shouldn't commit. - # This requires at least a savepoint for the outermost block. - if not self.savepoint: - raise TransactionManagementError( - "The outermost 'atomic' block cannot use " - "savepoint = False when autocommit is off.") - # Pretend we're already in an atomic block to bypass the code - # that disables autocommit to enter a transaction, and make a - # note to deal with this case in __exit__. - connection.in_atomic_block = True - connection.commit_on_exit = False - - if connection.in_atomic_block: - # We're already in a transaction; create a savepoint, unless we - # were told not to or we're already waiting for a rollback. The - # second condition avoids creating useless savepoints and prevents - # overwriting needs_rollback until the rollback is performed. - if self.savepoint and not connection.needs_rollback: - sid = connection.savepoint() - connection.savepoint_ids.append(sid) - else: - connection.savepoint_ids.append(None) - else: - # We aren't in a transaction yet; create one. - # The usual way to start a transaction is to turn autocommit off. - # However, some database adapters (namely sqlite3) don't handle - # transactions and savepoints properly when autocommit is off. - # In such cases, start an explicit transaction instead, which has - # the side-effect of disabling autocommit. - if connection.features.autocommits_when_autocommit_is_off: - connection._start_transaction_under_autocommit() - connection.autocommit = False - else: - connection.set_autocommit(False) - connection.in_atomic_block = True - - def __exit__(self, exc_type, exc_value, traceback): - connection = get_connection(self.using) - - if connection.savepoint_ids: - sid = connection.savepoint_ids.pop() - else: - # Prematurely unset this flag to allow using commit or rollback. - connection.in_atomic_block = False - - try: - if connection.closed_in_transaction: - # The database will perform a rollback by itself. - # Wait until we exit the outermost block. - pass - - elif exc_type is None and not connection.needs_rollback: - if connection.in_atomic_block: - # Release savepoint if there is one - if sid is not None: - try: - connection.savepoint_commit(sid) - except DatabaseError: - try: - connection.savepoint_rollback(sid) - except Error: - # If rolling back to a savepoint fails, mark for - # rollback at a higher level and avoid shadowing - # the original exception. - connection.needs_rollback = True - raise - else: - # Commit transaction - try: - connection.commit() - except DatabaseError: - try: - connection.rollback() - except Error: - # An error during rollback means that something - # went wrong with the connection. Drop it. - connection.close() - raise - else: - # This flag will be set to True again if there isn't a savepoint - # allowing to perform the rollback at this level. - connection.needs_rollback = False - if connection.in_atomic_block: - # Roll back to savepoint if there is one, mark for rollback - # otherwise. - if sid is None: - connection.needs_rollback = True - else: - try: - connection.savepoint_rollback(sid) - except Error: - # If rolling back to a savepoint fails, mark for - # rollback at a higher level and avoid shadowing - # the original exception. - connection.needs_rollback = True - else: - # Roll back transaction - try: - connection.rollback() - except Error: - # An error during rollback means that something - # went wrong with the connection. Drop it. - connection.close() - - finally: - # Outermost block exit when autocommit was enabled. - if not connection.in_atomic_block: - if connection.closed_in_transaction: - connection.connection = None - elif connection.features.autocommits_when_autocommit_is_off: - connection.autocommit = True - else: - connection.set_autocommit(True) - # Outermost block exit when autocommit was disabled. - elif not connection.savepoint_ids and not connection.commit_on_exit: - if connection.closed_in_transaction: - connection.connection = None - else: - connection.in_atomic_block = False - - def __call__(self, func): - @wraps(func, assigned=available_attrs(func)) - def inner(*args, **kwargs): - with self: - return func(*args, **kwargs) - return inner - - -def atomic(using=None, savepoint=True): - # Bare decorator: @atomic -- although the first argument is called - # `using`, it's actually the function being decorated. - if callable(using): - return Atomic(DEFAULT_DB_ALIAS, savepoint)(using) - # Decorator: @atomic(...) or context manager: with atomic(...): ... - else: - return Atomic(using, savepoint) - - -def _non_atomic_requests(view, using): - try: - view._non_atomic_requests.add(using) - except AttributeError: - view._non_atomic_requests = set([using]) - return view - - -def non_atomic_requests(using=None): - if callable(using): - return _non_atomic_requests(using, DEFAULT_DB_ALIAS) - else: - if using is None: - using = DEFAULT_DB_ALIAS - return lambda view: _non_atomic_requests(view, using) - - -############################################ -# Deprecated decorators / context managers # -############################################ - -class Transaction(object): - """ - Acts as either a decorator, or a context manager. If it's a decorator it - takes a function and returns a wrapped function. If it's a contextmanager - it's used with the ``with`` statement. In either event entering/exiting - are called before and after, respectively, the function/block is executed. - - autocommit, commit_on_success, and commit_manually contain the - implementations of entering and exiting. - """ - def __init__(self, entering, exiting, using): - self.entering = entering - self.exiting = exiting - self.using = using - - def __enter__(self): - self.entering(self.using) - - def __exit__(self, exc_type, exc_value, traceback): - self.exiting(exc_type, self.using) - - def __call__(self, func): - @wraps(func) - def inner(*args, **kwargs): - with self: - return func(*args, **kwargs) - return inner - -def _transaction_func(entering, exiting, using): - """ - Takes 3 things, an entering function (what to do to start this block of - transaction management), an exiting function (what to do to end it, on both - success and failure, and using which can be: None, indiciating using is - DEFAULT_DB_ALIAS, a callable, indicating that using is DEFAULT_DB_ALIAS and - to return the function already wrapped. - - Returns either a Transaction objects, which is both a decorator and a - context manager, or a wrapped function, if using is a callable. - """ - # Note that although the first argument is *called* `using`, it - # may actually be a function; @autocommit and @autocommit('foo') - # are both allowed forms. - if using is None: - using = DEFAULT_DB_ALIAS - if callable(using): - return Transaction(entering, exiting, DEFAULT_DB_ALIAS)(using) - return Transaction(entering, exiting, using) - - -def autocommit(using=None): - """ - Decorator that activates commit on save. This is Django's default behavior; - this decorator is useful if you globally activated transaction management in - your settings file and want the default behavior in some view functions. - """ - warnings.warn("autocommit is deprecated in favor of set_autocommit.", - PendingDeprecationWarning, stacklevel=2) - - def entering(using): - enter_transaction_management(managed=False, using=using) - - def exiting(exc_type, using): - leave_transaction_management(using=using) - - return _transaction_func(entering, exiting, using) - -def commit_on_success(using=None): - """ - This decorator activates commit on response. This way, if the view function - runs successfully, a commit is made; if the viewfunc produces an exception, - a rollback is made. This is one of the most common ways to do transaction - control in Web apps. - """ - warnings.warn("commit_on_success is deprecated in favor of atomic.", - PendingDeprecationWarning, stacklevel=2) - - def entering(using): - enter_transaction_management(using=using) - - def exiting(exc_type, using): - try: - if exc_type is not None: - if is_dirty(using=using): - rollback(using=using) - else: - if is_dirty(using=using): - try: - commit(using=using) - except: - rollback(using=using) - raise - finally: - leave_transaction_management(using=using) - - return _transaction_func(entering, exiting, using) - -def commit_manually(using=None): - """ - Decorator that activates manual transaction control. It just disables - automatic transaction control and doesn't do any commit/rollback of its - own -- it's up to the user to call the commit and rollback functions - themselves. - """ - warnings.warn("commit_manually is deprecated in favor of set_autocommit.", - PendingDeprecationWarning, stacklevel=2) - - def entering(using): - enter_transaction_management(using=using) - - def exiting(exc_type, using): - leave_transaction_management(using=using) - - return _transaction_func(entering, exiting, using) - -def commit_on_success_unless_managed(using=None, savepoint=False): - """ - Transitory API to preserve backwards-compatibility while refactoring. - - Once the legacy transaction management is fully deprecated, this should - simply be replaced by atomic. Until then, it's necessary to guarantee that - a commit occurs on exit, which atomic doesn't do when it's nested. - - Unlike atomic, savepoint defaults to False because that's closer to the - legacy behavior. - """ - connection = get_connection(using) - if connection.get_autocommit() or connection.in_atomic_block: - return atomic(using, savepoint) - else: - def entering(using): - pass - - def exiting(exc_type, using): - set_dirty(using=using) - - return _transaction_func(entering, exiting, using) |