Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/distlib/resources.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
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 |