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

1import functools 

2import os 

3 

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 

13 

14# To keep track on which directories the finder has searched the static files. 

15searched_locations = [] 

16 

17 

18class BaseFinder: 

19 """ 

20 A base file finder to be used for custom staticfiles finder classes. 

21 """ 

22 

23 def check(self, **kwargs): 

24 raise NotImplementedError( 

25 "subclasses may provide a check() method to verify the finder is " 

26 "configured correctly." 

27 ) 

28 

29 def find(self, path, all=False): 

30 """ 

31 Given a relative file path, find an absolute file path. 

32 

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 ) 

39 

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 ) 

48 

49 

50class FileSystemFinder(BaseFinder): 

51 """ 

52 A static files finder that uses the ``STATICFILES_DIRS`` setting 

53 to locate files. 

54 """ 

55 

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) 

73 

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 

115 

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 

130 

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 

144 

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 

155 

156 

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 """ 

162 

163 storage_class = FileSystemStorage 

164 source_dir = "static" 

165 

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) 

184 

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 

193 

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 

209 

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 

220 

221 

222class BaseStorageFinder(BaseFinder): 

223 """ 

224 A base static files finder to be used to extended 

225 with an own storage class. 

226 """ 

227 

228 storage = None 

229 

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) 

243 

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 [] 

261 

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 

268 

269 

270class DefaultStorageFinder(BaseStorageFinder): 

271 """ 

272 A static files finder that uses the default storage backend. 

273 """ 

274 

275 storage = default_storage 

276 

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 ) 

286 

287 

288def find(path, all=False): 

289 """ 

290 Find a static file with the given path using all enabled finders. 

291 

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 

308 

309 

310def get_finders(): 

311 for finder_path in settings.STATICFILES_FINDERS: 

312 yield get_finder(finder_path) 

313 

314 

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()