laywerrobot/lib/python3.6/site-packages/numpy/_import_tools.py

352 lines
13 KiB
Python
Raw Normal View History

2020-08-27 21:55:39 +02:00
from __future__ import division, absolute_import, print_function
import os
import sys
import warnings
__all__ = ['PackageLoader']
class PackageLoader(object):
def __init__(self, verbose=False, infunc=False):
""" Manages loading packages.
"""
if infunc:
_level = 2
else:
_level = 1
self.parent_frame = frame = sys._getframe(_level)
self.parent_name = eval('__name__', frame.f_globals, frame.f_locals)
parent_path = eval('__path__', frame.f_globals, frame.f_locals)
if isinstance(parent_path, str):
parent_path = [parent_path]
self.parent_path = parent_path
if '__all__' not in frame.f_locals:
exec('__all__ = []', frame.f_globals, frame.f_locals)
self.parent_export_names = eval('__all__', frame.f_globals, frame.f_locals)
self.info_modules = {}
self.imported_packages = []
self.verbose = None
def _get_info_files(self, package_dir, parent_path, parent_package=None):
""" Return list of (package name,info.py file) from parent_path subdirectories.
"""
from glob import glob
files = glob(os.path.join(parent_path, package_dir, 'info.py'))
for info_file in glob(os.path.join(parent_path, package_dir, 'info.pyc')):
if info_file[:-1] not in files:
files.append(info_file)
info_files = []
for info_file in files:
package_name = os.path.dirname(info_file[len(parent_path)+1:])\
.replace(os.sep, '.')
if parent_package:
package_name = parent_package + '.' + package_name
info_files.append((package_name, info_file))
info_files.extend(self._get_info_files('*',
os.path.dirname(info_file),
package_name))
return info_files
def _init_info_modules(self, packages=None):
"""Initialize info_modules = {<package_name>: <package info.py module>}.
"""
from numpy.compat import npy_load_module
info_files = []
info_modules = self.info_modules
if packages is None:
for path in self.parent_path:
info_files.extend(self._get_info_files('*', path))
else:
for package_name in packages:
package_dir = os.path.join(*package_name.split('.'))
for path in self.parent_path:
names_files = self._get_info_files(package_dir, path)
if names_files:
info_files.extend(names_files)
break
else:
try:
exec('import %s.info as info' % (package_name))
info_modules[package_name] = info
except ImportError as msg:
self.warn('No scipy-style subpackage %r found in %s. '\
'Ignoring: %s'\
% (package_name, ':'.join(self.parent_path), msg))
for package_name, info_file in info_files:
if package_name in info_modules:
continue
fullname = self.parent_name +'.'+ package_name
if info_file[-1]=='c':
filedescriptor = ('.pyc', 'rb', 2)
else:
filedescriptor = ('.py', 'U', 1)
try:
info_module = npy_load_module(fullname + '.info',
info_file,
filedescriptor)
except Exception as msg:
self.error(msg)
info_module = None
if info_module is None or getattr(info_module, 'ignore', False):
info_modules.pop(package_name, None)
else:
self._init_info_modules(getattr(info_module, 'depends', []))
info_modules[package_name] = info_module
return
def _get_sorted_names(self):
""" Return package names sorted in the order as they should be
imported due to dependence relations between packages.
"""
depend_dict = {}
for name, info_module in self.info_modules.items():
depend_dict[name] = getattr(info_module, 'depends', [])
package_names = []
for name in list(depend_dict.keys()):
if not depend_dict[name]:
package_names.append(name)
del depend_dict[name]
while depend_dict:
for name, lst in list(depend_dict.items()):
new_lst = [n for n in lst if n in depend_dict]
if not new_lst:
package_names.append(name)
del depend_dict[name]
else:
depend_dict[name] = new_lst
return package_names
def __call__(self,*packages, **options):
"""Load one or more packages into parent package top-level namespace.
This function is intended to shorten the need to import many
subpackages, say of scipy, constantly with statements such as
import scipy.linalg, scipy.fftpack, scipy.etc...
Instead, you can say:
import scipy
scipy.pkgload('linalg','fftpack',...)
or
scipy.pkgload()
to load all of them in one call.
If a name which doesn't exist in scipy's namespace is
given, a warning is shown.
Parameters
----------
*packages : arg-tuple
the names (one or more strings) of all the modules one
wishes to load into the top-level namespace.
verbose= : integer
verbosity level [default: -1].
verbose=-1 will suspend also warnings.
force= : bool
when True, force reloading loaded packages [default: False].
postpone= : bool
when True, don't load packages [default: False]
"""
# 2014-10-29, 1.10
warnings.warn('pkgload and PackageLoader are obsolete '
'and will be removed in a future version of numpy',
DeprecationWarning, stacklevel=2)
frame = self.parent_frame
self.info_modules = {}
if options.get('force', False):
self.imported_packages = []
self.verbose = verbose = options.get('verbose', -1)
postpone = options.get('postpone', None)
self._init_info_modules(packages or None)
self.log('Imports to %r namespace\n----------------------------'\
% self.parent_name)
for package_name in self._get_sorted_names():
if package_name in self.imported_packages:
continue
info_module = self.info_modules[package_name]
global_symbols = getattr(info_module, 'global_symbols', [])
postpone_import = getattr(info_module, 'postpone_import', False)
if (postpone and not global_symbols) \
or (postpone_import and postpone is not None):
continue
old_object = frame.f_locals.get(package_name, None)
cmdstr = 'import '+package_name
if self._execcmd(cmdstr):
continue
self.imported_packages.append(package_name)
if verbose!=-1:
new_object = frame.f_locals.get(package_name)
if old_object is not None and old_object is not new_object:
self.warn('Overwriting %s=%s (was %s)' \
% (package_name, self._obj2repr(new_object),
self._obj2repr(old_object)))
if '.' not in package_name:
self.parent_export_names.append(package_name)
for symbol in global_symbols:
if symbol=='*':
symbols = eval('getattr(%s,"__all__",None)'\
% (package_name),
frame.f_globals, frame.f_locals)
if symbols is None:
symbols = eval('dir(%s)' % (package_name),
frame.f_globals, frame.f_locals)
symbols = [s for s in symbols if not s.startswith('_')]
else:
symbols = [symbol]
if verbose!=-1:
old_objects = {}
for s in symbols:
if s in frame.f_locals:
old_objects[s] = frame.f_locals[s]
cmdstr = 'from '+package_name+' import '+symbol
if self._execcmd(cmdstr):
continue
if verbose!=-1:
for s, old_object in old_objects.items():
new_object = frame.f_locals[s]
if new_object is not old_object:
self.warn('Overwriting %s=%s (was %s)' \
% (s, self._obj2repr(new_object),
self._obj2repr(old_object)))
if symbol=='*':
self.parent_export_names.extend(symbols)
else:
self.parent_export_names.append(symbol)
return
def _execcmd(self, cmdstr):
""" Execute command in parent_frame."""
frame = self.parent_frame
try:
exec (cmdstr, frame.f_globals, frame.f_locals)
except Exception as msg:
self.error('%s -> failed: %s' % (cmdstr, msg))
return True
else:
self.log('%s -> success' % (cmdstr))
return
def _obj2repr(self, obj):
""" Return repr(obj) with"""
module = getattr(obj, '__module__', None)
file = getattr(obj, '__file__', None)
if module is not None:
return repr(obj) + ' from ' + module
if file is not None:
return repr(obj) + ' from ' + file
return repr(obj)
def log(self, mess):
if self.verbose>1:
print(str(mess), file=sys.stderr)
def warn(self, mess):
if self.verbose>=0:
print(str(mess), file=sys.stderr)
def error(self, mess):
if self.verbose!=-1:
print(str(mess), file=sys.stderr)
def _get_doc_title(self, info_module):
""" Get the title from a package info.py file.
"""
title = getattr(info_module, '__doc_title__', None)
if title is not None:
return title
title = getattr(info_module, '__doc__', None)
if title is not None:
title = title.lstrip().split('\n', 1)[0]
return title
return '* Not Available *'
def _format_titles(self,titles,colsep='---'):
display_window_width = 70 # How to determine the correct value in runtime??
lengths = [len(name)-name.find('.')-1 for (name, title) in titles]+[0]
max_length = max(lengths)
lines = []
for (name, title) in titles:
name = name[name.find('.')+1:]
w = max_length - len(name)
words = title.split()
line = '%s%s %s' % (name, w*' ', colsep)
tab = len(line) * ' '
while words:
word = words.pop(0)
if len(line)+len(word)>display_window_width:
lines.append(line)
line = tab
line += ' ' + word
lines.append(line)
return '\n'.join(lines)
def get_pkgdocs(self):
""" Return documentation summary of subpackages.
"""
import sys
self.info_modules = {}
self._init_info_modules(None)
titles = []
symbols = []
for package_name, info_module in self.info_modules.items():
global_symbols = getattr(info_module, 'global_symbols', [])
fullname = self.parent_name +'.'+ package_name
note = ''
if fullname not in sys.modules:
note = ' [*]'
titles.append((fullname, self._get_doc_title(info_module) + note))
if global_symbols:
symbols.append((package_name, ', '.join(global_symbols)))
retstr = self._format_titles(titles) +\
'\n [*] - using a package requires explicit import (see pkgload)'
if symbols:
retstr += """\n\nGlobal symbols from subpackages"""\
"""\n-------------------------------\n""" +\
self._format_titles(symbols, '-->')
return retstr
class PackageLoaderDebug(PackageLoader):
def _execcmd(self, cmdstr):
""" Execute command in parent_frame."""
frame = self.parent_frame
print('Executing', repr(cmdstr), '...', end=' ')
sys.stdout.flush()
exec (cmdstr, frame.f_globals, frame.f_locals)
print('ok')
sys.stdout.flush()
return
if int(os.environ.get('NUMPY_IMPORT_DEBUG', '0')):
PackageLoader = PackageLoaderDebug