mirror of
https://github.com/powerline/powerline.git
synced 2025-07-25 23:05:32 +02:00
commit
a4e8f36f36
@ -10,10 +10,43 @@ from powerline.lib.config import ConfigLoader
|
|||||||
|
|
||||||
from threading import Lock, Event
|
from threading import Lock, Event
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unicode
|
||||||
|
except ImportError:
|
||||||
|
unicode = str # NOQA
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_SYSTEM_CONFIG_DIR = None
|
DEFAULT_SYSTEM_CONFIG_DIR = None
|
||||||
|
|
||||||
|
|
||||||
|
def safe_unicode(s):
|
||||||
|
'''Return unicode instance without raising an exception.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
return unicode(s)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
try:
|
||||||
|
return unicode(s, 'utf-8')
|
||||||
|
except TypeError:
|
||||||
|
return unicode(str(s), 'utf-8')
|
||||||
|
except Exception as e:
|
||||||
|
return safe_unicode(e)
|
||||||
|
|
||||||
|
|
||||||
|
class FailedUnicode(unicode):
|
||||||
|
'''Builtin ``unicode`` (``str`` in python 3) subclass indicating fatal
|
||||||
|
error.
|
||||||
|
|
||||||
|
If your code for some reason wants to determine whether `.render()` method
|
||||||
|
failed it should check returned string for being a FailedUnicode instance.
|
||||||
|
Alternatively you could subclass Powerline and override `.render()` method
|
||||||
|
to do what you like in place of catching the exception and returning
|
||||||
|
FailedUnicode.
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def find_config_file(search_paths, config_file):
|
def find_config_file(search_paths, config_file):
|
||||||
config_file += '.json'
|
config_file += '.json'
|
||||||
for path in search_paths:
|
for path in search_paths:
|
||||||
@ -61,6 +94,29 @@ class PowerlineLogger(object):
|
|||||||
self._log('debug', msg, *args, **kwargs)
|
self._log('debug', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
_fallback_logger = None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_fallback_logger():
|
||||||
|
global _fallback_logger
|
||||||
|
if _fallback_logger:
|
||||||
|
return _fallback_logger
|
||||||
|
|
||||||
|
log_format = '%(asctime)s:%(levelname)s:%(message)s'
|
||||||
|
formatter = logging.Formatter(log_format)
|
||||||
|
|
||||||
|
level = logging.WARNING
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
handler.setLevel(level)
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
logger = logging.getLogger('powerline')
|
||||||
|
logger.setLevel(level)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
_fallback_logger = PowerlineLogger(None, logger, '_fallback_')
|
||||||
|
return _fallback_logger
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
@ -233,7 +289,7 @@ class Powerline(object):
|
|||||||
try:
|
try:
|
||||||
Renderer = __import__(self.renderer_module, fromlist=['renderer']).renderer
|
Renderer = __import__(self.renderer_module, fromlist=['renderer']).renderer
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.pl.exception('Failed to import renderer module: {0}', str(e))
|
self.exception('Failed to import renderer module: {0}', str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Renderer updates configuration file via segments’ .startup thus it
|
# Renderer updates configuration file via segments’ .startup thus it
|
||||||
@ -242,7 +298,7 @@ class Powerline(object):
|
|||||||
try:
|
try:
|
||||||
renderer = Renderer(**self.renderer_options)
|
renderer = Renderer(**self.renderer_options)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.pl.exception('Failed to construct renderer object: {0}', str(e))
|
self.exception('Failed to construct renderer object: {0}', str(e))
|
||||||
if not hasattr(self, 'renderer'):
|
if not hasattr(self, 'renderer'):
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
@ -360,16 +416,34 @@ class Powerline(object):
|
|||||||
try:
|
try:
|
||||||
self.create_renderer(**create_renderer_kwargs)
|
self.create_renderer(**create_renderer_kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.pl.exception('Failed to create renderer: {0}', str(e))
|
self.exception('Failed to create renderer: {0}', str(e))
|
||||||
finally:
|
if hasattr(self, 'renderer'):
|
||||||
self.create_renderer_kwargs.clear()
|
with self.cr_kwargs_lock:
|
||||||
|
self.create_renderer_kwargs.clear()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
with self.cr_kwargs_lock:
|
||||||
|
self.create_renderer_kwargs.clear()
|
||||||
|
|
||||||
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()``.
|
||||||
'''
|
'''
|
||||||
self.update_renderer()
|
try:
|
||||||
return self.renderer.render(*args, **kwargs)
|
self.update_renderer()
|
||||||
|
return self.renderer.render(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
self.exception('Failed to render: {0}', str(e))
|
||||||
|
except Exception as e:
|
||||||
|
# Updates e variable to new value, masking previous one.
|
||||||
|
# Normally it is the same exception (due to raise in case pl is
|
||||||
|
# unset), but it may also show error in logger. Note that latter
|
||||||
|
# is not logged by logger for obvious reasons, thus this also
|
||||||
|
# prevents us from seeing logger traceback.
|
||||||
|
pass
|
||||||
|
return FailedUnicode(safe_unicode(e))
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
'''Shut down all background threads. Must be run only prior to exiting
|
'''Shut down all background threads. Must be run only prior to exiting
|
||||||
@ -410,3 +484,9 @@ class Powerline(object):
|
|||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
|
||||||
|
def exception(self, msg, *args, **kwargs):
|
||||||
|
if 'prefix' not in kwargs:
|
||||||
|
kwargs['prefix'] = 'powerline'
|
||||||
|
pl = getattr(self, 'pl', None) or _get_fallback_logger()
|
||||||
|
return pl.exception(msg, *args, **kwargs)
|
||||||
|
@ -155,6 +155,10 @@ class ConfigLoader(MultiRunnedThread):
|
|||||||
try:
|
try:
|
||||||
self.loaded[path] = deepcopy(self._load(path))
|
self.loaded[path] = deepcopy(self._load(path))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
self.loaded.pop(path)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
self.exception('Error while loading {0}: {1}', path, str(e))
|
self.exception('Error while loading {0}: {1}', path, str(e))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -707,13 +707,13 @@ class NetworkLoadSegment(KwThreadedSegment):
|
|||||||
total = activity
|
total = activity
|
||||||
interface = name
|
interface = name
|
||||||
|
|
||||||
if interface in self.interfaces:
|
try:
|
||||||
idata = self.interfaces[interface]
|
idata = self.interfaces[interface]
|
||||||
try:
|
try:
|
||||||
idata['prev'] = idata['last']
|
idata['prev'] = idata['last']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
else:
|
except KeyError:
|
||||||
idata = {}
|
idata = {}
|
||||||
if self.run_once:
|
if self.run_once:
|
||||||
idata['prev'] = (monotonic(), _get_bytes(interface))
|
idata['prev'] = (monotonic(), _get_bytes(interface))
|
||||||
|
@ -141,7 +141,7 @@ class TestConfigReload(TestCase):
|
|||||||
self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>')
|
self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>')
|
||||||
self.assertAccessEvents('config', 'themes/test/nonexistent')
|
self.assertAccessEvents('config', 'themes/test/nonexistent')
|
||||||
# It should normally handle file missing error
|
# It should normally handle file missing error
|
||||||
self.assertEqual(p.logger._pop_msgs(), ['exception:test:Failed to create renderer: themes/test/nonexistent'])
|
self.assertEqual(p.logger._pop_msgs(), ['exception:test:powerline:Failed to create renderer: themes/test/nonexistent'])
|
||||||
|
|
||||||
config['config']['ext']['test']['theme'] = 'default'
|
config['config']['ext']['test']['theme'] = 'default'
|
||||||
add_watcher_events(p, 'config')
|
add_watcher_events(p, 'config')
|
||||||
@ -154,7 +154,7 @@ class TestConfigReload(TestCase):
|
|||||||
self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>')
|
self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>><None None None>')
|
||||||
self.assertAccessEvents('config', 'colorschemes/test/nonexistent')
|
self.assertAccessEvents('config', 'colorschemes/test/nonexistent')
|
||||||
# It should normally handle file missing error
|
# It should normally handle file missing error
|
||||||
self.assertEqual(p.logger._pop_msgs(), ['exception:test:Failed to create renderer: colorschemes/test/nonexistent'])
|
self.assertEqual(p.logger._pop_msgs(), ['exception:test:powerline:Failed to create renderer: colorschemes/test/nonexistent'])
|
||||||
|
|
||||||
config['config']['ext']['test']['colorscheme'] = '2'
|
config['config']['ext']['test']['colorscheme'] = '2'
|
||||||
add_watcher_events(p, 'config')
|
add_watcher_events(p, 'config')
|
||||||
@ -187,7 +187,7 @@ class TestConfigReload(TestCase):
|
|||||||
add_watcher_events(p, 'config')
|
add_watcher_events(p, 'config')
|
||||||
self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>')
|
self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>><None None None>')
|
||||||
self.assertAccessEvents('config')
|
self.assertAccessEvents('config')
|
||||||
self.assertIn('exception:test:Failed to create renderer: fcf:colorschemes/test/nonexistentraise', p.logger._pop_msgs())
|
self.assertIn('exception:test:powerline:Failed to create renderer: fcf:colorschemes/test/nonexistentraise', p.logger._pop_msgs())
|
||||||
|
|
||||||
config['colorschemes/test/nonexistentraise'] = {
|
config['colorschemes/test/nonexistentraise'] = {
|
||||||
'groups': {
|
'groups': {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user