Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/distlib/resources.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
| author | shellac |
|---|---|
| date | Thu, 14 May 2020 14:56:58 -0400 |
| parents | 26e78fe6e8c4 |
| children |
comparison
equal
deleted
inserted
replaced
| 1:75ca89e9b81c | 2:6af9afd405e9 |
|---|---|
| 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 |
