Django

Code

Ticket #730: middleware_dict_single_instances_basic_sanity_checks-validation.diff

File middleware_dict_single_instances_basic_sanity_checks-validation.diff, 10.4 kB (added by mrts, 2 years ago)

Added validation as well. Consider this patch to be a draft of the general ideas, it's not even tested.

  • django/conf/project_template/settings.py

    old new  
    5757#     'django.template.loaders.eggs.load_template_source', 
    5858) 
    5959 
    60 MIDDLEWARE_CLASSES = ( 
    61     'django.middleware.common.CommonMiddleware', 
    62     'django.contrib.sessions.middleware.SessionMiddleware', 
    63     'django.contrib.auth.middleware.AuthenticationMiddleware', 
    64     'django.middleware.doc.XViewMiddleware', 
    65 
     60MIDDLEWARE_CLASSES = { 
     61    'request': ( 
     62        'django.middleware.common.CommonMiddleware', 
     63        'django.contrib.sessions.middleware.SessionMiddleware', 
     64        'django.contrib.auth.middleware.AuthenticationMiddleware', 
     65    ), 
     66    'response': ( 
     67        'django.contrib.sessions.middleware.SessionMiddleware', 
     68#        'django.middleware.http.ConditionalGetMiddleware', 
     69#        'django.middleware.gzip.GZipMiddleware', 
     70        'django.middleware.common.CommonMiddleware', 
     71    ), 
     72    'view': ( 
     73        'django.middleware.doc.XViewMiddleware', 
     74    ), 
     75
    6676 
    6777ROOT_URLCONF = '{{ project_name }}.urls' 
    6878 
  • django/conf/global_settings.py

    old new  
    291291# MIDDLEWARE # 
    292292############## 
    293293 
    294 # List of middleware classes to use.  Order is important; in the request phase, 
    295 # this middleware classes will be applied in the order given, and in the 
    296 # response phase the middleware will be applied in reverse order. 
    297 MIDDLEWARE_CLASSES = ( 
    298     'django.contrib.sessions.middleware.SessionMiddleware', 
    299     'django.contrib.auth.middleware.AuthenticationMiddleware', 
    300 #     'django.middleware.http.ConditionalGetMiddleware', 
    301 #     'django.middleware.gzip.GZipMiddleware', 
    302     'django.middleware.common.CommonMiddleware', 
    303     'django.middleware.doc.XViewMiddleware', 
    304 
     294# List of middleware classes to use.  Order is important; all middleware types 
     295# will be applied in the order given. 
     296MIDDLEWARE_CLASSES = { 
     297    'request': ( 
     298        'django.middleware.common.CommonMiddleware', 
     299        'django.contrib.sessions.middleware.SessionMiddleware', 
     300        'django.contrib.auth.middleware.AuthenticationMiddleware', 
     301    ), 
     302    'response': ( 
     303        'django.contrib.sessions.middleware.SessionMiddleware', 
     304#        'django.middleware.http.ConditionalGetMiddleware', 
     305#        'django.middleware.gzip.GZipMiddleware', 
     306        'django.middleware.common.CommonMiddleware', 
     307    ), 
     308    'view': ( 
     309        'django.middleware.doc.XViewMiddleware', 
     310    ), 
     311
    305312 
    306313############ 
    307314# SESSIONS # 
  • django/core/handlers/base.py

    old new  
    11import sys 
    22 
    33from django import http 
     4from django.core import exceptions 
    45from django.core import signals 
    56from django.utils.encoding import force_unicode 
    67 
     
    1617    def __init__(self): 
    1718        self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None 
    1819 
    19     def load_middleware(self): 
    20         """ 
    21         Populate middleware lists from settings.MIDDLEWARE_CLASSES. 
    22  
    23         Must be called after the environment is fixed (see __call__). 
    24         """ 
    25         from django.conf import settings 
    26         from django.core import exceptions 
     20    def _load_middleware_from_list(self, mw_paths): 
    2721        self._request_middleware = [] 
    2822        self._view_middleware = [] 
    2923        self._response_middleware = [] 
    3024        self._exception_middleware = [] 
    31         for middleware_path in settings.MIDDLEWARE_CLASSES: 
    32             try: 
    33                 dot = middleware_path.rindex('.') 
    34             except ValueError: 
    35                 raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path 
    36             mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:] 
    37             try: 
    38                 mod = __import__(mw_module, {}, {}, ['']) 
    39             except ImportError, e: 
    40                 raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e) 
    41             try: 
    42                 mw_class = getattr(mod, mw_classname) 
    43             except AttributeError: 
    44                 raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname) 
    45  
    46             try: 
    47                 mw_instance = mw_class() 
    48             except exceptions.MiddlewareNotUsed: 
    49                 continue 
    50  
     25        mw_instances = [ _middleware_instance_from_path(mw_path) for mw_path 
     26                in mw_paths ] 
     27        for mw_instance in mw_instances: 
    5128            if hasattr(mw_instance, 'process_request'): 
    5229                self._request_middleware.append(mw_instance.process_request) 
    5330            if hasattr(mw_instance, 'process_view'): 
     
    5734            if hasattr(mw_instance, 'process_exception'): 
    5835                self._exception_middleware.insert(0, mw_instance.process_exception) 
    5936 
     37    def _load_middleware_from_dict(self, mw_dict): 
     38        # fill the instances dict so that we have only one instance of each 
     39        # middleware 
     40        mw_instances = _middleware_instances_from_dict(mw_dict) 
     41        # it would be easy to do validation here, but it would be expensive 
     42        # for mw_path, mw_inst in mw_instances.items(): 
     43        #   for attr in ('request', 'view', 'response', 'exception'): 
     44        #       if hasattr(mw_inst, attr) and mw_path not in mw_dict[attr]: 
     45        #           raise ImproperlyConfigured("") 
     46 
     47        self._request_middleware = _particular_middleware_from_dicts('request', 
     48                mw_instances, mw_dict) 
     49        self._view_middleware = _particular_middleware_from_dicts('view', 
     50                mw_instances, mw_dict) 
     51        self._response_middleware = _particular_middleware_from_dicts('response', 
     52                mw_instances, mw_dict) 
     53        self._exception_middleware = _particular_middleware_from_dicts('exception', 
     54                mw_instances, mw_dict) 
     55 
     56    def load_middleware(self): 
     57        """ 
     58        Populate middleware lists from settings.MIDDLEWARE_CLASSES. 
     59 
     60        Must be called after the environment is fixed (see __call__). 
     61        """ 
     62        from django.conf import settings 
     63        if isinstance(settings.MIDDLEWARE_CLASSES, (tuple, list)): 
     64            self._load_middleware_from_list(settings.MIDDLEWARE_CLASSES) 
     65        elif isinstance(settings.MIDDLEWARE_CLASSES, (dict)): 
     66            self._load_middleware_from_dict(settings.MIDDLEWARE_CLASSES) 
     67        else: 
     68            raise exceptions.ImproperlyConfigured("MIDDLEWARE_CLASSES setting " 
     69                    "has to be either a tuple, list or a dict.") 
     70 
    6071    def get_response(self, request): 
    6172        "Returns an HttpResponse object for the given HttpRequest" 
    62         from django.core import exceptions, urlresolvers 
     73        from django.core import urlresolvers 
    6374        from django.conf import settings 
    6475 
    6576        # Apply request middleware 
     
    171182            response = func(request, response) 
    172183        return response 
    173184 
     185def validate_middleware(self): 
     186    # A very rough attempt at validation, doesn't load the middleware. 
     187    # Note that this assumes that if middleware has a process_foo method, 
     188    # then it has to be registered in MIDDLEWARE_CLASSES['foo']. 
     189    from django.conf import settings 
     190    # if MIDDLEWARE_CLASSES is a list, no easy way to validate 
     191    if isinstance(settings.MIDDLEWARE_CLASSES, (dict)): 
     192        mw_dict = settings.MIDDLEWARE_CLASSES 
     193        mw_instances = _middleware_instances_from_dict(mw_dict) 
     194        for mw_path, mw_inst in mw_instances.items(): 
     195            for attr in ('request', 'view', 'response', 'exception'): 
     196                if hasattr(mw_inst, attr) and mw_path not in mw_dict[attr]: 
     197                    raise exceptions.ImproperlyConfigured("%s has to " 
     198                            "be enabled for %s processing in " 
     199                            "MIDDLEWARE_CLASSES setting." % (mw_path, attr)) 
     200 
    174201def get_script_name(environ): 
    175202    """ 
    176203    Returns the equivalent of the HTTP request's SCRIPT_NAME environment 
     
    195222        return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))]) 
    196223    return force_unicode(environ.get('SCRIPT_NAME', u'')) 
    197224 
     225def _middleware_instance_from_path(middleware_path): 
     226    try: 
     227        dot = middleware_path.rindex('.') 
     228    except ValueError: 
     229        raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path 
     230    mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:] 
     231    try: 
     232        mod = __import__(mw_module, {}, {}, ['']) 
     233    except ImportError, e: 
     234        raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e) 
     235    try: 
     236        mw_class = getattr(mod, mw_classname) 
     237    except AttributeError: 
     238        raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname) 
     239    # I'm ignoring the MiddlewareNotUsed exception as it's not used in Django 
     240    # according to grep, not documented and the only use case I can see is to 
     241    # raise it in custom middleware __init__ to disable the middleware 
     242    # temporarily. That can be better achieved with disabling it in settings 
     243    # (where it is explicit and visible). If everybody is happy with that, the 
     244    # exception should be removed from core.exceptions. See also #7820. 
     245    return mw_class() 
     246 
     247def _particular_middleware_from_dicts(mw_type, mw_instance_dict, mw_dict): 
     248    mw_instance_list = [] 
     249    for mw_path in mw_dict.get(mw_type, []): 
     250        mw_instance = mw_instance_dict[mw_path] 
     251        if not hasattr(mw_instance, 'process_' + mw_type): 
     252            raise exceptions.ImproperlyConfigured("%s middleware needs " 
     253                    "a 'process_%s' method, but it's missing from %s." 
     254                    % (mw_type.title(), mw_type, mw_path)) 
     255        mw_instance_list.append(mw_instance) 
     256    return mw_instance_list 
     257 
     258def _middleware_instances_from_dict(mw_dict): 
     259    mw_instances = {} 
     260    for mw_path_tuple in mw_dict.values(): 
     261        for mw_path in mw_path_tuple: 
     262            if mw_path not in mw_instances: 
     263                mw_instances[mw_path] = _middleware_instance_from_path(mw_path) 
     264    return mw_instances