Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/1.1.1'

  • Loading branch information...
commit bdaa116d39e9494d761178737bf59540ffb97e89 2 parents a79ebad + 0bb5a93
@jezdez jezdez authored
View
3  .gitignore
@@ -1,6 +1,5 @@
*.pyc
*.pyo
-*~
*.swp
*.orig
*.kpf
@@ -20,6 +19,6 @@ downloads/*
bin/*
develop-eggs/*.egg-link
docs/_build
-tests/project/site_media/*
+tests/project/site_media/static/*
.tox/
*.egg
View
3  AUTHORS
@@ -4,4 +4,5 @@ Brian Beck <exogen@gmail.com>
Brian Rosner <brosner@gmail.com>
Chris Beaven <smileychris@gmail.com>
Carl Meyer <carl@dirtcircle.com>
-Luke Lee <durdenmisc@gmail.com>
+Luke Lee <durdenmisc@gmail.com>
+Sébastien Fievet <zyegfryed@gmail.com>
View
13 setup.py
@@ -97,11 +97,9 @@ def find_package_data(
return out
-VERSION = __import__("staticfiles").__version__
-
setup(
name="django-staticfiles",
- version=VERSION,
+ version=":versiontools:staticfiles:",
description="A Django app that provides helpers for serving static files.",
long_description=read("README.rst"),
author="Jannis Leidel",
@@ -117,7 +115,16 @@ def find_package_data(
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
"Framework :: Django",
],
zip_safe=False,
+ install_requires=[
+ 'django-appconf >= 0.2.2',
+ ],
+ setup_requires=[
+ 'versiontools >= 1.6',
+ ],
)
View
18 staticfiles/__init__.py
@@ -1,16 +1,2 @@
-VERSION = (1, 1, 0, "f", 0) # following PEP 386
-DEV_N = None
-
-
-def get_version():
- version = "%s.%s" % (VERSION[0], VERSION[1])
- if VERSION[2]:
- version = "%s.%s" % (version, VERSION[2])
- if VERSION[3] != "f":
- version = "%s%s%s" % (version, VERSION[3], VERSION[4])
- if DEV_N:
- version = "%s.dev%s" % (version, DEV_N)
- return version
-
-
-__version__ = get_version()
+# following PEP 386, versiontools will pick it up
+__version__ = (1, 1, 1, "final", 0)
View
57 staticfiles/models.py
@@ -1,5 +1,58 @@
-# Initialize the settings.
-from staticfiles import settings
+"""
+Initializes the settings
+"""
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+
+from appconf import AppConf
+
+
+class StaticFilesConf(AppConf):
+ # The directory in which the static files are collected in
+ ROOT = ''
+ # The URL path to STATIC_ROOT
+ URL = None
+ # A tuple of two-tuples with a name and the path of additional directories
+ # which hold static files and should be taken into account
+ DIRS = ()
+ # Apps that shouldn't be taken into account when collecting app media
+ EXCLUDED_APPS = ()
+ # Destination storage
+ STORAGE = 'staticfiles.storage.StaticFilesStorage'
+ # List of finder classes that know how to find static files in
+ # various locations.
+ FINDERS = (
+ 'staticfiles.finders.FileSystemFinder',
+ 'staticfiles.finders.AppDirectoriesFinder',
+ # 'staticfiles.finders.DefaultStorageFinder',
+ )
+
+ def configure_root(self, value):
+ """
+ Use STATIC_ROOT since it doesn't has the default prefix
+ """
+ root = value or getattr(settings, 'STATIC_ROOT', None)
+ if (self.MEDIA_ROOT and root) and (self.MEDIA_ROOT == root):
+ raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
+ "settings must have different values")
+ self.STATIC_ROOT = root
+ return root
+
+ def configure_url(self, value):
+ """
+ Use STATIC_URL since it doesn't has the default prefix
+ """
+ url = value or getattr(settings, 'STATIC_URL', None)
+ if not url:
+ raise ImproperlyConfigured("You're using the staticfiles app "
+ "without having set the required "
+ "STATIC_URL setting.")
+ if url == self.MEDIA_URL:
+ raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
+ "settings must have different values")
+ self.STATIC_URL = url
+ return url
+
# Okay, this is ugly, but I don't see another way except adding a registry
# pattern thingie to Django which seems like overengineering. Meh.
View
51 staticfiles/settings.py
@@ -1,51 +0,0 @@
-from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
-
-from staticfiles.utils import AppSettings
-
-
-class StaticfilesSettings(AppSettings):
- # The directory in which the static files are collected in
- ROOT = ''
- # The URL path to STATIC_ROOT
- URL = None
- # A tuple of two-tuples with a name and the path of additional directories
- # which hold static files and should be taken into account
- DIRS = ()
- # Apps that shouldn't be taken into account when collecting app media
- EXCLUDED_APPS = ()
- # Destination storage
- STORAGE = 'staticfiles.storage.StaticFilesStorage'
- # List of finder classes that know how to find static files in
- # various locations.
- FINDERS = (
- 'staticfiles.finders.FileSystemFinder',
- 'staticfiles.finders.AppDirectoriesFinder',
- # 'staticfiles.finders.DefaultStorageFinder',
- )
-
- def configure_root(self, value):
- """
- Use STATIC_ROOT since it doesn't has the default prefix
- """
- root = value or getattr(settings, 'STATIC_ROOT', None)
- if (self.MEDIA_ROOT and root) and (self.MEDIA_ROOT == root):
- raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
- "settings must have different values")
- self.STATIC_ROOT = root
- return root
-
- def configure_url(self, value):
- """
- Use STATIC_URL since it doesn't has the default prefix
- """
- url = value or getattr(settings, 'STATIC_URL', None)
- if not url:
- raise ImproperlyConfigured("You're using the staticfiles app "
- "without having set the required "
- "STATIC_URL setting.")
- if url == self.MEDIA_URL:
- raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
- "settings must have different values")
- self.STATIC_URL = url
- return url
View
27 staticfiles/storage.py
@@ -97,8 +97,8 @@ def __init__(self, *args, **kwargs):
def hashed_name(self, name, content=None):
if content is None:
if not self.exists(name):
- raise ValueError("The file '%s' could not be found with %r." %
- (name, self))
+ raise ValueError(
+ "The file '%s' could not be found with %r." % (name, self))
try:
content = self.open(name)
except IOError:
@@ -144,13 +144,22 @@ def converter(matchobj):
return matched
name_parts = name.split('/')
# Using posix normpath here to remove duplicates
- result = url_parts = posixpath.normpath(url).split('/')
- level = url.count('..')
- if level:
- result = name_parts[:-level - 1] + url_parts[level:]
- elif name_parts[:-1]:
- result = name_parts[:-1] + url_parts[-1:]
- joined_result = '/'.join(result)
+ url = posixpath.normpath(url)
+ url_parts = url.split('/')
+ parent_level, sub_level = url.count('..'), url.count('/')
+ if url.startswith('/'):
+ sub_level -= 1
+ url_parts = url_parts[1:]
+ if parent_level or not url.startswith('/'):
+ start, end = parent_level + 1, parent_level
+ else:
+ if sub_level:
+ if sub_level == 1:
+ parent_level -= 1
+ start, end = parent_level, sub_level - 1
+ else:
+ start, end = 1, sub_level - 1
+ joined_result = '/'.join(name_parts[:-start] + url_parts[end:])
hashed_url = self.url(joined_result, force=True)
# Return the hashed and normalized version to the file
return 'url("%s")' % hashed_url
View
169 staticfiles/utils.py
@@ -1,10 +1,7 @@
import os
-import sys
import fnmatch
import warnings
-from django.conf import settings
-
def get_files_for_app(app, ignore_patterns=None):
"""
@@ -65,169 +62,3 @@ def get_files(storage, ignore_patterns=None, location=''):
for fn in get_files(storage, ignore_patterns, dir):
yield fn
-
-class AppSettingsOptions(object):
-
- def __init__(self, meta, *args, **kwargs):
- self.configured = False
-
- def prefixed_name(self, name):
- if name.startswith(self.app_label):
- return name
- return "%s_%s" % (self.app_label.upper(), name.upper())
-
-
-class AppSettingsMetaClass(type):
- options_class = AppSettingsOptions
-
- def __new__(cls, name, bases, attrs):
- super_new = super(AppSettingsMetaClass, cls).__new__
- parents = [b for b in bases if isinstance(b, AppSettingsMetaClass)]
- if not parents:
- return super_new(cls, name, bases, attrs)
-
- try:
- meta = attrs.pop('Meta')
- except KeyError:
- meta = None
-
- attrs['_meta'] = cls.options_class(meta)
- new_class = super_new(cls, name, bases, attrs)
-
- if getattr(new_class._meta, 'app_label', None) is None:
- # Figure out the app_label by looking one level up.
- # For 'django.contrib.sites.models', this would be 'sites'.
- model_module = sys.modules[new_class.__module__]
- new_class._meta.app_label = model_module.__name__.split('.')[-2]
-
- names = []
- defaults = []
- for name in filter(lambda name: name == name.upper(), attrs):
- prefixed_name = new_class._meta.prefixed_name(name)
- names.append((name, prefixed_name))
- defaults.append((prefixed_name, attrs.pop(name)))
-
- new_class.defaults = dict(defaults)
- new_class.names = dict(names)
- new_class._configure()
-
- def _configure(cls):
- if not cls._meta.configured:
- # the ad-hoc settings class instance used to configure each value
- obj = cls()
- for name, prefixed_name in obj.names.items():
- default_value = obj.defaults.get(prefixed_name)
- value = getattr(settings, prefixed_name, default_value)
- callback = getattr(obj, "configure_%s" % name.lower(), None)
- if callable(callback):
- value = callback(value)
- # Finally, set the setting in the global setting object
- setattr(settings, prefixed_name, value)
- cls._meta.configured = True
-
-
-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's
- models.py::
-
- from path.to.utils import AppSettings
-
- class MyAppSettings(AppSettings):
- SETTING_1 = "one"
- SETTING_2 = (
- "two",
- )
-
- class Meta:
- app_label = 'myapp'
-
- The settings are initialized with the app label of where the setting is
- located at. E.g. if your ``models.py`` is in the ``myapp`` package,
- the prefix of the settings will be ``MYAPP``.
-
- The ``MyAppSettings`` class will automatically look at Django's
- global setting to determine each of the settings. E.g. adding this to
- your site's ``settings.py`` will set the ``SETTING_1`` app setting
- accordingly::
-
- MYAPP_SETTING_1 = "uno"
-
- Usage
- -----
-
- Instead of using ``from django.conf import settings`` as you would
- usually do, you can **optionally** switch to using your apps own
- settings module to access the settings::
-
- from myapp.models import MyAppSettings
-
- myapp_settings = MyAppSettings()
-
- print myapp_settings.MYAPP_SETTING_1
-
- ``AppSettings`` class automatically work as proxies for the other
- settings, which aren't related to the app. For example the following
- code is perfectly valid::
-
- from myapp.models import MyAppSettings
-
- settings = MyAppSettings()
-
- if "myapp" in settings.INSTALLED_APPS:
- print "yay, myapp is installed!"
-
- In case you want to set some settings ad-hoc, you can simply pass
- the value when instanciating the ``AppSettings`` class::
-
- from myapp.models import MyAppSettings
-
- settings = MyAppSettings(SETTING_1='something completely different')
-
- if 'different' in settings.MYAPP_SETTINGS_1:
- print 'yay, I'm different!'
-
- 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
-
- The value of ``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.
- """
- __metaclass__ = AppSettingsMetaClass
-
- def __init__(self, **kwargs):
- for name, value in kwargs.iteritems():
- setattr(self, self._meta.prefixed_name(name), value)
-
- def __dir__(self):
- return sorted(list(set(dir(settings))))
-
- __members__ = lambda self: self.__dir__()
-
- def __getattr__(self, name):
- return getattr(settings, name)
-
- def __setattr__(self, name, value):
- setattr(settings, name, value)
View
BIN  tests/project/documents/cached/css/img/window.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
3  tests/project/documents/cached/css/window.css
@@ -0,0 +1,3 @@
+body {
+ background: #d3d6d8 url("img/window.png");
+}
View
BIN  tests/project/documents/cached/img/relative.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
5 tests/project/documents/cached/relative.css
@@ -1,2 +1,5 @@
@import url("../cached/styles.css");
-@import url("absolute.css");
+@import url("absolute.css");
+body {
+ background: #d3d6d8 url(img/relative.png);
+}
View
2  tests/project/documents/cached/styles.css
@@ -1 +1 @@
-@import url("cached/other.css");
+@import url("other.css");
View
1  tests/project/documents/test/backup~
@@ -0,0 +1 @@
+should be ignored
View
0  tests/project/site_media/media/media-file.txt
No changes.
View
26 tests/tests.py
@@ -352,11 +352,11 @@ def test_template_tag_return(self):
""", "/static/test/file.dad0999e4f8f.txt")
self.assertTemplateRenders("""
{% load staticfiles %}{% static "cached/styles.css" %}
- """, "/static/cached/styles.5653c259030b.css")
+ """, "/static/cached/styles.93b1147e8552.css")
def test_template_tag_simple_content(self):
relpath = self.cached_file_path("cached/styles.css")
- self.assertEqual(relpath, "cached/styles.5653c259030b.css")
+ self.assertEqual(relpath, "cached/styles.93b1147e8552.css")
relfile = storage.staticfiles_storage.open(relpath)
try:
content = relfile.read()
@@ -372,7 +372,7 @@ def test_template_tag_absolute(self):
try:
content = relfile.read()
self.assertFalse(u("/static/cached/styles.css") in content)
- self.assertTrue(u("/static/cached/styles.5653c259030b.css") in content)
+ self.assertTrue(u("/static/cached/styles.93b1147e8552.css") in content)
finally:
relfile.close()
@@ -383,19 +383,33 @@ def test_template_tag_denorm(self):
try:
content = relfile.read()
self.assertFalse(u("..//cached///styles.css") in content)
- self.assertTrue(u("/static/cached/styles.5653c259030b.css") in content)
+ self.assertTrue(u("/static/cached/styles.93b1147e8552.css") in content)
finally:
relfile.close()
def test_template_tag_relative(self):
relpath = self.cached_file_path("cached/relative.css")
- self.assertEqual(relpath, "cached/relative.298ff891a8d4.css")
+ self.assertEqual(relpath, "cached/relative.8dffb45d91f5.css")
relfile = storage.staticfiles_storage.open(relpath)
try:
content = relfile.read()
+ self.assertTrue(u("/static/cached/styles.93b1147e8552.css") in content)
self.assertFalse(u("../cached/styles.css") in content)
self.assertFalse(u('@import "styles.css"') in content)
- self.assertTrue(u("/static/cached/styles.5653c259030b.css") in content)
+ self.assertFalse(u('url(img/relative.png)') in content)
+ self.assertTrue(u('url("/static/cached/img/relative.acae32e4532b.png")') in content)
+ self.assertTrue(u("/static/cached/styles.93b1147e8552.css") in content)
+ finally:
+ relfile.close()
+
+ def test_template_tag_deep_relative(self):
+ relpath = self.cached_file_path("cached/css/window.css")
+ self.assertEqual(relpath, "cached/css/window.9db38d5169f3.css")
+ relfile = storage.staticfiles_storage.open(relpath)
+ try:
+ content = relfile.read()
+ self.assertFalse(u('url(img/window.png)') in content)
+ self.assertTrue(u('url("/static/cached/css/img/window.acae32e4532b.png")') in content)
finally:
relfile.close()
View
2  tests/tox.ini
@@ -1,6 +1,5 @@
[tox]
setupdir = ..
-downloadcache = {toxinidir}/_download/
distribute = False
envlist =
py25-1.2.X, py26-1.2.X, py27-1.2.X,
@@ -8,6 +7,7 @@ envlist =
py25-1.4.X, py26-1.4.X, py27-1.4.X,
[testenv]
+downloadcache = {toxworkdir}/_download/
commands =
{envbindir}/django-admin.py test {posargs:tests} --settings=tests.settings
setenv =
Please sign in to comment.
Something went wrong with that request. Please try again.