Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/contrib/staticfiles/finders.py: 33%
170 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1import functools
2import os
4from django.apps import apps
5from django.conf import settings
6from django.contrib.staticfiles import utils
7from django.core.checks import Error, Warning
8from django.core.exceptions import ImproperlyConfigured
9from django.core.files.storage import FileSystemStorage, Storage, default_storage
10from django.utils._os import safe_join
11from django.utils.functional import LazyObject, empty
12from django.utils.module_loading import import_string
14# To keep track on which directories the finder has searched the static files.
15searched_locations = []
18class BaseFinder:
19 """
20 A base file finder to be used for custom staticfiles finder classes.
21 """
23 def check(self, **kwargs):
24 raise NotImplementedError(
25 "subclasses may provide a check() method to verify the finder is "
26 "configured correctly."
27 )
29 def find(self, path, all=False):
30 """
31 Given a relative file path, find an absolute file path.
33 If the ``all`` parameter is False (default) return only the first found
34 file path; if True, return a list of all found files paths.
35 """
36 raise NotImplementedError(
37 "subclasses of BaseFinder must provide a find() method"
38 )
40 def list(self, ignore_patterns):
41 """
42 Given an optional list of paths to ignore, return a two item iterable
43 consisting of the relative path and storage instance.
44 """
45 raise NotImplementedError(
46 "subclasses of BaseFinder must provide a list() method"
47 )
50class FileSystemFinder(BaseFinder):
51 """
52 A static files finder that uses the ``STATICFILES_DIRS`` setting
53 to locate files.
54 """
56 def __init__(self, app_names=None, *args, **kwargs):
57 # List of locations with static files
58 self.locations = []
59 # Maps dir paths to an appropriate storage instance
60 self.storages = {}
61 for root in settings.STATICFILES_DIRS: 61 ↛ 62line 61 didn't jump to line 62, because the loop on line 61 never started
62 if isinstance(root, (list, tuple)):
63 prefix, root = root
64 else:
65 prefix = ""
66 if (prefix, root) not in self.locations:
67 self.locations.append((prefix, root))
68 for prefix, root in self.locations: 68 ↛ 69line 68 didn't jump to line 69, because the loop on line 68 never started
69 filesystem_storage = FileSystemStorage(location=root)
70 filesystem_storage.prefix = prefix
71 self.storages[root] = filesystem_storage
72 super().__init__(*args, **kwargs)
74 def check(self, **kwargs):
75 errors = []
76 if not isinstance(settings.STATICFILES_DIRS, (list, tuple)): 76 ↛ 77line 76 didn't jump to line 77, because the condition on line 76 was never true
77 errors.append(
78 Error(
79 "The STATICFILES_DIRS setting is not a tuple or list.",
80 hint="Perhaps you forgot a trailing comma?",
81 id="staticfiles.E001",
82 )
83 )
84 return errors
85 for root in settings.STATICFILES_DIRS: 85 ↛ 86line 85 didn't jump to line 86, because the loop on line 85 never started
86 if isinstance(root, (list, tuple)):
87 prefix, root = root
88 if prefix.endswith("/"):
89 errors.append(
90 Error(
91 "The prefix %r in the STATICFILES_DIRS setting must "
92 "not end with a slash." % prefix,
93 id="staticfiles.E003",
94 )
95 )
96 if settings.STATIC_ROOT and os.path.abspath(
97 settings.STATIC_ROOT
98 ) == os.path.abspath(root):
99 errors.append(
100 Error(
101 "The STATICFILES_DIRS setting should not contain the "
102 "STATIC_ROOT setting.",
103 id="staticfiles.E002",
104 )
105 )
106 if not os.path.isdir(root):
107 errors.append(
108 Warning(
109 f"The directory '{root}' in the STATICFILES_DIRS setting "
110 f"does not exist.",
111 id="staticfiles.W004",
112 )
113 )
114 return errors
116 def find(self, path, all=False):
117 """
118 Look for files in the extra locations as defined in STATICFILES_DIRS.
119 """
120 matches = []
121 for prefix, root in self.locations:
122 if root not in searched_locations:
123 searched_locations.append(root)
124 matched_path = self.find_location(root, path, prefix)
125 if matched_path:
126 if not all:
127 return matched_path
128 matches.append(matched_path)
129 return matches
131 def find_location(self, root, path, prefix=None):
132 """
133 Find a requested static file in a location and return the found
134 absolute path (or ``None`` if no match).
135 """
136 if prefix:
137 prefix = "%s%s" % (prefix, os.sep)
138 if not path.startswith(prefix):
139 return None
140 path = path[len(prefix) :]
141 path = safe_join(root, path)
142 if os.path.exists(path):
143 return path
145 def list(self, ignore_patterns):
146 """
147 List all files in all locations.
148 """
149 for prefix, root in self.locations:
150 # Skip nonexistent directories.
151 if os.path.isdir(root):
152 storage = self.storages[root]
153 for path in utils.get_files(storage, ignore_patterns):
154 yield path, storage
157class AppDirectoriesFinder(BaseFinder):
158 """
159 A static files finder that looks in the directory of each app as
160 specified in the source_dir attribute.
161 """
163 storage_class = FileSystemStorage
164 source_dir = "static"
166 def __init__(self, app_names=None, *args, **kwargs):
167 # The list of apps that are handled
168 self.apps = []
169 # Mapping of app names to storage instances
170 self.storages = {}
171 app_configs = apps.get_app_configs()
172 if app_names: 172 ↛ 173line 172 didn't jump to line 173, because the condition on line 172 was never true
173 app_names = set(app_names)
174 app_configs = [ac for ac in app_configs if ac.name in app_names]
175 for app_config in app_configs:
176 app_storage = self.storage_class(
177 os.path.join(app_config.path, self.source_dir)
178 )
179 if os.path.isdir(app_storage.location):
180 self.storages[app_config.name] = app_storage
181 if app_config.name not in self.apps: 181 ↛ 175line 181 didn't jump to line 175, because the condition on line 181 was never false
182 self.apps.append(app_config.name)
183 super().__init__(*args, **kwargs)
185 def list(self, ignore_patterns):
186 """
187 List all files in all app storages.
188 """
189 for storage in self.storages.values():
190 if storage.exists(""): # check if storage location exists
191 for path in utils.get_files(storage, ignore_patterns):
192 yield path, storage
194 def find(self, path, all=False):
195 """
196 Look for files in the app directories.
197 """
198 matches = []
199 for app in self.apps:
200 app_location = self.storages[app].location
201 if app_location not in searched_locations:
202 searched_locations.append(app_location)
203 match = self.find_in_app(app, path)
204 if match:
205 if not all:
206 return match
207 matches.append(match)
208 return matches
210 def find_in_app(self, app, path):
211 """
212 Find a requested static file in an app's static locations.
213 """
214 storage = self.storages.get(app)
215 # Only try to find a file if the source dir actually exists.
216 if storage and storage.exists(path):
217 matched_path = storage.path(path)
218 if matched_path:
219 return matched_path
222class BaseStorageFinder(BaseFinder):
223 """
224 A base static files finder to be used to extended
225 with an own storage class.
226 """
228 storage = None
230 def __init__(self, storage=None, *args, **kwargs):
231 if storage is not None:
232 self.storage = storage
233 if self.storage is None:
234 raise ImproperlyConfigured(
235 "The staticfiles storage finder %r "
236 "doesn't have a storage class "
237 "assigned." % self.__class__
238 )
239 # Make sure we have a storage instance here.
240 if not isinstance(self.storage, (Storage, LazyObject)):
241 self.storage = self.storage()
242 super().__init__(*args, **kwargs)
244 def find(self, path, all=False):
245 """
246 Look for files in the default file storage, if it's local.
247 """
248 try:
249 self.storage.path("")
250 except NotImplementedError:
251 pass
252 else:
253 if self.storage.location not in searched_locations:
254 searched_locations.append(self.storage.location)
255 if self.storage.exists(path):
256 match = self.storage.path(path)
257 if all:
258 match = [match]
259 return match
260 return []
262 def list(self, ignore_patterns):
263 """
264 List all files of the storage.
265 """
266 for path in utils.get_files(self.storage, ignore_patterns):
267 yield path, self.storage
270class DefaultStorageFinder(BaseStorageFinder):
271 """
272 A static files finder that uses the default storage backend.
273 """
275 storage = default_storage
277 def __init__(self, *args, **kwargs):
278 super().__init__(*args, **kwargs)
279 base_location = getattr(self.storage, "base_location", empty)
280 if not base_location:
281 raise ImproperlyConfigured(
282 "The storage backend of the "
283 "staticfiles finder %r doesn't have "
284 "a valid location." % self.__class__
285 )
288def find(path, all=False):
289 """
290 Find a static file with the given path using all enabled finders.
292 If ``all`` is ``False`` (default), return the first matching
293 absolute path (or ``None`` if no match). Otherwise return a list.
294 """
295 searched_locations[:] = []
296 matches = []
297 for finder in get_finders():
298 result = finder.find(path, all=all)
299 if not all and result:
300 return result
301 if not isinstance(result, (list, tuple)):
302 result = [result]
303 matches.extend(result)
304 if matches:
305 return matches
306 # No match.
307 return [] if all else None
310def get_finders():
311 for finder_path in settings.STATICFILES_FINDERS:
312 yield get_finder(finder_path)
315@functools.lru_cache(maxsize=None)
316def get_finder(import_path):
317 """
318 Import the staticfiles finder class described by import_path, where
319 import_path is the full Python path to the class.
320 """
321 Finder = import_string(import_path)
322 if not issubclass(Finder, BaseFinder): 322 ↛ 323line 322 didn't jump to line 323, because the condition on line 322 was never true
323 raise ImproperlyConfigured(
324 'Finder "%s" is not a subclass of "%s"' % (Finder, BaseFinder)
325 )
326 return Finder()