Django 1.6 upgrade: "cannot import name BaseHandler"
Question: I am trying to upgrade from Django 1.5.5 to Django 1.6. Everything tests fine,
but when I try to run my django project, I get the following error:

    
    
    ValueError: Unable to configure handler 'mail_admins': Cannot resolve 'vbenergyzone.core.utils.log.StaffSuperuserEmailHandler': cannot import name BaseHandler
    

Why?

Here is what I have tried:

  * I have removed my custom logging handler code completely. The project runs fine without any errors.
  * I have replaced my custom logging handler code and replaced it with the default handler code. I get the same error.
  * I have tried Django 1.6c1 and get the same error.
  * I have created a ticket: <https://code.djangoproject.com/ticket/21502>.

Here is my stacktrace:

    
    
    20:29:03 web.1    | started with pid 1501
    20:29:03 worker.1 | started with pid 1504
    20:29:03 web.1    | 2013-11-23 20:29:03 [1503] [INFO] Starting gunicorn 18.0
    20:29:03 web.1    | 2013-11-23 20:29:03 [1503] [INFO] Listening at: http://192.168.50.4:5000 (1503)
    20:29:03 web.1    | 2013-11-23 20:29:03 [1503] [INFO] Using worker: sync
    20:29:03 web.1    | 2013-11-23 20:29:03 [1518] [INFO] Booting worker with pid: 1518
    20:29:04 web.1    | 2013-11-23 14:29:04 [1518] [ERROR] Exception in worker process:
    20:29:04 web.1    | Traceback (most recent call last):
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 495, in spawn_worker
    20:29:04 web.1    |     worker.init_process()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/workers/base.py", line 106, in init_process
    20:29:04 web.1    |     self.wsgi = self.app.wsgi()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 114, in wsgi
    20:29:04 web.1    |     self.callable = self.load()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 62, in load
    20:29:04 web.1    |     return self.load_wsgiapp()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load_wsgiapp
    20:29:04 web.1    |     return util.import_app(self.app_uri)
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/util.py", line 354, in import_app
    20:29:04 web.1    |     __import__(module)
    20:29:04 web.1    |   File "/vagrant/vbenergyzone/wsgi.py", line 23, in <module>
    20:29:04 web.1    |     from django.core.wsgi import get_wsgi_application
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/core/wsgi.py", line 1, in <module>
    20:29:04 web.1    |     from django.core.handlers.wsgi import WSGIHandler
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 11, in <module>
    20:29:04 web.1    |     from django.core.handlers import base
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 12, in <module>
    20:29:04 web.1    |     from django.db import connections, transaction
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/db/__init__.py", line 83, in <module>
    20:29:04 web.1    |     signals.request_started.connect(reset_queries)
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 88, in connect
    20:29:04 web.1    |     if settings.DEBUG:
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/conf/__init__.py", line 54, in __getattr__
    20:29:04 web.1    |     self._setup(name)
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/conf/__init__.py", line 50, in _setup
    20:29:04 web.1    |     self._configure_logging()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/conf/__init__.py", line 80, in _configure_logging
    20:29:04 web.1    |     logging_config_func(self.LOGGING)
    20:29:04 web.1    |   File "/usr/lib/python2.7/logging/config.py", line 777, in dictConfig
    20:29:04 web.1    |     dictConfigClass(config).configure()
    20:29:04 web.1    |   File "/usr/lib/python2.7/logging/config.py", line 575, in configure
    20:29:04 web.1    |     '%r: %s' % (name, e))
    20:29:04 web.1    | ValueError: Unable to configure handler 'mail_admins': Cannot resolve 'vbenergyzone.core.utils.log.StaffSuperuserEmailHandler': cannot import name BaseHandler
    20:29:04 web.1    | Traceback (most recent call last):
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 495, in spawn_worker
    20:29:04 web.1    |     worker.init_process()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/workers/base.py", line 106, in init_process
    20:29:04 web.1    |     self.wsgi = self.app.wsgi()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 114, in wsgi
    20:29:04 web.1    |     self.callable = self.load()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 62, in load
    20:29:04 web.1    |     return self.load_wsgiapp()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load_wsgiapp
    20:29:04 web.1    |     return util.import_app(self.app_uri)
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/gunicorn/util.py", line 354, in import_app
    20:29:04 web.1    |     __import__(module)
    20:29:04 web.1    |   File "/vagrant/vbenergyzone/wsgi.py", line 23, in <module>
    20:29:04 web.1    |     from django.core.wsgi import get_wsgi_application
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/core/wsgi.py", line 1, in <module>
    20:29:04 web.1    |     from django.core.handlers.wsgi import WSGIHandler
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 11, in <module>
    20:29:04 web.1    |     from django.core.handlers import base
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 12, in <module>
    20:29:04 web.1    |     from django.db import connections, transaction
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/db/__init__.py", line 83, in <module>
    20:29:04 web.1    |     signals.request_started.connect(reset_queries)
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 88, in connect
    20:29:04 web.1    |     if settings.DEBUG:
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/conf/__init__.py", line 54, in __getattr__
    20:29:04 web.1    |     self._setup(name)
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/conf/__init__.py", line 50, in _setup
    20:29:04 web.1    |     self._configure_logging()
    20:29:04 web.1    |   File "/home/vagrant/.virtualenvs/VBEZ/local/lib/python2.7/site-packages/django/conf/__init__.py", line 80, in _configure_logging
    20:29:04 web.1    |     logging_config_func(self.LOGGING)
    20:29:04 web.1    |   File "/usr/lib/python2.7/logging/config.py", line 777, in dictConfig
    20:29:04 web.1    |     dictConfigClass(config).configure()
    20:29:04 web.1    |   File "/usr/lib/python2.7/logging/config.py", line 575, in configure
    20:29:04 web.1    |     '%r: %s' % (name, e))
    20:29:04 web.1    | ValueError: Unable to configure handler 'mail_admins': Cannot resolve 'vbenergyzone.core.utils.log.StaffSuperuserEmailHandler': cannot import name BaseHandler
    

Here is my logging configuration:

    
    
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': True,
        'filters': {
             'require_debug_false': {
                 '()': 'django.utils.log.RequireDebugFalse'
             }
         },
        'formatters': {
            'verbose': {
                'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
            },
            'simple': {
                'format': '%(levelname)s %(message)s'
            },
        },
        'handlers': {
            'null': {
                'level': 'DEBUG',
                'class': 'django.utils.log.NullHandler',
            },
            'console':{
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'mail_admins': {
                'level': 'ERROR',
                # 'class': 'django.utils.log.AdminEmailHandler',
                'class': 'vbenergyzone.core.utils.log.StaffSuperuserEmailHandler',
                'filters': [],
            }
        },
        'loggers': {
            'django': {
                'handlers': ['null'],
                'propagate': True,
                'level': 'INFO',
            },
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': True,
            },
            'vbenergyzone': {
                'handlers': ['console', 'mail_admins'],
                'level': 'INFO',
            }
        }
    }
    

Here is my custom logger:

    
    
    """
    Logging utilities
    """
    import logging
    import traceback
    
    from django.contrib.sites.models import Site
    
    from django.views.debug import get_exception_reporter_filter
    
    from vbenergyzone.core import send_message
    
    # ==============================================================================
    
    class StaffSuperuserEmailHandler(logging.Handler):
        def emit(self, record):
            try:
                request = record.request
                domain = Site.objects.get_current().domain
    
                subject = 'User %s experienced an error on %s: %s' % \
                    (request.user, domain, record.getMessage())
    
                filter = get_exception_reporter_filter(request)
                request_repr = filter.get_request_repr(request)
            except Exception:
                subject = '%s: %s' % (
                    record.levelname,
                    record.getMessage(),
                )
    
                request = None
                request_repr = "Request repr() unavailable."
    
            if record.exc_info:
                exc_info = record.exc_info
                stack_trace = \
                    '\n'.join(traceback.format_exception(*record.exc_info))
            else:
                exc_info = (None, record.getMessage(), None)
                stack_trace = 'No stack trace available'
    
            context_object = {
                'message':      record.getMessage(),
                'request':      request,
                'request_repr': request_repr,
                'stack_trace':  stack_trace,
            }
    
            send_message(
                context_object=context_object,
                html_template='core/email/staff_super_email_handler.html',
                send_to_staff_and_superusers=True,
                subject=self.format_subject(subject),
                text_template='core/email/staff_super_email_handler.txt',
            )
    
        def format_subject(self, subject):
            """
            Escape CR and LF characters, and limit length.
            RFC 2822's hard limit is 998 characters per line. So, minus "Subject: "
            the actual subject must be no longer than 989 characters.
            """
            formatted_subject = subject.replace('\n', '\\n').replace('\r', '\\r')
            return formatted_subject[:989]
    


Answer: This is a known bug with a patch that will be coming out with Django 1.6.1. In
the meantime, this commit includes the patch:
<https://github.com/django/django/commit/432de546113942be60089a879371073ad09fb4fe>.

Thanks to claudep and bmispelon at the Django project for helping me with
this!

