Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/pyramid/config/assets.py : 25%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import os
2import pkg_resources
3import sys
5from zope.interface import implementer
7from pyramid.interfaces import IPackageOverrides, PHASE1_CONFIG
9from pyramid.exceptions import ConfigurationError
10from pyramid.threadlocal import get_current_registry
12from pyramid.config.actions import action_method
15class OverrideProvider(pkg_resources.DefaultProvider):
16 def __init__(self, module):
17 pkg_resources.DefaultProvider.__init__(self, module)
18 self.module_name = module.__name__
20 def _get_overrides(self):
21 reg = get_current_registry()
22 overrides = reg.queryUtility(IPackageOverrides, self.module_name)
23 return overrides
25 def get_resource_filename(self, manager, resource_name):
26 """ Return a true filesystem path for resource_name,
27 co-ordinating the extraction with manager, if the resource
28 must be unpacked to the filesystem.
29 """
30 overrides = self._get_overrides()
31 if overrides is not None:
32 filename = overrides.get_filename(resource_name)
33 if filename is not None:
34 return filename
35 return pkg_resources.DefaultProvider.get_resource_filename(
36 self, manager, resource_name
37 )
39 def get_resource_stream(self, manager, resource_name):
40 """ Return a readable file-like object for resource_name."""
41 overrides = self._get_overrides()
42 if overrides is not None:
43 stream = overrides.get_stream(resource_name)
44 if stream is not None:
45 return stream
46 return pkg_resources.DefaultProvider.get_resource_stream(
47 self, manager, resource_name
48 )
50 def get_resource_string(self, manager, resource_name):
51 """ Return a string containing the contents of resource_name."""
52 overrides = self._get_overrides()
53 if overrides is not None:
54 string = overrides.get_string(resource_name)
55 if string is not None:
56 return string
57 return pkg_resources.DefaultProvider.get_resource_string(
58 self, manager, resource_name
59 )
61 def has_resource(self, resource_name):
62 overrides = self._get_overrides()
63 if overrides is not None:
64 result = overrides.has_resource(resource_name)
65 if result is not None:
66 return result
67 return pkg_resources.DefaultProvider.has_resource(self, resource_name)
69 def resource_isdir(self, resource_name):
70 overrides = self._get_overrides()
71 if overrides is not None:
72 result = overrides.isdir(resource_name)
73 if result is not None:
74 return result
75 return pkg_resources.DefaultProvider.resource_isdir(
76 self, resource_name
77 )
79 def resource_listdir(self, resource_name):
80 overrides = self._get_overrides()
81 if overrides is not None:
82 result = overrides.listdir(resource_name)
83 if result is not None:
84 return result
85 return pkg_resources.DefaultProvider.resource_listdir(
86 self, resource_name
87 )
90@implementer(IPackageOverrides)
91class PackageOverrides(object):
92 # pkg_resources arg in kw args below for testing
93 def __init__(self, package, pkg_resources=pkg_resources):
94 loader = self._real_loader = getattr(package, '__loader__', None)
95 if isinstance(loader, self.__class__):
96 self._real_loader = None
97 # We register ourselves as a __loader__ *only* to support the
98 # setuptools _find_adapter adapter lookup; this class doesn't
99 # actually support the PEP 302 loader "API". This is
100 # excusable due to the following statement in the spec:
101 # ... Loader objects are not
102 # required to offer any useful functionality (any such functionality,
103 # such as the zipimport get_data() method mentioned above, is
104 # optional)...
105 # A __loader__ attribute is basically metadata, and setuptools
106 # uses it as such.
107 package.__loader__ = self
108 # we call register_loader_type for every instantiation of this
109 # class; that's OK, it's idempotent to do it more than once.
110 pkg_resources.register_loader_type(self.__class__, OverrideProvider)
111 self.overrides = []
112 self.overridden_package_name = package.__name__
114 def insert(self, path, source):
115 if not path or path.endswith('/'):
116 override = DirectoryOverride(path, source)
117 else:
118 override = FileOverride(path, source)
119 self.overrides.insert(0, override)
120 return override
122 def filtered_sources(self, resource_name):
123 for override in self.overrides:
124 o = override(resource_name)
125 if o is not None:
126 yield o
128 def get_filename(self, resource_name):
129 for source, path in self.filtered_sources(resource_name):
130 result = source.get_filename(path)
131 if result is not None:
132 return result
134 def get_stream(self, resource_name):
135 for source, path in self.filtered_sources(resource_name):
136 result = source.get_stream(path)
137 if result is not None:
138 return result
140 def get_string(self, resource_name):
141 for source, path in self.filtered_sources(resource_name):
142 result = source.get_string(path)
143 if result is not None:
144 return result
146 def has_resource(self, resource_name):
147 for source, path in self.filtered_sources(resource_name):
148 if source.exists(path):
149 return True
151 def isdir(self, resource_name):
152 for source, path in self.filtered_sources(resource_name):
153 result = source.isdir(path)
154 if result is not None:
155 return result
157 def listdir(self, resource_name):
158 for source, path in self.filtered_sources(resource_name):
159 result = source.listdir(path)
160 if result is not None:
161 return result
163 @property
164 def real_loader(self):
165 if self._real_loader is None:
166 raise NotImplementedError()
167 return self._real_loader
169 def get_data(self, path):
170 """ See IPEP302Loader.
171 """
172 return self.real_loader.get_data(path)
174 def is_package(self, fullname):
175 """ See IPEP302Loader.
176 """
177 return self.real_loader.is_package(fullname)
179 def get_code(self, fullname):
180 """ See IPEP302Loader.
181 """
182 return self.real_loader.get_code(fullname)
184 def get_source(self, fullname):
185 """ See IPEP302Loader.
186 """
187 return self.real_loader.get_source(fullname)
190class DirectoryOverride:
191 def __init__(self, path, source):
192 self.path = path
193 self.pathlen = len(self.path)
194 self.source = source
196 def __call__(self, resource_name):
197 if resource_name.startswith(self.path):
198 new_path = resource_name[self.pathlen :]
199 return self.source, new_path
202class FileOverride:
203 def __init__(self, path, source):
204 self.path = path
205 self.source = source
207 def __call__(self, resource_name):
208 if resource_name == self.path:
209 return self.source, ''
212class PackageAssetSource(object):
213 """
214 An asset source relative to a package.
216 If this asset source is a file, then we expect the ``prefix`` to point
217 to the new name of the file, and the incoming ``resource_name`` will be
218 the empty string, as returned by the ``FileOverride``.
220 """
222 def __init__(self, package, prefix):
223 self.package = package
224 if hasattr(package, '__name__'):
225 self.pkg_name = package.__name__
226 else:
227 self.pkg_name = package
228 self.prefix = prefix
230 def get_path(self, resource_name):
231 return '%s%s' % (self.prefix, resource_name)
233 def get_filename(self, resource_name):
234 path = self.get_path(resource_name)
235 if pkg_resources.resource_exists(self.pkg_name, path):
236 return pkg_resources.resource_filename(self.pkg_name, path)
238 def get_stream(self, resource_name):
239 path = self.get_path(resource_name)
240 if pkg_resources.resource_exists(self.pkg_name, path):
241 return pkg_resources.resource_stream(self.pkg_name, path)
243 def get_string(self, resource_name):
244 path = self.get_path(resource_name)
245 if pkg_resources.resource_exists(self.pkg_name, path):
246 return pkg_resources.resource_string(self.pkg_name, path)
248 def exists(self, resource_name):
249 path = self.get_path(resource_name)
250 if pkg_resources.resource_exists(self.pkg_name, path):
251 return True
253 def isdir(self, resource_name):
254 path = self.get_path(resource_name)
255 if pkg_resources.resource_exists(self.pkg_name, path):
256 return pkg_resources.resource_isdir(self.pkg_name, path)
258 def listdir(self, resource_name):
259 path = self.get_path(resource_name)
260 if pkg_resources.resource_exists(self.pkg_name, path):
261 return pkg_resources.resource_listdir(self.pkg_name, path)
264class FSAssetSource(object):
265 """
266 An asset source relative to a path in the filesystem.
268 """
270 def __init__(self, prefix):
271 self.prefix = prefix
273 def get_path(self, resource_name):
274 if resource_name:
275 path = os.path.join(self.prefix, resource_name)
276 else:
277 path = self.prefix
278 return path
280 def get_filename(self, resource_name):
281 path = self.get_path(resource_name)
282 if os.path.exists(path):
283 return path
285 def get_stream(self, resource_name):
286 path = self.get_filename(resource_name)
287 if path is not None:
288 return open(path, 'rb')
290 def get_string(self, resource_name):
291 stream = self.get_stream(resource_name)
292 if stream is not None:
293 with stream:
294 return stream.read()
296 def exists(self, resource_name):
297 path = self.get_filename(resource_name)
298 if path is not None:
299 return True
301 def isdir(self, resource_name):
302 path = self.get_filename(resource_name)
303 if path is not None:
304 return os.path.isdir(path)
306 def listdir(self, resource_name):
307 path = self.get_filename(resource_name)
308 if path is not None:
309 return os.listdir(path)
312class AssetsConfiguratorMixin(object):
313 def _override(
314 self, package, path, override_source, PackageOverrides=PackageOverrides
315 ):
316 pkg_name = package.__name__
317 override = self.registry.queryUtility(IPackageOverrides, name=pkg_name)
318 if override is None:
319 override = PackageOverrides(package)
320 self.registry.registerUtility(
321 override, IPackageOverrides, name=pkg_name
322 )
323 override.insert(path, override_source)
325 @action_method
326 def override_asset(self, to_override, override_with, _override=None):
327 """ Add a :app:`Pyramid` asset override to the current
328 configuration state.
330 ``to_override`` is an :term:`asset specification` to the
331 asset being overridden.
333 ``override_with`` is an :term:`asset specification` to the
334 asset that is performing the override. This may also be an absolute
335 path.
337 See :ref:`assets_chapter` for more
338 information about asset overrides."""
339 if to_override == override_with:
340 raise ConfigurationError(
341 'You cannot override an asset with itself'
342 )
344 package = to_override
345 path = ''
346 if ':' in to_override:
347 package, path = to_override.split(':', 1)
349 # *_isdir = override is package or directory
350 overridden_isdir = path == '' or path.endswith('/')
352 if os.path.isabs(override_with):
353 override_source = FSAssetSource(override_with)
354 if not os.path.exists(override_with):
355 raise ConfigurationError(
356 'Cannot override asset with an absolute path that does '
357 'not exist'
358 )
359 override_isdir = os.path.isdir(override_with)
360 override_package = None
361 override_prefix = override_with
362 else:
363 override_package = override_with
364 override_prefix = ''
365 if ':' in override_with:
366 override_package, override_prefix = override_with.split(':', 1)
368 __import__(override_package)
369 to_package = sys.modules[override_package]
370 override_source = PackageAssetSource(to_package, override_prefix)
372 override_isdir = override_prefix == '' or override_with.endswith(
373 '/'
374 )
376 if overridden_isdir and (not override_isdir):
377 raise ConfigurationError(
378 'A directory cannot be overridden with a file (put a '
379 'slash at the end of override_with if necessary)'
380 )
382 if (not overridden_isdir) and override_isdir:
383 raise ConfigurationError(
384 'A file cannot be overridden with a directory (put a '
385 'slash at the end of to_override if necessary)'
386 )
388 override = _override or self._override # test jig
390 def register():
391 __import__(package)
392 from_package = sys.modules[package]
393 override(from_package, path, override_source)
395 intr = self.introspectable(
396 'asset overrides',
397 (package, override_package, path, override_prefix),
398 '%s -> %s' % (to_override, override_with),
399 'asset override',
400 )
401 intr['to_override'] = to_override
402 intr['override_with'] = override_with
403 self.action(
404 None, register, introspectables=(intr,), order=PHASE1_CONFIG
405 )
407 override_resource = override_asset # bw compat