Moved settings handling over to django-appconf and fixed coverage.

This commit is contained in:
Jannis Leidel
2011-08-25 17:51:47 +02:00
parent fc5c2dd7ba
commit c16e6a8df2
25 changed files with 90 additions and 162 deletions

View File

@@ -2,12 +2,13 @@ from __future__ import with_statement
import os
import codecs
from django.conf import settings
from django.core.files.base import ContentFile
from django.template.loader import render_to_string
from django.utils.encoding import smart_unicode
from compressor.cache import get_hexdigest, get_mtime
from compressor.conf import settings
from compressor.exceptions import CompressorError, UncompressableFileError
from compressor.filters import CompilerFilter
from compressor.storage import default_storage

View File

@@ -2,12 +2,12 @@ import os
import socket
import time
from django.conf import settings
from django.core.cache import get_cache
from django.utils.encoding import smart_str
from django.utils.hashcompat import md5_constructor
from django.utils.importlib import import_module
from compressor.conf import settings
from compressor.utils import get_mod_func

View File

@@ -1,4 +1,5 @@
from compressor.conf import settings
from django.conf import settings
from compressor.base import Compressor, SOURCE_HUNK, SOURCE_FILE
from compressor.exceptions import UncompressableFileError

View File

@@ -3,11 +3,11 @@ import os
import logging
import subprocess
import tempfile
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files.temp import NamedTemporaryFile
from django.utils.importlib import import_module
from compressor.conf import settings
from compressor.exceptions import FilterError
from compressor.utils import get_mod_func
from compressor.utils.stringformat import FormattableString as fstr

View File

@@ -1,4 +1,5 @@
from compressor.conf import settings
from django.conf import settings
from compressor.filters import CompilerFilter

View File

@@ -2,8 +2,9 @@ import os
import re
import posixpath
from django.conf import settings
from compressor.cache import get_hexdigest, get_hashed_mtime
from compressor.conf import settings
from compressor.filters import FilterBase
from compressor.utils import staticfiles

View File

@@ -1,4 +1,5 @@
from compressor.conf import settings
from django.conf import settings
from compressor.filters import CompilerFilter

View File

@@ -3,7 +3,8 @@ import re
import mimetypes
from base64 import b64encode
from compressor.conf import settings
from django.conf import settings
from compressor.filters import FilterBase

View File

@@ -1,4 +1,5 @@
from compressor.conf import settings
from django.conf import settings
from compressor.filters import CompilerFilter

View File

@@ -1,4 +1,5 @@
from compressor.conf import settings
from django.conf import settings
from compressor.base import Compressor, SOURCE_HUNK, SOURCE_FILE
from compressor.exceptions import UncompressableFileError

View File

@@ -9,6 +9,7 @@ try:
except ImportError:
from StringIO import StringIO
from django.conf import settings
from django.core.management.base import NoArgsCommand, CommandError
from django.template import Context, Template, TemplateDoesNotExist, TemplateSyntaxError
from django.utils.datastructures import SortedDict
@@ -22,7 +23,6 @@ except ImportError:
CachedLoader = None
from compressor.cache import cache, get_offline_cachekey
from compressor.conf import settings
from compressor.exceptions import OfflineGenerationError
from compressor.templatetags.compress import CompressorNode
from compressor.utils import walk, any

View File

@@ -2,10 +2,10 @@ import fnmatch
import os
from optparse import make_option
from django.conf import settings
from django.core.management.base import NoArgsCommand, CommandError
from compressor.cache import cache, get_mtime, get_mtime_cachekey
from compressor.conf import settings
from compressor.utils import walk

View File

@@ -1,11 +1,12 @@
import os
from django import VERSION as DJANGO_VERSION
from django.conf import settings as global_settings
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from compressor.utils.settings import AppSettings
from appconf import AppConf
class CompressorSettings(AppSettings):
class CompressorConf(AppConf):
# Main switch
ENABLED = False
# Allows changing verbosity from the settings.
@@ -60,14 +61,17 @@ class CompressorSettings(AppSettings):
# The context to be used when compressing the files "offline"
OFFLINE_CONTEXT = {}
class Meta:
prefix = 'compress'
def configure_enabled(self, value):
return value or not global_settings.DEBUG
return value or not settings.DEBUG
def configure_root(self, value):
if value is None:
value = getattr(global_settings, 'STATIC_ROOT', None)
value = getattr(settings, 'STATIC_ROOT', None)
if not value:
value = global_settings.MEDIA_ROOT
value = settings.MEDIA_ROOT
if not value:
raise ImproperlyConfigured(
"The COMPRESS_ROOT setting must be set.")
@@ -76,9 +80,9 @@ class CompressorSettings(AppSettings):
def configure_url(self, value):
# Uses Django 1.3's STATIC_URL by default or falls back to MEDIA_URL
if value is None:
value = getattr(global_settings, "STATIC_URL", None)
value = getattr(settings, "STATIC_URL", None)
if not value:
value = global_settings.MEDIA_URL
value = settings.MEDIA_URL
if not value.endswith("/"):
raise ImproperlyConfigured("The URL settings (e.g. COMPRESS_URL) "
"must have a trailing slash.")
@@ -87,11 +91,11 @@ class CompressorSettings(AppSettings):
def configure_cache_backend(self, value):
if value is None:
# If we are on Django 1.3 AND using the new CACHES setting...
if DJANGO_VERSION[:2] >= (1, 3) and hasattr(global_settings, "CACHES"):
if DJANGO_VERSION[:2] >= (1, 3) and hasattr(settings, "CACHES"):
value = "default"
else:
# falling back to the old CACHE_BACKEND setting
value = getattr(global_settings, "CACHE_BACKEND", None)
value = getattr(settings, "CACHE_BACKEND", None)
if not value:
raise ImproperlyConfigured(
"Please specify a cache backend in your settings.")
@@ -100,11 +104,11 @@ class CompressorSettings(AppSettings):
def configure_offline_context(self, value):
if not value:
value = {
"MEDIA_URL": global_settings.MEDIA_URL,
"MEDIA_URL": settings.MEDIA_URL,
}
# Adds the 1.3 STATIC_URL setting to the context if available
if getattr(global_settings, "STATIC_URL", None):
value["STATIC_URL"] = global_settings.STATIC_URL
if getattr(settings, "STATIC_URL", None):
value["STATIC_URL"] = settings.STATIC_URL
return value
def configure_precompilers(self, value):
@@ -112,5 +116,3 @@ class CompressorSettings(AppSettings):
raise ImproperlyConfigured("The COMPRESS_PRECOMPILERS setting "
"must be a list or tuple. Check for missing commas.")
return value
settings = CompressorSettings(prefix="COMPRESS")

View File

@@ -2,11 +2,10 @@ import gzip
from os import path
from datetime import datetime
from django.conf import settings
from django.core.files.storage import FileSystemStorage, get_storage_class
from django.utils.functional import LazyObject
from compressor.conf import settings
class CompressorFileStorage(FileSystemStorage):
"""

View File

@@ -1,9 +1,9 @@
from django import template
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from compressor.cache import (cache, cache_get, cache_set,
get_offline_cachekey, get_templatetag_cachekey)
from compressor.conf import settings
from compressor.utils import get_class
register = template.Library()

View File

@@ -1,107 +0,0 @@
from inspect import getmembers
from django.conf import settings
class AppSettings(object):
"""
An app setting object to be used for handling app setting defaults
gracefully and providing a nice API for them. Say you have an app
called ``myapp`` and want to define a few defaults, and refer to the
defaults easily in the apps code. Add a ``settings.py`` to your app::
from path.to.utils import AppSettings
class MyAppSettings(AppSettings):
SETTING_1 = "one"
SETTING_2 = (
"two",
)
Then initialize the setting with the correct prefix in the location of
of your choice, e.g. ``conf.py`` of the app module::
settings = MyAppSettings(prefix="MYAPP")
The ``MyAppSettings`` instance will automatically look at Django's
global setting to determine each of the settings and respect the
provided ``prefix``. E.g. adding this to your site's ``settings.py``
will set the ``SETTING_1`` setting accordingly::
MYAPP_SETTING_1 = "uno"
Usage
-----
Instead of using ``from django.conf import settings`` as you would
usually do, you can switch to using your apps own settings module
to access the app settings::
from myapp.conf import settings
print myapp_settings.MYAPP_SETTING_1
``AppSettings`` instances also work as pass-throughs for other
global settings that aren't related to the app. For example the
following code is perfectly valid::
from myapp.conf import settings
if "myapp" in settings.INSTALLED_APPS:
print "yay, myapp is installed!"
Custom handling
---------------
Each of the settings can be individually configured with callbacks.
For example, in case a value of a setting depends on other settings
or other dependencies. The following example sets one setting to a
different value depending on a global setting::
from django.conf import settings
class MyCustomAppSettings(AppSettings):
ENABLED = True
def configure_enabled(self, value):
return value and not self.DEBUG
custom_settings = MyCustomAppSettings("MYAPP")
The value of ``custom_settings.MYAPP_ENABLED`` will vary depending on the
value of the global ``DEBUG`` setting.
Each of the app settings can be customized by providing
a method ``configure_<lower_setting_name>`` that takes the default
value as defined in the class attributes as the only parameter.
The method needs to return the value to be use for the setting in
question.
"""
def __dir__(self):
return sorted(list(set(self.__dict__.keys() + dir(settings))))
__members__ = lambda self: self.__dir__()
def __getattr__(self, name):
if name.startswith(self._prefix):
raise AttributeError("%r object has no attribute %r" %
(self.__class__.__name__, name))
return getattr(settings, name)
def __setattr__(self, name, value):
super(AppSettings, self).__setattr__(name, value)
if name in dir(settings):
setattr(settings, name, value)
def __init__(self, prefix):
super(AppSettings, self).__setattr__('_prefix', prefix)
for name, value in filter(self.issetting, getmembers(self.__class__)):
prefixed_name = "%s_%s" % (prefix.upper(), name.upper())
value = getattr(settings, prefixed_name, value)
callback = getattr(self, "configure_%s" % name.lower(), None)
if callable(callback):
value = callback(value)
delattr(self.__class__, name)
setattr(self, prefixed_name, value)
def issetting(self, (name, value)):
return name == name.upper()

View File

@@ -121,4 +121,7 @@ setup(
'Topic :: Internet :: WWW/HTTP',
],
zip_safe = False,
install_requires=[
'django-appconf >= 0.4',
],
)

24
tests/settings.py Normal file
View File

@@ -0,0 +1,24 @@
import os
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
COMPRESS_CACHE_BACKEND = 'locmem://'
DATABASE_ENGINE = 'sqlite3'
INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.sites',
'django.contrib.auth',
'django.contrib.admin',
'compressor',
'tests',
]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(TEST_DIR, 'media')
TEMPLATE_DIRS = (
os.path.join(TEST_DIR, 'templates'),
)

View File

@@ -4,12 +4,11 @@ import re
from BeautifulSoup import BeautifulSoup
from django.conf import settings
from django.core.cache.backends import locmem
from django.test import TestCase
from compressor.base import SOURCE_HUNK, SOURCE_FILE
from compressor.cache import get_hexdigest
from compressor.conf import settings
from compressor.css import CssCompressor
from compressor.js import JsCompressor
@@ -22,6 +21,7 @@ def css_tag(href, **kwargs):
test_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
class CompressorTestCase(TestCase):
def setUp(self):
@@ -81,7 +81,7 @@ class CompressorTestCase(TestCase):
def test_js_split(self):
out = [
(SOURCE_FILE, os.path.join(settings.COMPRESS_ROOT, u'js/one.js'), u'js/one.js', '<script src="/media/js/one.js" type="text/javascript"></script>'),
(SOURCE_HUNK, u'obj.value = "value";', None, '<script type="text/javascript">obj.value = "value";</script>')
(SOURCE_HUNK, u'obj.value = "value";', None, '<script type="text/javascript">obj.value = "value";</script>'),
]
split = self.js_node.split_contents()
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3])) for x in split]
@@ -127,7 +127,6 @@ class CompressorTestCase(TestCase):
settings.COMPRESS_OUTPUT_DIR = old_output_dir
class CssMediaTestCase(TestCase):
def setUp(self):
self.css = """\
@@ -151,8 +150,6 @@ class CssMediaTestCase(TestCase):
self.assertEqual(media, [l.get('media', None) for l in links])
class VerboseTestCase(CompressorTestCase):
def setUp(self):
@@ -165,5 +162,3 @@ class CacheBackendTestCase(CompressorTestCase):
def test_correct_backend(self):
from compressor.cache import cache
self.assertEqual(cache.__class__, locmem.CacheClass)

View File

@@ -3,10 +3,10 @@ import os
import sys
from unittest2 import skipIf
from django.conf import settings
from django.test import TestCase
from compressor.cache import get_hashed_mtime
from compressor.conf import settings
from compressor.css import CssCompressor
from compressor.utils import find_command
from compressor.filters.base import CompilerFilter

View File

@@ -1,10 +1,10 @@
from __future__ import with_statement
import os
from django.conf import settings
from django.template import Template, Context
from django.test import TestCase
from compressor.conf import settings
from compressor.management.commands.compress import Command as CompressCommand
from .base import test_dir, css_tag

View File

@@ -2,8 +2,6 @@ from __future__ import with_statement
import os
from unittest2 import skipIf
from BeautifulSoup import BeautifulSoup
try:
import lxml
except ImportError:
@@ -20,7 +18,8 @@ except ImportError:
BeautifulSoup = None
from compressor.conf import settings
from django.conf import settings
from compressor.base import SOURCE_HUNK, SOURCE_FILE
from .base import CompressorTestCase

View File

@@ -1,10 +1,10 @@
from __future__ import with_statement
from django.conf import settings
from django.core.files.storage import get_storage_class
from django.test import TestCase
from compressor import base
from compressor.conf import settings
from .base import css_tag
from .templatetags import render

View File

@@ -1,10 +1,9 @@
from __future__ import with_statement
from django.conf import settings
from django.template import Template, Context, TemplateSyntaxError
from django.test import TestCase
from compressor.conf import settings
from .base import css_tag

View File

@@ -1,12 +1,18 @@
[tox]
setupdir = ..
distribute = false
downloadcache = {toxinidir}/_download/
[testenv]
commands =
{envpython} {toxinidir}/runtests.py []
coverage html -d {envtmpdir}/coverage
{envbindir}/coverage erase
{envbindir}/coverage run --branch --include=*compressor* --omit=*test*,*rjsmin*,*cssmin*,*stringformat*,*models* {envbindir}/django-admin.py test {posargs:tests} --settings=tests.settings
{envbindir}/coverage report
{envbindir}/coverage html -d {envtmpdir}
echo "Type the following to open the coverage report: python -m webbrowser -t file://{envtmpdir}/index.html"
setenv =
PYTHONPATH = {toxinidir}/..
downloadcache = {toxworkdir}/_download/
[testenv:docs]
changedir = ../docs
@@ -20,7 +26,7 @@ commands =
basepython = python2.5
deps =
unittest2
BeautifulSoup
BeautifulSoup==3.2.0
html5lib
coverage
django==1.2.5
@@ -29,7 +35,7 @@ deps =
basepython = python2.6
deps =
unittest2
BeautifulSoup
BeautifulSoup==3.2.0
html5lib
coverage
django==1.2.5
@@ -38,7 +44,7 @@ deps =
basepython = python2.7
deps =
unittest2
BeautifulSoup
BeautifulSoup==3.2.0
html5lib
coverage
django==1.2.5
@@ -48,7 +54,7 @@ deps =
basepython = python2.5
deps =
unittest2
BeautifulSoup
BeautifulSoup==3.2.0
html5lib
coverage
django==1.3
@@ -57,7 +63,7 @@ deps =
basepython = python2.6
deps =
unittest2
BeautifulSoup
BeautifulSoup==3.2.0
html5lib
coverage
django==1.3
@@ -66,7 +72,7 @@ deps =
basepython = python2.7
deps =
unittest2
BeautifulSoup
BeautifulSoup==3.2.0
html5lib
coverage
django==1.3