Factorize some code using ContextDecorator.

This commit is contained in:
Thomas Chaumeny 2014-08-19 18:32:02 +02:00 committed by Simon Charette
parent c9c0be31c5
commit 191d953c99
3 changed files with 24 additions and 19 deletions

View File

@ -1,9 +1,7 @@
from functools import wraps
from django.db import ( from django.db import (
connections, DEFAULT_DB_ALIAS, connections, DEFAULT_DB_ALIAS,
DatabaseError, Error, ProgrammingError) DatabaseError, Error, ProgrammingError)
from django.utils.decorators import available_attrs from django.utils.decorators import ContextDecorator
class TransactionManagementError(ProgrammingError): class TransactionManagementError(ProgrammingError):
@ -109,7 +107,7 @@ def set_rollback(rollback, using=None):
# Decorators / context managers # # Decorators / context managers #
################################# #################################
class Atomic(object): class Atomic(ContextDecorator):
""" """
This class guarantees the atomic execution of a given block. This class guarantees the atomic execution of a given block.
@ -285,13 +283,6 @@ class Atomic(object):
else: else:
connection.in_atomic_block = False 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): def atomic(using=None, savepoint=True):
# Bare decorator: @atomic -- although the first argument is called # Bare decorator: @atomic -- although the first argument is called

View File

@ -18,6 +18,7 @@ from django.template import Template, loader, TemplateDoesNotExist
from django.template.loaders import cached from django.template.loaders import cached
from django.test.signals import template_rendered, setting_changed from django.test.signals import template_rendered, setting_changed
from django.utils import six from django.utils import six
from django.utils.decorators import ContextDecorator
from django.utils.deprecation import RemovedInDjango19Warning, RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango19Warning, RemovedInDjango20Warning
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.translation import deactivate from django.utils.translation import deactivate
@ -146,7 +147,7 @@ def get_runner(settings, test_runner_class=None):
return test_runner return test_runner
class override_template_loaders(object): class override_template_loaders(ContextDecorator):
""" """
Acts as a function decorator, context manager or start/end manager and Acts as a function decorator, context manager or start/end manager and
override the template loaders. It could be used in the following ways: override the template loaders. It could be used in the following ways:
@ -174,13 +175,6 @@ class override_template_loaders(object):
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
loader.template_source_loaders = self.old_loaders loader.template_source_loaders = self.old_loaders
def __call__(self, test_func):
@wraps(test_func)
def inner(*args, **kwargs):
with self:
return test_func(*args, **kwargs)
return inner
@classmethod @classmethod
def override(cls, *loaders): def override(cls, *loaders):
if hasattr(loader, RESTORE_LOADERS_ATTR): if hasattr(loader, RESTORE_LOADERS_ATTR):

View File

@ -1,5 +1,10 @@
"Functions that help with dynamically creating decorators for views." "Functions that help with dynamically creating decorators for views."
try:
from contextlib import ContextDecorator
except ImportError:
ContextDecorator = None
from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
from django.utils import six from django.utils import six
@ -124,3 +129,18 @@ def make_middleware_decorator(middleware_class):
return _wrapped_view return _wrapped_view
return _decorator return _decorator
return _make_decorator return _make_decorator
if ContextDecorator is None:
# ContextDecorator was introduced in Python 3.2
# See https://docs.python.org/3/library/contextlib.html#contextlib.ContextDecorator
class ContextDecorator(object):
"""
A base class that enables a context manager to also be used as a decorator.
"""
def __call__(self, func):
@wraps(func, assigned=available_attrs(func))
def inner(*args, **kwargs):
with self:
return func(*args, **kwargs)
return inner