Remove reference cycle

Switches from

    powerline ↔ get_module_attr (as a bound method it contains reference to
            │       ↑            self)
            └────> theme

to

            ┌────> pl, import_paths
            │       ↑
    powerline → get_module_attr
            │       ↑
            └────> theme

This is a separate commit because I am not sure whether it makes sense to bother
with this cycle.
This commit is contained in:
ZyX 2013-04-09 00:00:28 +04:00 committed by ZyX
parent 446eb42ea8
commit bbe3210bb6

View File

@ -270,6 +270,38 @@ else:
raise exception raise exception
def gen_module_attr_getter(pl, import_paths):
def get_module_attr(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 = import_paths + sys.path
module = str(module)
attr = str(attr)
try:
return getattr(__import__(module, fromlist=(attr,)), attr)
except Exception as e:
pl.exception('Failed to import attr {0} from module {1}: {2}', attr, module, str(e), prefix=prefix)
return None
finally:
sys.path = oldpath
return get_module_attr
class Powerline(object): class Powerline(object):
'''Main powerline class, entrance point for all powerline uses. Sets '''Main powerline class, entrance point for all powerline uses. Sets
powerline up and loads the configuration. powerline up and loads the configuration.
@ -396,6 +428,8 @@ class Powerline(object):
if not self.run_once: if not self.run_once:
self.config_loader.set_watcher(self.common_config['watcher']) self.config_loader.set_watcher(self.common_config['watcher'])
self.get_module_attr = gen_module_attr_getter(self.pl, self.import_paths)
self.renderer_options.update( self.renderer_options.update(
pl=self.pl, pl=self.pl,
term_truecolor=self.common_config['term_truecolor'], term_truecolor=self.common_config['term_truecolor'],
@ -407,8 +441,6 @@ 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, 'get_module_attr': self.get_module_attr,
}, },
) )
@ -656,34 +688,6 @@ 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()``.