Replace various __import__ calls with one Powerline.get_module_attr

Also makes some more errors non-fatal:
- Failure to import renderer class in case there is an existing renderer object
- Failure to import segment function
- Failure to import matcher function

One of the purposes: create a function that is able to collect all imported
modules to reload them (really purge out from `sys.modules` and let the python
do its job when reimporting powerline and recreating Powerline and other
objects).
This commit is contained in:
ZyX 2013-04-08 23:46:29 +04:00 committed by ZyX
parent c2c2d7efca
commit 446eb42ea8
5 changed files with 64 additions and 42 deletions

View File

@ -407,6 +407,9 @@ class Powerline(object):
'common_config': self.common_config, 'common_config': self.common_config,
'run_once': self.run_once, 'run_once': self.run_once,
'shutdown_event': self.shutdown_event, 'shutdown_event': self.shutdown_event,
# Note: creates implicit reference to self meaning
# reference cycle.
'get_module_attr': self.get_module_attr,
}, },
) )
@ -468,11 +471,12 @@ class Powerline(object):
self.renderer_options['theme_config'] = self.load_theme_config(self.ext_config.get('theme', 'default')) self.renderer_options['theme_config'] = self.load_theme_config(self.ext_config.get('theme', 'default'))
if create_renderer: if create_renderer:
try: Renderer = self.get_module_attr(self.renderer_module, 'renderer')
Renderer = __import__(self.renderer_module, fromlist=['renderer']).renderer if not Renderer:
except Exception as e: if hasattr(self, 'renderer'):
self.exception('Failed to import renderer module: {0}', str(e)) return
sys.exit(1) else:
raise ImportError('Failed to obtain renderer')
# Renderer updates configuration file via segments .startup thus it # Renderer updates configuration file via segments .startup thus it
# should be locked to prevent state when configuration was updated, # should be locked to prevent state when configuration was updated,
@ -652,6 +656,34 @@ class Powerline(object):
with self.cr_kwargs_lock: with self.cr_kwargs_lock:
self.cr_kwargs.clear() self.cr_kwargs.clear()
def get_module_attr(self, module, attr, prefix='powerline'):
'''Import module and get its attribute.
Replaces ``from {module} import {attr}``.
:param str module:
Module name, will be passed as first argument to ``__import__``.
:param str attr:
Module attribute, will be passed to ``__import__`` as the only value
in ``fromlist`` tuple.
:return:
Attribute value or ``None``. Note: there is no way to distinguish
between successfull import of attribute equal to ``None`` and
unsuccessfull import.
'''
oldpath = sys.path
sys.path = self.import_paths + sys.path
module = str(module)
attr = str(attr)
try:
return getattr(__import__(module, fromlist=(attr,)), attr)
except Exception as e:
self.pl.exception('Failed to import attr {0} from module {1}: {2}', attr, module, str(e), prefix=prefix)
return None
finally:
sys.path = oldpath
def render(self, *args, **kwargs): def render(self, *args, **kwargs):
'''Update/create renderer if needed and pass all arguments further to '''Update/create renderer if needed and pass all arguments further to
``self.renderer.render()``. ``self.renderer.render()``.

View File

@ -1,19 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import
import sys
def gen_matcher_getter(ext, import_paths):
def get(match_name):
match_module, separator, match_function = match_name.rpartition('.')
if not separator:
match_module = 'powerline.matchers.{0}'.format(ext)
match_function = match_name
oldpath = sys.path
sys.path = import_paths + sys.path
try:
return getattr(__import__(str(match_module), fromlist=[str(match_function)]), match_function)
finally:
sys.path = oldpath
return get

View File

@ -55,14 +55,11 @@ def get_segment_key(merge, *args, **kwargs):
def get_function(data, segment): def get_function(data, segment):
oldpath = sys.path
sys.path = data['path'] + sys.path
segment_module = str(segment.get('module', data['default_module'])) segment_module = str(segment.get('module', data['default_module']))
name = str(segment['name']) function = data['get_module_attr'](segment_module, segment['name'], prefix='segment_generator')
try: if not function:
return None, getattr(__import__(segment_module, fromlist=[name]), name), segment_module raise ImportError('Failed to obtain segment function')
finally: return None, function, segment_module
sys.path = oldpath
def get_string(data, segment): def get_string(data, segment):
@ -162,10 +159,10 @@ def process_segment(pl, side, segment_info, parsed_segments, segment):
parsed_segments.append(segment) parsed_segments.append(segment)
def gen_segment_getter(pl, ext, common_config, theme_configs, default_module=None): def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, get_module_attr):
data = { data = {
'default_module': default_module or 'powerline.segments.' + ext, 'default_module': default_module or 'powerline.segments.' + ext,
'path': common_config['paths'], 'get_module_attr': get_module_attr,
} }
def get_key(merge, segment, module, key, default=None): def get_key(merge, segment, module, key, default=None):

View File

@ -29,6 +29,7 @@ class Theme(object):
theme_config, theme_config,
common_config, common_config,
pl, pl,
get_module_attr,
main_theme_config=None, main_theme_config=None,
run_once=False, run_once=False,
shutdown_event=None): shutdown_event=None):
@ -53,7 +54,7 @@ class Theme(object):
theme_configs = [theme_config] theme_configs = [theme_config]
if main_theme_config: if main_theme_config:
theme_configs.append(main_theme_config) theme_configs.append(main_theme_config)
get_segment = gen_segment_getter(pl, ext, common_config, theme_configs, theme_config.get('default_module')) get_segment = gen_segment_getter(pl, ext, common_config, theme_configs, theme_config.get('default_module'), get_module_attr)
for segdict in itertools.chain((theme_config['segments'],), for segdict in itertools.chain((theme_config['segments'],),
theme_config['segments'].get('above', ())): theme_config['segments'].get('above', ())):
self.segments.append(new_empty_segment_line()) self.segments.append(new_empty_segment_line())

View File

@ -6,7 +6,6 @@ import sys
from powerline.bindings.vim import vim_get_func, vim_getvar from powerline.bindings.vim import vim_get_func, vim_getvar
from powerline import Powerline from powerline import Powerline
from powerline.lib import mergedicts from powerline.lib import mergedicts
from powerline.matcher import gen_matcher_getter
import vim import vim
from itertools import count from itertools import count
@ -80,18 +79,30 @@ class VimPowerline(Powerline):
) )
def get_local_themes(self, local_themes): def get_local_themes(self, local_themes):
self.get_matcher = gen_matcher_getter(self.ext, self.import_paths)
if not local_themes: if not local_themes:
return {} return {}
return dict(( return dict((
( (matcher, {'config': self.load_theme_config(val)})
(None if key == '__tabline__' else self.get_matcher(key)), for matcher, key, val in (
{'config': self.load_theme_config(val)} (
(None if k == '__tabline__' else self.get_matcher(k)),
k,
v
)
for k, v in local_themes.items()
) if (
matcher or
key == '__tabline__'
) )
for key, val in local_themes.items()) ))
)
def get_matcher(self, match_name):
match_module, separator, match_function = match_name.rpartition('.')
if not separator:
match_module = 'powerline.matchers.{0}'.format(self.ext)
match_function = match_name
return self.get_module_attr(match_module, match_function, prefix='matcher_generator')
def get_config_paths(self): def get_config_paths(self):
try: try: