~ibmcharmers/charms/xenial/ibm-cinder-storwize-svc/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/pip/_vendor/distlib/resources.py

  • Committer: Ankammarao
  • Date: 2017-03-06 05:11:42 UTC
  • Revision ID: achittet@in.ibm.com-20170306051142-dpg27z4es1k56hfn
Marked tests folder executable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Copyright (C) 2013-2016 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