PageRenderTime 58ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/staticfiles/finders.py

https://code.google.com/p/mango-py/
Python | 264 lines | 231 code | 7 blank | 26 comment | 4 complexity | 935a225e08059584eb1d048cbd5a1420 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. import os
  2. from django.conf import settings
  3. from django.core.exceptions import ImproperlyConfigured
  4. from django.core.files.storage import default_storage, Storage, FileSystemStorage
  5. from django.utils.datastructures import SortedDict
  6. from django.utils.functional import memoize, LazyObject
  7. from django.utils.importlib import import_module
  8. from django.utils._os import safe_join
  9. from django.contrib.staticfiles import utils
  10. from django.contrib.staticfiles.storage import AppStaticStorage
  11. _finders = SortedDict()
  12. class BaseFinder(object):
  13. """
  14. A base file finder to be used for custom staticfiles finder classes.
  15. """
  16. def find(self, path, all=False):
  17. """
  18. Given a relative file path this ought to find an
  19. absolute file path.
  20. If the ``all`` parameter is ``False`` (default) only
  21. the first found file path will be returned; if set
  22. to ``True`` a list of all found files paths is returned.
  23. """
  24. raise NotImplementedError()
  25. def list(self, ignore_patterns=[]):
  26. """
  27. Given an optional list of paths to ignore, this should return
  28. a two item iterable consisting of the relative path and storage
  29. instance.
  30. """
  31. raise NotImplementedError()
  32. class FileSystemFinder(BaseFinder):
  33. """
  34. A static files finder that uses the ``STATICFILES_DIRS`` setting
  35. to locate files.
  36. """
  37. def __init__(self, apps=None, *args, **kwargs):
  38. # List of locations with static files
  39. self.locations = []
  40. # Maps dir paths to an appropriate storage instance
  41. self.storages = SortedDict()
  42. if not isinstance(settings.STATICFILES_DIRS, (list, tuple)):
  43. raise ImproperlyConfigured(
  44. "Your STATICFILES_DIRS setting is not a tuple or list; "
  45. "perhaps you forgot a trailing comma?")
  46. for root in settings.STATICFILES_DIRS:
  47. if isinstance(root, (list, tuple)):
  48. prefix, root = root
  49. else:
  50. prefix = ''
  51. if os.path.abspath(settings.STATIC_ROOT) == os.path.abspath(root):
  52. raise ImproperlyConfigured(
  53. "The STATICFILES_DIRS setting should "
  54. "not contain the STATIC_ROOT setting")
  55. if (prefix, root) not in self.locations:
  56. self.locations.append((prefix, root))
  57. for prefix, root in self.locations:
  58. filesystem_storage = FileSystemStorage(location=root)
  59. filesystem_storage.prefix = prefix
  60. self.storages[root] = filesystem_storage
  61. super(FileSystemFinder, self).__init__(*args, **kwargs)
  62. def find(self, path, all=False):
  63. """
  64. Looks for files in the extra locations
  65. as defined in ``STATICFILES_DIRS``.
  66. """
  67. matches = []
  68. for prefix, root in self.locations:
  69. matched_path = self.find_location(root, path, prefix)
  70. if matched_path:
  71. if not all:
  72. return matched_path
  73. matches.append(matched_path)
  74. return matches
  75. def find_location(self, root, path, prefix=None):
  76. """
  77. Finds a requested static file in a location, returning the found
  78. absolute path (or ``None`` if no match).
  79. """
  80. if prefix:
  81. prefix = '%s%s' % (prefix, os.sep)
  82. if not path.startswith(prefix):
  83. return None
  84. path = path[len(prefix):]
  85. path = safe_join(root, path)
  86. if os.path.exists(path):
  87. return path
  88. def list(self, ignore_patterns):
  89. """
  90. List all files in all locations.
  91. """
  92. for prefix, root in self.locations:
  93. storage = self.storages[root]
  94. for path in utils.get_files(storage, ignore_patterns):
  95. yield path, storage
  96. class AppDirectoriesFinder(BaseFinder):
  97. """
  98. A static files finder that looks in the directory of each app as
  99. specified in the source_dir attribute of the given storage class.
  100. """
  101. storage_class = AppStaticStorage
  102. def __init__(self, apps=None, *args, **kwargs):
  103. # The list of apps that are handled
  104. self.apps = []
  105. # Mapping of app module paths to storage instances
  106. self.storages = SortedDict()
  107. if apps is None:
  108. apps = settings.INSTALLED_APPS
  109. for app in apps:
  110. app_storage = self.storage_class(app)
  111. if os.path.isdir(app_storage.location):
  112. self.storages[app] = app_storage
  113. if app not in self.apps:
  114. self.apps.append(app)
  115. super(AppDirectoriesFinder, self).__init__(*args, **kwargs)
  116. def list(self, ignore_patterns):
  117. """
  118. List all files in all app storages.
  119. """
  120. for storage in self.storages.itervalues():
  121. if storage.exists(''): # check if storage location exists
  122. for path in utils.get_files(storage, ignore_patterns):
  123. yield path, storage
  124. def find(self, path, all=False):
  125. """
  126. Looks for files in the app directories.
  127. """
  128. matches = []
  129. for app in self.apps:
  130. match = self.find_in_app(app, path)
  131. if match:
  132. if not all:
  133. return match
  134. matches.append(match)
  135. return matches
  136. def find_in_app(self, app, path):
  137. """
  138. Find a requested static file in an app's static locations.
  139. """
  140. storage = self.storages.get(app, None)
  141. if storage:
  142. if storage.prefix:
  143. prefix = '%s%s' % (storage.prefix, os.sep)
  144. if not path.startswith(prefix):
  145. return None
  146. path = path[len(prefix):]
  147. # only try to find a file if the source dir actually exists
  148. if storage.exists(path):
  149. matched_path = storage.path(path)
  150. if matched_path:
  151. return matched_path
  152. class BaseStorageFinder(BaseFinder):
  153. """
  154. A base static files finder to be used to extended
  155. with an own storage class.
  156. """
  157. storage = None
  158. def __init__(self, storage=None, *args, **kwargs):
  159. if storage is not None:
  160. self.storage = storage
  161. if self.storage is None:
  162. raise ImproperlyConfigured("The staticfiles storage finder %r "
  163. "doesn't have a storage class "
  164. "assigned." % self.__class__)
  165. # Make sure we have an storage instance here.
  166. if not isinstance(self.storage, (Storage, LazyObject)):
  167. self.storage = self.storage()
  168. super(BaseStorageFinder, self).__init__(*args, **kwargs)
  169. def find(self, path, all=False):
  170. """
  171. Looks for files in the default file storage, if it's local.
  172. """
  173. try:
  174. self.storage.path('')
  175. except NotImplementedError:
  176. pass
  177. else:
  178. if self.storage.exists(path):
  179. match = self.storage.path(path)
  180. if all:
  181. match = [match]
  182. return match
  183. return []
  184. def list(self, ignore_patterns):
  185. """
  186. List all files of the storage.
  187. """
  188. for path in utils.get_files(self.storage, ignore_patterns):
  189. yield path, self.storage
  190. class DefaultStorageFinder(BaseStorageFinder):
  191. """
  192. A static files finder that uses the default storage backend.
  193. """
  194. storage = default_storage
  195. def find(path, all=False):
  196. """
  197. Find a static file with the given path using all enabled finders.
  198. If ``all`` is ``False`` (default), return the first matching
  199. absolute path (or ``None`` if no match). Otherwise return a list.
  200. """
  201. matches = []
  202. for finder in get_finders():
  203. result = finder.find(path, all=all)
  204. if not all and result:
  205. return result
  206. if not isinstance(result, (list, tuple)):
  207. result = [result]
  208. matches.extend(result)
  209. if matches:
  210. return matches
  211. # No match.
  212. return all and [] or None
  213. def get_finders():
  214. for finder_path in settings.STATICFILES_FINDERS:
  215. yield get_finder(finder_path)
  216. def _get_finder(import_path):
  217. """
  218. Imports the staticfiles finder class described by import_path, where
  219. import_path is the full Python path to the class.
  220. """
  221. module, attr = import_path.rsplit('.', 1)
  222. try:
  223. mod = import_module(module)
  224. except ImportError, e:
  225. raise ImproperlyConfigured('Error importing module %s: "%s"' %
  226. (module, e))
  227. try:
  228. Finder = getattr(mod, attr)
  229. except AttributeError:
  230. raise ImproperlyConfigured('Module "%s" does not define a "%s" '
  231. 'class.' % (module, attr))
  232. if not issubclass(Finder, BaseFinder):
  233. raise ImproperlyConfigured('Finder "%s" is not a subclass of "%s"' %
  234. (Finder, BaseFinder))
  235. return Finder()
  236. get_finder = memoize(_get_finder, _finders, 1)