Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / astroid / modutils.py @ 745

History | View | Annotate | Download (25 KB)

1
# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
#
4
# This file is part of astroid.
5
#
6
# astroid is free software: you can redistribute it and/or modify it under
7
# the terms of the GNU Lesser General Public License as published by the Free
8
# Software Foundation, either version 2.1 of the License, or (at your option) any
9
# later version.
10
#
11
# astroid is distributed in the hope that it will be useful, but WITHOUT
12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
14
# details.
15
#
16
# You should have received a copy of the GNU Lesser General Public License along
17
# with astroid.  If not, see <http://www.gnu.org/licenses/>.
18
"""Python modules manipulation utility functions.
19

20
:type PY_SOURCE_EXTS: tuple(str)
21
:var PY_SOURCE_EXTS: list of possible python source file extension
22

23
:type STD_LIB_DIRS: set of str
24
:var STD_LIB_DIRS: directories where standard modules are located
25

26
:type BUILTIN_MODULES: dict
27
:var BUILTIN_MODULES: dictionary with builtin module names has key
28
"""
29
from __future__ import with_statement
30

    
31
import imp
32
import os
33
import platform
34
import sys
35
from distutils.sysconfig import get_python_lib
36
from distutils.errors import DistutilsPlatformError
37
import zipimport
38

    
39
try:
40
    import pkg_resources
41
except ImportError:
42
    pkg_resources = None
43

    
44
PY_ZIPMODULE = object()
45

    
46
if sys.platform.startswith('win'):
47
    PY_SOURCE_EXTS = ('py', 'pyw')
48
    PY_COMPILED_EXTS = ('dll', 'pyd')
49
else:
50
    PY_SOURCE_EXTS = ('py',)
51
    PY_COMPILED_EXTS = ('so',)
52

    
53

    
54
try:
55
    # The explicit sys.prefix is to work around a patch in virtualenv that
56
    # replaces the 'real' sys.prefix (i.e. the location of the binary)
57
    # with the prefix from which the virtualenv was created. This throws
58
    # off the detection logic for standard library modules, thus the
59
    # workaround.
60
    STD_LIB_DIRS = set([
61
        get_python_lib(standard_lib=True, prefix=sys.prefix),
62
        # Take care of installations where exec_prefix != prefix.
63
        get_python_lib(standard_lib=True, prefix=sys.exec_prefix),
64
        get_python_lib(standard_lib=True)])
65
# get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to
66
# non-valid path, see https://bugs.pypy.org/issue1164
67
except DistutilsPlatformError:
68
    STD_LIB_DIRS = set()
69

    
70
if os.name == 'nt':
71
    STD_LIB_DIRS.add(os.path.join(sys.prefix, 'dlls'))
72
    try:
73
        # real_prefix is defined when running inside virtualenv.
74
        STD_LIB_DIRS.add(os.path.join(sys.real_prefix, 'dlls'))
75
    except AttributeError:
76
        pass
77
if platform.python_implementation() == 'PyPy':
78
    _root = os.path.join(sys.prefix, 'lib_pypy')
79
    STD_LIB_DIRS.add(_root)
80
    try:
81
        # real_prefix is defined when running inside virtualenv.
82
        STD_LIB_DIRS.add(os.path.join(sys.real_prefix, 'lib_pypy'))
83
    except AttributeError:
84
        pass
85
    del _root
86
if os.name == 'posix':
87
    # Need the real prefix is we're under a virtualenv, otherwise
88
    # the usual one will do.
89
    try:
90
        prefix = sys.real_prefix
91
    except AttributeError:
92
        prefix = sys.prefix
93

    
94
    def _posix_path(path):
95
        base_python = 'python%d.%d' % sys.version_info[:2]
96
        return os.path.join(prefix, path, base_python)
97

    
98
    STD_LIB_DIRS.add(_posix_path('lib'))
99
    if sys.maxsize > 2**32:
100
        # This tries to fix a problem with /usr/lib64 builds,
101
        # where systems are running both 32-bit and 64-bit code
102
        # on the same machine, which reflects into the places where
103
        # standard library could be found. More details can be found
104
        # here http://bugs.python.org/issue1294959.
105
        # An easy reproducing case would be
106
        # https://github.com/PyCQA/pylint/issues/712#issuecomment-163178753
107
        STD_LIB_DIRS.add(_posix_path('lib64'))
108

    
109
EXT_LIB_DIR = get_python_lib()
110
IS_JYTHON = platform.python_implementation() == 'Jython'
111
BUILTIN_MODULES = dict.fromkeys(sys.builtin_module_names, True)
112

    
113

    
114
class NoSourceFile(Exception):
115
    """exception raised when we are not able to get a python
116
    source file for a precompiled file
117
    """
118

    
119
def _normalize_path(path):
120
    return os.path.normcase(os.path.abspath(path))
121

    
122

    
123
def _path_from_filename(filename, is_jython=IS_JYTHON):
124
    if not is_jython:
125
        if sys.version_info > (3, 0):
126
            return filename
127
        else:
128
            if filename.endswith(".pyc"):
129
                return filename[:-1]
130
            return filename
131
    head, has_pyclass, _ = filename.partition("$py.class")
132
    if has_pyclass:
133
        return head + ".py"
134
    return filename
135

    
136

    
137
def _handle_blacklist(blacklist, dirnames, filenames):
138
    """remove files/directories in the black list
139

140
    dirnames/filenames are usually from os.walk
141
    """
142
    for norecurs in blacklist:
143
        if norecurs in dirnames:
144
            dirnames.remove(norecurs)
145
        elif norecurs in filenames:
146
            filenames.remove(norecurs)
147

    
148

    
149
_NORM_PATH_CACHE = {}
150

    
151
def _cache_normalize_path(path):
152
    """abspath with caching"""
153
    # _module_file calls abspath on every path in sys.path every time it's
154
    # called; on a larger codebase this easily adds up to half a second just
155
    # assembling path components. This cache alleviates that.
156
    try:
157
        return _NORM_PATH_CACHE[path]
158
    except KeyError:
159
        if not path: # don't cache result for ''
160
            return _normalize_path(path)
161
        result = _NORM_PATH_CACHE[path] = _normalize_path(path)
162
        return result
163

    
164
def load_module_from_name(dotted_name, path=None, use_sys=True):
165
    """Load a Python module from its name.
166

167
    :type dotted_name: str
168
    :param dotted_name: python name of a module or package
169

170
    :type path: list or None
171
    :param path:
172
      optional list of path where the module or package should be
173
      searched (use sys.path if nothing or None is given)
174

175
    :type use_sys: bool
176
    :param use_sys:
177
      boolean indicating whether the sys.modules dictionary should be
178
      used or not
179

180

181
    :raise ImportError: if the module or package is not found
182

183
    :rtype: module
184
    :return: the loaded module
185
    """
186
    return load_module_from_modpath(dotted_name.split('.'), path, use_sys)
187

    
188

    
189
def load_module_from_modpath(parts, path=None, use_sys=1):
190
    """Load a python module from its splitted name.
191

192
    :type parts: list(str) or tuple(str)
193
    :param parts:
194
      python name of a module or package splitted on '.'
195

196
    :type path: list or None
197
    :param path:
198
      optional list of path where the module or package should be
199
      searched (use sys.path if nothing or None is given)
200

201
    :type use_sys: bool
202
    :param use_sys:
203
      boolean indicating whether the sys.modules dictionary should be used or not
204

205
    :raise ImportError: if the module or package is not found
206

207
    :rtype: module
208
    :return: the loaded module
209
    """
210
    if use_sys:
211
        try:
212
            return sys.modules['.'.join(parts)]
213
        except KeyError:
214
            pass
215
    modpath = []
216
    prevmodule = None
217
    for part in parts:
218
        modpath.append(part)
219
        curname = '.'.join(modpath)
220
        module = None
221
        if len(modpath) != len(parts):
222
            # even with use_sys=False, should try to get outer packages from sys.modules
223
            module = sys.modules.get(curname)
224
        elif use_sys:
225
            # because it may have been indirectly loaded through a parent
226
            module = sys.modules.get(curname)
227
        if module is None:
228
            mp_file, mp_filename, mp_desc = imp.find_module(part, path)
229
            module = imp.load_module(curname, mp_file, mp_filename, mp_desc)
230
            # mp_file still needs to be closed.
231
            if mp_file:
232
                mp_file.close()
233
        if prevmodule:
234
            setattr(prevmodule, part, module)
235
        _file = getattr(module, '__file__', '')
236
        prevmodule = module
237
        if not _file and _is_namespace(curname):
238
            continue
239
        if not _file and len(modpath) != len(parts):
240
            raise ImportError('no module in %s' % '.'.join(parts[len(modpath):]))
241
        path = [os.path.dirname(_file)]
242
    return module
243

    
244

    
245
def load_module_from_file(filepath, path=None, use_sys=True, extrapath=None):
246
    """Load a Python module from it's path.
247

248
    :type filepath: str
249
    :param filepath: path to the python module or package
250

251
    :type path: list or None
252
    :param path:
253
      optional list of path where the module or package should be
254
      searched (use sys.path if nothing or None is given)
255

256
    :type use_sys: bool
257
    :param use_sys:
258
      boolean indicating whether the sys.modules dictionary should be
259
      used or not
260

261

262
    :raise ImportError: if the module or package is not found
263

264
    :rtype: module
265
    :return: the loaded module
266
    """
267
    modpath = modpath_from_file(filepath, extrapath)
268
    return load_module_from_modpath(modpath, path, use_sys)
269

    
270

    
271
def _check_init(path, mod_path):
272
    """check there are some __init__.py all along the way"""
273
    modpath = []
274
    for part in mod_path:
275
        modpath.append(part)
276
        path = os.path.join(path, part)
277
        if not _is_namespace('.'.join(modpath)) and not _has_init(path):
278
            return False
279
    return True
280

    
281

    
282
def modpath_from_file(filename, extrapath=None):
283
    """given a file path return the corresponding splitted module's name
284
    (i.e name of a module or package splitted on '.')
285

286
    :type filename: str
287
    :param filename: file's path for which we want the module's name
288

289
    :type extrapath: dict
290
    :param extrapath:
291
      optional extra search path, with path as key and package name for the path
292
      as value. This is usually useful to handle package splitted in multiple
293
      directories using __path__ trick.
294

295

296
    :raise ImportError:
297
      if the corresponding module's name has not been found
298

299
    :rtype: list(str)
300
    :return: the corresponding splitted module's name
301
    """
302
    filename = _path_from_filename(filename)
303
    filename = os.path.abspath(filename)
304
    base = os.path.splitext(filename)[0]
305
    if extrapath is not None:
306
        for path_ in extrapath:
307
            path = os.path.abspath(path_)
308
            if path and os.path.normcase(base[:len(path)]) == os.path.normcase(path):
309
                submodpath = [pkg for pkg in base[len(path):].split(os.sep)
310
                              if pkg]
311
                if _check_init(path, submodpath[:-1]):
312
                    return extrapath[path_].split('.') + submodpath
313
    for path in sys.path:
314
        path = _cache_normalize_path(path)
315
        if path and os.path.normcase(base).startswith(path):
316
            modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg]
317
            if _check_init(path, modpath[:-1]):
318
                return modpath
319
    raise ImportError('Unable to find module for %s in %s' % (
320
        filename, ', \n'.join(sys.path)))
321

    
322

    
323
def file_from_modpath(modpath, path=None, context_file=None):
324
    return file_info_from_modpath(modpath, path, context_file)[0]
325

    
326
def file_info_from_modpath(modpath, path=None, context_file=None):
327
    """given a mod path (i.e. splitted module / package name), return the
328
    corresponding file, giving priority to source file over precompiled
329
    file if it exists
330

331
    :type modpath: list or tuple
332
    :param modpath:
333
      splitted module's name (i.e name of a module or package splitted
334
      on '.')
335
      (this means explicit relative imports that start with dots have
336
      empty strings in this list!)
337

338
    :type path: list or None
339
    :param path:
340
      optional list of path where the module or package should be
341
      searched (use sys.path if nothing or None is given)
342

343
    :type context_file: str or None
344
    :param context_file:
345
      context file to consider, necessary if the identifier has been
346
      introduced using a relative import unresolvable in the actual
347
      context (i.e. modutils)
348

349
    :raise ImportError: if there is no such module in the directory
350

351
    :rtype: (str or None, import type)
352
    :return:
353
      the path to the module's file or None if it's an integrated
354
      builtin module such as 'sys'
355
    """
356
    if context_file is not None:
357
        context = os.path.dirname(context_file)
358
    else:
359
        context = context_file
360
    if modpath[0] == 'xml':
361
        # handle _xmlplus
362
        try:
363
            return _file_from_modpath(['_xmlplus'] + modpath[1:], path, context)
364
        except ImportError:
365
            return _file_from_modpath(modpath, path, context)
366
    elif modpath == ['os', 'path']:
367
        # FIXME: currently ignoring search_path...
368
        return os.path.__file__, imp.PY_SOURCE
369
    return _file_from_modpath(modpath, path, context)
370

    
371

    
372
def get_module_part(dotted_name, context_file=None):
373
    """given a dotted name return the module part of the name :
374

375
    >>> get_module_part('astroid.as_string.dump')
376
    'astroid.as_string'
377

378
    :type dotted_name: str
379
    :param dotted_name: full name of the identifier we are interested in
380

381
    :type context_file: str or None
382
    :param context_file:
383
      context file to consider, necessary if the identifier has been
384
      introduced using a relative import unresolvable in the actual
385
      context (i.e. modutils)
386

387

388
    :raise ImportError: if there is no such module in the directory
389

390
    :rtype: str or None
391
    :return:
392
      the module part of the name or None if we have not been able at
393
      all to import the given name
394

395
    XXX: deprecated, since it doesn't handle package precedence over module
396
    (see #10066)
397
    """
398
    # os.path trick
399
    if dotted_name.startswith('os.path'):
400
        return 'os.path'
401
    parts = dotted_name.split('.')
402
    if context_file is not None:
403
        # first check for builtin module which won't be considered latter
404
        # in that case (path != None)
405
        if parts[0] in BUILTIN_MODULES:
406
            if len(parts) > 2:
407
                raise ImportError(dotted_name)
408
            return parts[0]
409
        # don't use += or insert, we want a new list to be created !
410
    path = None
411
    starti = 0
412
    if parts[0] == '':
413
        assert context_file is not None, \
414
                'explicit relative import, but no context_file?'
415
        path = [] # prevent resolving the import non-relatively
416
        starti = 1
417
    while parts[starti] == '': # for all further dots: change context
418
        starti += 1
419
        context_file = os.path.dirname(context_file)
420
    for i in range(starti, len(parts)):
421
        try:
422
            file_from_modpath(parts[starti:i+1], path=path,
423
                              context_file=context_file)
424
        except ImportError:
425
            if not i >= max(1, len(parts) - 2):
426
                raise
427
            return '.'.join(parts[:i])
428
    return dotted_name
429

    
430

    
431
def get_module_files(src_directory, blacklist):
432
    """given a package directory return a list of all available python
433
    module's files in the package and its subpackages
434

435
    :type src_directory: str
436
    :param src_directory:
437
      path of the directory corresponding to the package
438

439
    :type blacklist: list or tuple
440
    :param blacklist: iterable
441
      list of files or directories to ignore.
442

443
    :rtype: list
444
    :return:
445
      the list of all available python module's files in the package and
446
      its subpackages
447
    """
448
    files = []
449
    for directory, dirnames, filenames in os.walk(src_directory):
450
        _handle_blacklist(blacklist, dirnames, filenames)
451
        # check for __init__.py
452
        if not '__init__.py' in filenames:
453
            dirnames[:] = ()
454
            continue
455
        for filename in filenames:
456
            if _is_python_file(filename):
457
                src = os.path.join(directory, filename)
458
                files.append(src)
459
    return files
460

    
461

    
462
def get_source_file(filename, include_no_ext=False):
463
    """given a python module's file name return the matching source file
464
    name (the filename will be returned identically if it's a already an
465
    absolute path to a python source file...)
466

467
    :type filename: str
468
    :param filename: python module's file name
469

470

471
    :raise NoSourceFile: if no source file exists on the file system
472

473
    :rtype: str
474
    :return: the absolute path of the source file if it exists
475
    """
476
    copy = getattr(filename,"copy",None)
477
    filename = os.path.abspath(_path_from_filename(filename))
478
    base, orig_ext = os.path.splitext(filename)
479
    for ext in PY_SOURCE_EXTS:
480
        source_path = '%s.%s' % (base, ext)
481
        if os.path.exists(source_path):
482
            if copy==None:
483
              return source_path
484
            return copy(source_path)
485
    if include_no_ext and not orig_ext and os.path.exists(base):
486
        return base
487
    raise NoSourceFile(filename)
488

    
489

    
490
def is_python_source(filename):
491
    """
492
    rtype: bool
493
    return: True if the filename is a python source file
494
    """
495
    return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS
496

    
497

    
498
def is_standard_module(modname, std_path=None):
499
    """try to guess if a module is a standard python module (by default,
500
    see `std_path` parameter's description)
501

502
    :type modname: str
503
    :param modname: name of the module we are interested in
504

505
    :type std_path: list(str) or tuple(str)
506
    :param std_path: list of path considered has standard
507

508

509
    :rtype: bool
510
    :return:
511
      true if the module:
512
      - is located on the path listed in one of the directory in `std_path`
513
      - is a built-in module
514
    """
515
    modname = modname.split('.')[0]
516
    try:
517
        filename = file_from_modpath([modname])
518
    except ImportError:
519
        # import failed, i'm probably not so wrong by supposing it's
520
        # not standard...
521
        return False
522
    # modules which are not living in a file are considered standard
523
    # (sys and __builtin__ for instance)
524
    if filename is None:
525
        # we assume there are no namespaces in stdlib
526
        return not _is_namespace(modname)
527
    filename = _normalize_path(filename)
528
    if filename.startswith(_cache_normalize_path(EXT_LIB_DIR)):
529
        return False
530
    if std_path is None:
531
        std_path = STD_LIB_DIRS
532
    for path in std_path:
533
        if filename.startswith(_cache_normalize_path(path)):
534
            return True
535
    return False
536

    
537

    
538

    
539
def is_relative(modname, from_file):
540
    """return true if the given module name is relative to the given
541
    file name
542

543
    :type modname: str
544
    :param modname: name of the module we are interested in
545

546
    :type from_file: str
547
    :param from_file:
548
      path of the module from which modname has been imported
549

550
    :rtype: bool
551
    :return:
552
      true if the module has been imported relatively to `from_file`
553
    """
554
    if not os.path.isdir(from_file):
555
        from_file = os.path.dirname(from_file)
556
    if from_file in sys.path:
557
        return False
558
    try:
559
        stream, _, _ = imp.find_module(modname.split('.')[0], [from_file])
560

    
561
        # Close the stream to avoid ResourceWarnings.
562
        if stream:
563
            stream.close()
564
        return True
565
    except ImportError:
566
        return False
567

    
568

    
569
# internal only functions #####################################################
570

    
571
def _file_from_modpath(modpath, path=None, context=None):
572
    """given a mod path (i.e. splitted module / package name), return the
573
    corresponding file
574

575
    this function is used internally, see `file_from_modpath`'s
576
    documentation for more information
577
    """
578
    assert len(modpath) > 0
579
    if context is not None:
580
        try:
581
            mtype, mp_filename = _module_file(modpath, [context])
582
        except ImportError:
583
            mtype, mp_filename = _module_file(modpath, path)
584
    else:
585
        mtype, mp_filename = _module_file(modpath, path)
586
    if mtype == imp.PY_COMPILED:
587
        try:
588
            return get_source_file(mp_filename), imp.PY_SOURCE
589
        except NoSourceFile:
590
            return mp_filename, imp.PY_COMPILED
591
    elif mtype == imp.C_BUILTIN:
592
        # integrated builtin module
593
        return None, imp.C_BUILTIN
594
    elif mtype == imp.PKG_DIRECTORY:
595
        mp_filename = _has_init(mp_filename)
596
        mtype = imp.PY_SOURCE
597
    return mp_filename, mtype
598

    
599
def _search_zip(modpath, pic):
600
    for filepath, importer in list(pic.items()):
601
        if importer is not None:
602
            if importer.find_module(modpath[0]):
603
                if not importer.find_module(os.path.sep.join(modpath)):
604
                    raise ImportError('No module named %s in %s/%s' % (
605
                        '.'.join(modpath[1:]), filepath, modpath))
606
                return (PY_ZIPMODULE,
607
                        os.path.abspath(filepath) + os.path.sep + os.path.sep.join(modpath),
608
                        filepath)
609
    raise ImportError('No module named %s' % '.'.join(modpath))
610

    
611
try:
612
    import pkg_resources
613
except ImportError:
614
    pkg_resources = None
615

    
616

    
617
def _is_namespace(modname):
618
    return (pkg_resources is not None
619
            and modname in pkg_resources._namespace_packages)
620

    
621

    
622
def _module_file(modpath, path=None):
623
    """get a module type / file path
624

625
    :type modpath: list or tuple
626
    :param modpath:
627
      splitted module's name (i.e name of a module or package splitted
628
      on '.'), with leading empty strings for explicit relative import
629

630
    :type path: list or None
631
    :param path:
632
      optional list of path where the module or package should be
633
      searched (use sys.path if nothing or None is given)
634

635

636
    :rtype: tuple(int, str)
637
    :return: the module type flag and the file path for a module
638
    """
639
    # egg support compat
640
    try:
641
        pic = sys.path_importer_cache
642
        _path = (path is None and sys.path or path)
643
        for __path in _path:
644
            if not __path in pic:
645
                try:
646
                    pic[__path] = zipimport.zipimporter(__path)
647
                except zipimport.ZipImportError:
648
                    pic[__path] = None
649
        checkeggs = True
650
    except AttributeError:
651
        checkeggs = False
652
    # pkg_resources support (aka setuptools namespace packages)
653
    if _is_namespace(modpath[0]) and modpath[0] in sys.modules:
654
        # setuptools has added into sys.modules a module object with proper
655
        # __path__, get back information from there
656
        module = sys.modules[modpath.pop(0)]
657
        path = module.__path__
658
        if not modpath:
659
            return imp.C_BUILTIN, None
660
    imported = []
661
    while modpath:
662
        modname = modpath[0]
663
        # take care to changes in find_module implementation wrt builtin modules
664
        #
665
        # Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23)
666
        # >>> imp.find_module('posix')
667
        # (None, 'posix', ('', '', 6))
668
        #
669
        # Python 3.3.1 (default, Apr 26 2013, 12:08:46)
670
        # >>> imp.find_module('posix')
671
        # (None, None, ('', '', 6))
672
        try:
673
            stream, mp_filename, mp_desc = imp.find_module(modname, path)
674
        except ImportError:
675
            if checkeggs:
676
                return _search_zip(modpath, pic)[:2]
677
            raise
678
        else:
679
            # Don't forget to close the stream to avoid
680
            # spurious ResourceWarnings.
681
            if stream:
682
                stream.close()
683

    
684
            if checkeggs and mp_filename:
685
                fullabspath = [_cache_normalize_path(x) for x in _path]
686
                try:
687
                    pathindex = fullabspath.index(os.path.dirname(_normalize_path(mp_filename)))
688
                    emtype, emp_filename, zippath = _search_zip(modpath, pic)
689
                    if pathindex > _path.index(zippath):
690
                        # an egg takes priority
691
                        return emtype, emp_filename
692
                except ValueError:
693
                    # XXX not in _path
694
                    pass
695
                except ImportError:
696
                    pass
697
                checkeggs = False
698
        imported.append(modpath.pop(0))
699
        mtype = mp_desc[2]
700
        if modpath:
701
            if mtype != imp.PKG_DIRECTORY:
702
                raise ImportError('No module %s in %s' % ('.'.join(modpath),
703
                                                          '.'.join(imported)))
704
            # XXX guess if package is using pkgutil.extend_path by looking for
705
            # those keywords in the first four Kbytes
706
            try:
707
                with open(os.path.join(mp_filename, '__init__.py'), 'rb') as stream:
708
                    data = stream.read(4096)
709
            except IOError:
710
                path = [mp_filename]
711
            else:
712
                extend_path = b'pkgutil' in data and b'extend_path' in data
713
                declare_namespace = (
714
                    b"pkg_resources" in data
715
                    and b"declare_namespace(__name__)" in data)
716
                if extend_path or declare_namespace:
717
                    # extend_path is called, search sys.path for module/packages
718
                    # of this name see pkgutil.extend_path documentation
719
                    path = [os.path.join(p, *imported) for p in sys.path
720
                            if os.path.isdir(os.path.join(p, *imported))]
721
                else:
722
                    path = [mp_filename]
723
    return mtype, mp_filename
724

    
725
def _is_python_file(filename):
726
    """return true if the given filename should be considered as a python file
727

728
    .pyc and .pyo are ignored
729
    """
730
    for ext in ('.py', '.so', '.pyd', '.pyw'):
731
        if filename.endswith(ext):
732
            return True
733
    return False
734

    
735

    
736
def _has_init(directory):
737
    """if the given directory has a valid __init__ file, return its path,
738
    else return None
739
    """
740
    mod_or_pack = os.path.join(directory, '__init__')
741
    for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'):
742
        if os.path.exists(mod_or_pack + '.' + ext):
743
            return mod_or_pack + '.' + ext
744
    return None