1# Copyright (c) 2018 gevent community 2# 3# Permission is hereby granted, free of charge, to any person obtaining a copy 4# of this software and associated documentation files (the "Software"), to deal 5# in the Software without restriction, including without limitation the rights 6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7# copies of the Software, and to permit persons to whom the Software is 8# furnished to do so, subject to the following conditions: 9# 10# The above copyright notice and this permission notice shall be included in 11# all copies or substantial portions of the Software. 12# 13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19# THE SOFTWARE. 20from __future__ import absolute_import, print_function, division 21 22import importlib 23import os.path 24import warnings 25 26import gevent 27 28from . import sysinfo 29from . import util 30 31 32OPTIONAL_MODULES = frozenset({ 33 ## Resolvers. 34 # ares might not be built 35 'gevent.resolver_ares', 36 'gevent.resolver.ares', 37 # dnspython might not be installed 38 'gevent.resolver.dnspython', 39 ## Backends 40 'gevent.libev', 41 'gevent.libev.watcher', 42 'gevent.libuv.loop', 43 'gevent.libuv.watcher', 44}) 45 46EXCLUDED_MODULES = frozenset({ 47 '__init__', 48 'core', 49 'ares', 50 '_util', 51 '_semaphore', 52 'corecffi', 53 '_corecffi', 54 '_corecffi_build', 55}) 56 57def walk_modules( 58 basedir=None, 59 modpath=None, 60 include_so=False, 61 recursive=False, 62 check_optional=True, 63 include_tests=False, 64 optional_modules=OPTIONAL_MODULES, 65 excluded_modules=EXCLUDED_MODULES, 66): 67 """ 68 Find gevent modules, yielding tuples of ``(path, importable_module_name)``. 69 70 :keyword bool check_optional: If true (the default), then if we discover a 71 module that is known to be optional on this system (such as a backend), 72 we will attempt to import it; if the import fails, it will not be returned. 73 If false, then we will not make such an attempt, the caller will need to be prepared 74 for an `ImportError`; the caller can examine *optional_modules* against 75 the yielded *importable_module_name*. 76 """ 77 # pylint:disable=too-many-branches 78 if sysinfo.PYPY: 79 include_so = False 80 if basedir is None: 81 basedir = os.path.dirname(gevent.__file__) 82 if modpath is None: 83 modpath = 'gevent.' 84 else: 85 if modpath is None: 86 modpath = '' 87 88 for fn in sorted(os.listdir(basedir)): 89 path = os.path.join(basedir, fn) 90 if os.path.isdir(path): 91 if not recursive: 92 continue 93 if not include_tests and fn in ['testing', 'tests']: 94 continue 95 pkg_init = os.path.join(path, '__init__.py') 96 if os.path.exists(pkg_init): 97 yield pkg_init, modpath + fn 98 for p, m in walk_modules( 99 path, modpath + fn + ".", 100 include_so=include_so, 101 recursive=recursive, 102 check_optional=check_optional, 103 include_tests=include_tests, 104 optional_modules=optional_modules, 105 excluded_modules=excluded_modules, 106 ): 107 yield p, m 108 continue 109 110 if fn.endswith('.py'): 111 x = fn[:-3] 112 if x.endswith('_d'): 113 x = x[:-2] 114 if x in excluded_modules: 115 continue 116 modname = modpath + x 117 if check_optional and modname in optional_modules: 118 try: 119 with warnings.catch_warnings(): 120 warnings.simplefilter('ignore', DeprecationWarning) 121 importlib.import_module(modname) 122 except ImportError: 123 util.debug("Unable to import optional module %s", modname) 124 continue 125 yield path, modname 126 elif include_so and fn.endswith(sysinfo.SHARED_OBJECT_EXTENSION): 127 if '.pypy-' in fn: 128 continue 129 if fn.endswith('_d.so'): 130 yield path, modpath + fn[:-5] 131 else: 132 yield path, modpath + fn[:-3] 133