summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2012-09-24 22:11:42 +0200
committerClaude Paroz <claude@2xlibre.net>2012-09-24 22:12:45 +0200
commitfc69fff9ab5bba8a6cff3eaf51f02a3204b1c015 (patch)
treec8ef89d4346f70b560d952f4aca168135ae6d5bc
parente72e22e518a730cd28cd68c9374fa79a45e27a9c (diff)
Fixed #14861 -- Moved logging config outside of Settings.__init__
Thanks donspaulding for the report and simonpercivall for the initial patch.
-rw-r--r--django/conf/__init__.py30
-rw-r--r--docs/topics/logging.txt30
-rw-r--r--tests/regressiontests/logging_tests/logconfig.py7
-rw-r--r--tests/regressiontests/logging_tests/tests.py29
4 files changed, 52 insertions, 44 deletions
diff --git a/django/conf/__init__.py b/django/conf/__init__.py
index 6272f4ed5d..d636ff0b6c 100644
--- a/django/conf/__init__.py
+++ b/django/conf/__init__.py
@@ -43,13 +43,28 @@ class LazySettings(LazyObject):
% (name, ENVIRONMENT_VARIABLE))
self._wrapped = Settings(settings_module)
-
+ self._configure_logging()
def __getattr__(self, name):
if self._wrapped is empty:
self._setup(name)
return getattr(self._wrapped, name)
+ def _configure_logging(self):
+ """
+ Setup logging from LOGGING_CONFIG and LOGGING settings.
+ """
+ if self.LOGGING_CONFIG:
+ # First find the logging configuration function ...
+ logging_config_path, logging_config_func_name = self.LOGGING_CONFIG.rsplit('.', 1)
+ logging_config_module = importlib.import_module(logging_config_path)
+ logging_config_func = getattr(logging_config_module, logging_config_func_name)
+
+ # Backwards-compatibility shim for #16288 fix
+ compat_patch_logging_config(self.LOGGING)
+
+ # ... then invoke it with the logging settings
+ logging_config_func(self.LOGGING)
def configure(self, default_settings=global_settings, **options):
"""
@@ -133,19 +148,6 @@ class Settings(BaseSettings):
os.environ['TZ'] = self.TIME_ZONE
time.tzset()
- # Settings are configured, so we can set up the logger if required
- if self.LOGGING_CONFIG:
- # First find the logging configuration function ...
- logging_config_path, logging_config_func_name = self.LOGGING_CONFIG.rsplit('.', 1)
- logging_config_module = importlib.import_module(logging_config_path)
- logging_config_func = getattr(logging_config_module, logging_config_func_name)
-
- # Backwards-compatibility shim for #16288 fix
- compat_patch_logging_config(self.LOGGING)
-
- # ... then invoke it with the logging settings
- logging_config_func(self.LOGGING)
-
class UserSettingsHolder(BaseSettings):
"""
diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt
index 94236babd6..a4aae0bc02 100644
--- a/docs/topics/logging.txt
+++ b/docs/topics/logging.txt
@@ -345,36 +345,6 @@ This logging configuration does the following things:
printed to the console; ``ERROR`` and ``CRITICAL``
messages will also be output via email.
-.. admonition:: Custom handlers and circular imports
-
- If your ``settings.py`` specifies a custom handler class and the file
- defining that class also imports ``settings.py`` a circular import will
- occur.
-
- For example, if ``settings.py`` contains the following config for
- :setting:`LOGGING`::
-
- LOGGING = {
- 'version': 1,
- 'handlers': {
- 'custom_handler': {
- 'level': 'INFO',
- 'class': 'myproject.logconfig.MyHandler',
- }
- }
- }
-
- and ``myproject/logconfig.py`` has the following line before the
- ``MyHandler`` definition::
-
- from django.conf import settings
-
- then the ``dictconfig`` module will raise an exception like the following::
-
- ValueError: Unable to configure handler 'custom_handler':
- Unable to configure handler 'custom_handler':
- 'module' object has no attribute 'logconfig'
-
.. _formatter documentation: http://docs.python.org/library/logging.html#formatter-objects
Custom logging configuration
diff --git a/tests/regressiontests/logging_tests/logconfig.py b/tests/regressiontests/logging_tests/logconfig.py
new file mode 100644
index 0000000000..8524aa2c24
--- /dev/null
+++ b/tests/regressiontests/logging_tests/logconfig.py
@@ -0,0 +1,7 @@
+import logging
+
+from django.conf import settings
+
+class MyHandler(logging.Handler):
+ def __init__(self, *args, **kwargs):
+ self.config = settings.LOGGING
diff --git a/tests/regressiontests/logging_tests/tests.py b/tests/regressiontests/logging_tests/tests.py
index f444e0ff46..a54b425f67 100644
--- a/tests/regressiontests/logging_tests/tests.py
+++ b/tests/regressiontests/logging_tests/tests.py
@@ -10,6 +10,8 @@ from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
from django.utils.log import CallbackFilter, RequireDebugFalse
+from ..admin_scripts.tests import AdminScriptTestCase
+
# logging config prior to using filter with mail_admins
OLD_LOGGING = {
@@ -253,3 +255,30 @@ class AdminEmailHandlerTest(TestCase):
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, expected_subject)
+
+
+class SettingsConfigTest(AdminScriptTestCase):
+ """
+ Test that accessing settings in a custom logging handler does not trigger
+ a circular import error.
+ """
+ def setUp(self):
+ log_config = """{
+ 'version': 1,
+ 'handlers': {
+ 'custom_handler': {
+ 'level': 'INFO',
+ 'class': 'logging_tests.logconfig.MyHandler',
+ }
+ }
+}"""
+ self.write_settings('settings.py', sdict={'LOGGING': log_config})
+
+ def tearDown(self):
+ self.remove_settings('settings.py')
+
+ def test_circular_dependency(self):
+ # validate is just an example command to trigger settings configuration
+ out, err = self.run_manage(['validate'])
+ self.assertNoOutput(err)
+ self.assertOutput(out, "0 errors found")