diff options
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/resources.py')
-rw-r--r-- | venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/resources.py | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/resources.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/resources.py new file mode 100644 index 0000000..cd618a6 --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/resources.py | |||
@@ -0,0 +1,355 @@ | |||
1 | # -*- coding: utf-8 -*- | ||
2 | # | ||
3 | # Copyright (C) 2013-2017 Vinay Sajip. | ||
4 | # Licensed to the Python Software Foundation under a contributor agreement. | ||
5 | # See LICENSE.txt and CONTRIBUTORS.txt. | ||
6 | # | ||
7 | from __future__ import unicode_literals | ||
8 | |||
9 | import bisect | ||
10 | import io | ||
11 | import logging | ||
12 | import os | ||
13 | import pkgutil | ||
14 | import shutil | ||
15 | import sys | ||
16 | import types | ||
17 | import zipimport | ||
18 | |||
19 | from . import DistlibException | ||
20 | from .util import cached_property, get_cache_base, path_to_cache_dir, Cache | ||
21 | |||
22 | logger = logging.getLogger(__name__) | ||
23 | |||
24 | |||
25 | cache = None # created when needed | ||
26 | |||
27 | |||
28 | class ResourceCache(Cache): | ||
29 | def __init__(self, base=None): | ||
30 | if base is None: | ||
31 | # Use native string to avoid issues on 2.x: see Python #20140. | ||
32 | base = os.path.join(get_cache_base(), str('resource-cache')) | ||
33 | super(ResourceCache, self).__init__(base) | ||
34 | |||
35 | def is_stale(self, resource, path): | ||
36 | """ | ||
37 | Is the cache stale for the given resource? | ||
38 | |||
39 | :param resource: The :class:`Resource` being cached. | ||
40 | :param path: The path of the resource in the cache. | ||
41 | :return: True if the cache is stale. | ||
42 | """ | ||
43 | # Cache invalidation is a hard problem :-) | ||
44 | return True | ||
45 | |||
46 | def get(self, resource): | ||
47 | """ | ||
48 | Get a resource into the cache, | ||
49 | |||
50 | :param resource: A :class:`Resource` instance. | ||
51 | :return: The pathname of the resource in the cache. | ||
52 | """ | ||
53 | prefix, path = resource.finder.get_cache_info(resource) | ||
54 | if prefix is None: | ||
55 | result = path | ||
56 | else: | ||
57 | result = os.path.join(self.base, self.prefix_to_dir(prefix), path) | ||
58 | dirname = os.path.dirname(result) | ||
59 | if not os.path.isdir(dirname): | ||
60 | os.makedirs(dirname) | ||
61 | if not os.path.exists(result): | ||
62 | stale = True | ||
63 | else: | ||
64 | stale = self.is_stale(resource, path) | ||
65 | if stale: | ||
66 | # write the bytes of the resource to the cache location | ||
67 | with open(result, 'wb') as f: | ||
68 | f.write(resource.bytes) | ||
69 | return result | ||
70 | |||
71 | |||
72 | class ResourceBase(object): | ||
73 | def __init__(self, finder, name): | ||
74 | self.finder = finder | ||
75 | self.name = name | ||
76 | |||
77 | |||
78 | class Resource(ResourceBase): | ||
79 | """ | ||
80 | A class representing an in-package resource, such as a data file. This is | ||
81 | not normally instantiated by user code, but rather by a | ||
82 | :class:`ResourceFinder` which manages the resource. | ||
83 | """ | ||
84 | is_container = False # Backwards compatibility | ||
85 | |||
86 | def as_stream(self): | ||
87 | """ | ||
88 | Get the resource as a stream. | ||
89 | |||
90 | This is not a property to make it obvious that it returns a new stream | ||
91 | each time. | ||
92 | """ | ||
93 | return self.finder.get_stream(self) | ||
94 | |||
95 | @cached_property | ||
96 | def file_path(self): | ||
97 | global cache | ||
98 | if cache is None: | ||
99 | cache = ResourceCache() | ||
100 | return cache.get(self) | ||
101 | |||
102 | @cached_property | ||
103 | def bytes(self): | ||
104 | return self.finder.get_bytes(self) | ||
105 | |||
106 | @cached_property | ||
107 | def size(self): | ||
108 | return self.finder.get_size(self) | ||
109 | |||
110 | |||
111 | class ResourceContainer(ResourceBase): | ||
112 | is_container = True # Backwards compatibility | ||
113 | |||
114 | @cached_property | ||
115 | def resources(self): | ||
116 | return self.finder.get_resources(self) | ||
117 | |||
118 | |||
119 | class ResourceFinder(object): | ||
120 | """ | ||
121 | Resource finder for file system resources. | ||
122 | """ | ||
123 | |||
124 | if sys.platform.startswith('java'): | ||
125 | skipped_extensions = ('.pyc', '.pyo', '.class') | ||
126 | else: | ||
127 | skipped_extensions = ('.pyc', '.pyo') | ||
128 | |||
129 | def __init__(self, module): | ||
130 | self.module = module | ||
131 | self.loader = getattr(module, '__loader__', None) | ||
132 | self.base = os.path.dirname(getattr(module, '__file__', '')) | ||
133 | |||
134 | def _adjust_path(self, path): | ||
135 | return os.path.realpath(path) | ||
136 | |||
137 | def _make_path(self, resource_name): | ||
138 | # Issue #50: need to preserve type of path on Python 2.x | ||
139 | # like os.path._get_sep | ||
140 | if isinstance(resource_name, bytes): # should only happen on 2.x | ||
141 | sep = b'/' | ||
142 | else: | ||
143 | sep = '/' | ||
144 | parts = resource_name.split(sep) | ||
145 | parts.insert(0, self.base) | ||
146 | result = os.path.join(*parts) | ||
147 | return self._adjust_path(result) | ||
148 | |||
149 | def _find(self, path): | ||
150 | return os.path.exists(path) | ||
151 | |||
152 | def get_cache_info(self, resource): | ||
153 | return None, resource.path | ||
154 | |||
155 | def find(self, resource_name): | ||
156 | path = self._make_path(resource_name) | ||
157 | if not self._find(path): | ||
158 | result = None | ||
159 | else: | ||
160 | if self._is_directory(path): | ||
161 | result = ResourceContainer(self, resource_name) | ||
162 | else: | ||
163 | result = Resource(self, resource_name) | ||
164 | result.path = path | ||
165 | return result | ||
166 | |||
167 | def get_stream(self, resource): | ||
168 | return open(resource.path, 'rb') | ||
169 | |||
170 | def get_bytes(self, resource): | ||
171 | with open(resource.path, 'rb') as f: | ||
172 | return f.read() | ||
173 | |||
174 | def get_size(self, resource): | ||
175 | return os.path.getsize(resource.path) | ||
176 | |||
177 | def get_resources(self, resource): | ||
178 | def allowed(f): | ||
179 | return (f != '__pycache__' and not | ||
180 | f.endswith(self.skipped_extensions)) | ||
181 | return set([f for f in os.listdir(resource.path) if allowed(f)]) | ||
182 | |||
183 | def is_container(self, resource): | ||
184 | return self._is_directory(resource.path) | ||
185 | |||
186 | _is_directory = staticmethod(os.path.isdir) | ||
187 | |||
188 | def iterator(self, resource_name): | ||
189 | resource = self.find(resource_name) | ||
190 | if resource is not None: | ||
191 | todo = [resource] | ||
192 | while todo: | ||
193 | resource = todo.pop(0) | ||
194 | yield resource | ||
195 | if resource.is_container: | ||
196 | rname = resource.name | ||
197 | for name in resource.resources: | ||
198 | if not rname: | ||
199 | new_name = name | ||
200 | else: | ||
201 | new_name = '/'.join([rname, name]) | ||
202 | child = self.find(new_name) | ||
203 | if child.is_container: | ||
204 | todo.append(child) | ||
205 | else: | ||
206 | yield child | ||
207 | |||
208 | |||
209 | class ZipResourceFinder(ResourceFinder): | ||
210 | """ | ||
211 | Resource finder for resources in .zip files. | ||
212 | """ | ||
213 | def __init__(self, module): | ||
214 | super(ZipResourceFinder, self).__init__(module) | ||
215 | archive = self.loader.archive | ||
216 | self.prefix_len = 1 + len(archive) | ||
217 | # PyPy doesn't have a _files attr on zipimporter, and you can't set one | ||
218 | if hasattr(self.loader, '_files'): | ||
219 | self._files = self.loader._files | ||
220 | else: | ||
221 | self._files = zipimport._zip_directory_cache[archive] | ||
222 | self.index = sorted(self._files) | ||
223 | |||
224 | def _adjust_path(self, path): | ||
225 | return path | ||
226 | |||
227 | def _find(self, path): | ||
228 | path = path[self.prefix_len:] | ||
229 | if path in self._files: | ||
230 | result = True | ||
231 | else: | ||
232 | if path and path[-1] != os.sep: | ||
233 | path = path + os.sep | ||
234 | i = bisect.bisect(self.index, path) | ||
235 | try: | ||
236 | result = self.index[i].startswith(path) | ||
237 | except IndexError: | ||
238 | result = False | ||
239 | if not result: | ||
240 | logger.debug('_find failed: %r %r', path, self.loader.prefix) | ||
241 | else: | ||
242 | logger.debug('_find worked: %r %r', path, self.loader.prefix) | ||
243 | return result | ||
244 | |||
245 | def get_cache_info(self, resource): | ||
246 | prefix = self.loader.archive | ||
247 | path = resource.path[1 + len(prefix):] | ||
248 | return prefix, path | ||
249 | |||
250 | def get_bytes(self, resource): | ||
251 | return self.loader.get_data(resource.path) | ||
252 | |||
253 | def get_stream(self, resource): | ||
254 | return io.BytesIO(self.get_bytes(resource)) | ||
255 | |||
256 | def get_size(self, resource): | ||
257 | path = resource.path[self.prefix_len:] | ||
258 | return self._files[path][3] | ||
259 | |||
260 | def get_resources(self, resource): | ||
261 | path = resource.path[self.prefix_len:] | ||
262 | if path and path[-1] != os.sep: | ||
263 | path += os.sep | ||
264 | plen = len(path) | ||
265 | result = set() | ||
266 | i = bisect.bisect(self.index, path) | ||
267 | while i < len(self.index): | ||
268 | if not self.index[i].startswith(path): | ||
269 | break | ||
270 | s = self.index[i][plen:] | ||
271 | result.add(s.split(os.sep, 1)[0]) # only immediate children | ||
272 | i += 1 | ||
273 | return result | ||
274 | |||
275 | def _is_directory(self, path): | ||
276 | path = path[self.prefix_len:] | ||
277 | if path and path[-1] != os.sep: | ||
278 | path += os.sep | ||
279 | i = bisect.bisect(self.index, path) | ||
280 | try: | ||
281 | result = self.index[i].startswith(path) | ||
282 | except IndexError: | ||
283 | result = False | ||
284 | return result | ||
285 | |||
286 | _finder_registry = { | ||
287 | type(None): ResourceFinder, | ||
288 | zipimport.zipimporter: ZipResourceFinder | ||
289 | } | ||
290 | |||
291 | try: | ||
292 | # In Python 3.6, _frozen_importlib -> _frozen_importlib_external | ||
293 | try: | ||
294 | import _frozen_importlib_external as _fi | ||
295 | except ImportError: | ||
296 | import _frozen_importlib as _fi | ||
297 | _finder_registry[_fi.SourceFileLoader] = ResourceFinder | ||
298 | _finder_registry[_fi.FileFinder] = ResourceFinder | ||
299 | del _fi | ||
300 | except (ImportError, AttributeError): | ||
301 | pass | ||
302 | |||
303 | |||
304 | def register_finder(loader, finder_maker): | ||
305 | _finder_registry[type(loader)] = finder_maker | ||
306 | |||
307 | _finder_cache = {} | ||
308 | |||
309 | |||
310 | def finder(package): | ||
311 | """ | ||
312 | Return a resource finder for a package. | ||
313 | :param package: The name of the package. | ||
314 | :return: A :class:`ResourceFinder` instance for the package. | ||
315 | """ | ||
316 | if package in _finder_cache: | ||
317 | result = _finder_cache[package] | ||
318 | else: | ||
319 | if package not in sys.modules: | ||
320 | __import__(package) | ||
321 | module = sys.modules[package] | ||
322 | path = getattr(module, '__path__', None) | ||
323 | if path is None: | ||
324 | raise DistlibException('You cannot get a finder for a module, ' | ||
325 | 'only for a package') | ||
326 | loader = getattr(module, '__loader__', None) | ||
327 | finder_maker = _finder_registry.get(type(loader)) | ||
328 | if finder_maker is None: | ||
329 | raise DistlibException('Unable to locate finder for %r' % package) | ||
330 | result = finder_maker(module) | ||
331 | _finder_cache[package] = result | ||
332 | return result | ||
333 | |||
334 | |||
335 | _dummy_module = types.ModuleType(str('__dummy__')) | ||
336 | |||
337 | |||
338 | def finder_for_path(path): | ||
339 | """ | ||
340 | Return a resource finder for a path, which should represent a container. | ||
341 | |||
342 | :param path: The path. | ||
343 | :return: A :class:`ResourceFinder` instance for the path. | ||
344 | """ | ||
345 | result = None | ||
346 | # calls any path hooks, gets importer into cache | ||
347 | pkgutil.get_importer(path) | ||
348 | loader = sys.path_importer_cache.get(path) | ||
349 | finder = _finder_registry.get(type(loader)) | ||
350 | if finder: | ||
351 | module = _dummy_module | ||
352 | module.__file__ = os.path.join(path, '') | ||
353 | module.__loader__ = loader | ||
354 | result = finder(module) | ||
355 | return result | ||