| | """Tools to assist importing optional external modules.""" |
| |
|
| | import sys |
| | import re |
| |
|
| | |
| | |
| | |
| |
|
| | WARN_NOT_INSTALLED = None |
| | WARN_OLD_VERSION = None |
| |
|
| |
|
| | def __sympy_debug(): |
| | |
| | |
| | |
| | import os |
| | debug_str = os.getenv('SYMPY_DEBUG', 'False') |
| | if debug_str in ('True', 'False'): |
| | return eval(debug_str) |
| | else: |
| | raise RuntimeError("unrecognized value for SYMPY_DEBUG: %s" % |
| | debug_str) |
| |
|
| | if __sympy_debug(): |
| | WARN_OLD_VERSION = True |
| | WARN_NOT_INSTALLED = True |
| |
|
| |
|
| | _component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) |
| |
|
| | def version_tuple(vstring): |
| | |
| | |
| | |
| | components = [] |
| | for x in _component_re.split(vstring): |
| | if x and x != '.': |
| | try: |
| | x = int(x) |
| | except ValueError: |
| | pass |
| | components.append(x) |
| | return tuple(components) |
| |
|
| |
|
| | def import_module(module, min_module_version=None, min_python_version=None, |
| | warn_not_installed=None, warn_old_version=None, |
| | module_version_attr='__version__', module_version_attr_call_args=None, |
| | import_kwargs={}, catch=()): |
| | """ |
| | Import and return a module if it is installed. |
| | |
| | If the module is not installed, it returns None. |
| | |
| | A minimum version for the module can be given as the keyword argument |
| | min_module_version. This should be comparable against the module version. |
| | By default, module.__version__ is used to get the module version. To |
| | override this, set the module_version_attr keyword argument. If the |
| | attribute of the module to get the version should be called (e.g., |
| | module.version()), then set module_version_attr_call_args to the args such |
| | that module.module_version_attr(*module_version_attr_call_args) returns the |
| | module's version. |
| | |
| | If the module version is less than min_module_version using the Python < |
| | comparison, None will be returned, even if the module is installed. You can |
| | use this to keep from importing an incompatible older version of a module. |
| | |
| | You can also specify a minimum Python version by using the |
| | min_python_version keyword argument. This should be comparable against |
| | sys.version_info. |
| | |
| | If the keyword argument warn_not_installed is set to True, the function will |
| | emit a UserWarning when the module is not installed. |
| | |
| | If the keyword argument warn_old_version is set to True, the function will |
| | emit a UserWarning when the library is installed, but cannot be imported |
| | because of the min_module_version or min_python_version options. |
| | |
| | Note that because of the way warnings are handled, a warning will be |
| | emitted for each module only once. You can change the default warning |
| | behavior by overriding the values of WARN_NOT_INSTALLED and WARN_OLD_VERSION |
| | in sympy.external.importtools. By default, WARN_NOT_INSTALLED is False and |
| | WARN_OLD_VERSION is True. |
| | |
| | This function uses __import__() to import the module. To pass additional |
| | options to __import__(), use the import_kwargs keyword argument. For |
| | example, to import a submodule A.B, you must pass a nonempty fromlist option |
| | to __import__. See the docstring of __import__(). |
| | |
| | This catches ImportError to determine if the module is not installed. To |
| | catch additional errors, pass them as a tuple to the catch keyword |
| | argument. |
| | |
| | Examples |
| | ======== |
| | |
| | >>> from sympy.external import import_module |
| | |
| | >>> numpy = import_module('numpy') |
| | |
| | >>> numpy = import_module('numpy', min_python_version=(2, 7), |
| | ... warn_old_version=False) |
| | |
| | >>> numpy = import_module('numpy', min_module_version='1.5', |
| | ... warn_old_version=False) # numpy.__version__ is a string |
| | |
| | >>> # gmpy does not have __version__, but it does have gmpy.version() |
| | |
| | >>> gmpy = import_module('gmpy', min_module_version='1.14', |
| | ... module_version_attr='version', module_version_attr_call_args=(), |
| | ... warn_old_version=False) |
| | |
| | >>> # To import a submodule, you must pass a nonempty fromlist to |
| | >>> # __import__(). The values do not matter. |
| | >>> p3 = import_module('mpl_toolkits.mplot3d', |
| | ... import_kwargs={'fromlist':['something']}) |
| | |
| | >>> # matplotlib.pyplot can raise RuntimeError when the display cannot be opened |
| | >>> matplotlib = import_module('matplotlib', |
| | ... import_kwargs={'fromlist':['pyplot']}, catch=(RuntimeError,)) |
| | |
| | """ |
| | |
| | |
| | warn_old_version = (WARN_OLD_VERSION if WARN_OLD_VERSION is not None |
| | else warn_old_version or True) |
| | warn_not_installed = (WARN_NOT_INSTALLED if WARN_NOT_INSTALLED is not None |
| | else warn_not_installed or False) |
| |
|
| | import warnings |
| |
|
| | |
| | if min_python_version: |
| | if sys.version_info < min_python_version: |
| | if warn_old_version: |
| | warnings.warn("Python version is too old to use %s " |
| | "(%s or newer required)" % ( |
| | module, '.'.join(map(str, min_python_version))), |
| | UserWarning, stacklevel=2) |
| | return |
| |
|
| | try: |
| | mod = __import__(module, **import_kwargs) |
| |
|
| | |
| | |
| | |
| | |
| | from_list = import_kwargs.get('fromlist', ()) |
| | for submod in from_list: |
| | if submod == 'collections' and mod.__name__ == 'matplotlib': |
| | __import__(module + '.' + submod) |
| | except ImportError: |
| | if warn_not_installed: |
| | warnings.warn("%s module is not installed" % module, UserWarning, |
| | stacklevel=2) |
| | return |
| | except catch as e: |
| | if warn_not_installed: |
| | warnings.warn( |
| | "%s module could not be used (%s)" % (module, repr(e)), |
| | stacklevel=2) |
| | return |
| |
|
| | if min_module_version: |
| | modversion = getattr(mod, module_version_attr) |
| | if module_version_attr_call_args is not None: |
| | modversion = modversion(*module_version_attr_call_args) |
| | if version_tuple(modversion) < version_tuple(min_module_version): |
| | if warn_old_version: |
| | |
| | if isinstance(min_module_version, str): |
| | verstr = min_module_version |
| | elif isinstance(min_module_version, (tuple, list)): |
| | verstr = '.'.join(map(str, min_module_version)) |
| | else: |
| | |
| | |
| | verstr = str(min_module_version) |
| | warnings.warn("%s version is too old to use " |
| | "(%s or newer required)" % (module, verstr), |
| | UserWarning, stacklevel=2) |
| | return |
| |
|
| | return mod |
| |
|