Merge pull request #147 from teto/log_stderr

Log stderr
This commit is contained in:
enkore 2014-12-18 19:01:40 +01:00
commit b374901642
8 changed files with 93 additions and 26 deletions

View File

@ -2,13 +2,13 @@
python3 --version python3 --version
py.test --version py.test --version
pep8 --version python3 -mpep8 --version
# Target directory for all build files # Target directory for all build files
BUILD=${1:-ci-build} BUILD=${1:-ci-build}
mkdir -p $BUILD mkdir -p $BUILD
pep8 --ignore E501 i3pystatus tests python3 -mpep8 --ignore E501 i3pystatus tests
# Check that the setup.py script works # Check that the setup.py script works
rm -rf ${BUILD}/test-install ${BUILD}/test-install-bin rm -rf ${BUILD}/test-install ${BUILD}/test-install-bin

View File

@ -5,6 +5,16 @@ from i3pystatus.core.modules import Module, IntervalModule
from i3pystatus.core.settings import SettingsBase from i3pystatus.core.settings import SettingsBase
from i3pystatus.core.util import formatp from i3pystatus.core.util import formatp
import logging
import os
h = logging.FileHandler(".i3pystatus-" + str(os.getpid()), delay=True)
logger = logging.getLogger("i3pystatus")
logger.addHandler(h)
logger.setLevel(logging.CRITICAL)
__path__ = extend_path(__path__, __name__) __path__ = extend_path(__path__, __name__)
__all__ = [ __all__ = [

View File

@ -0,0 +1,29 @@
# from subprocess import CalledProcessError
import subprocess
def run_through_shell(command, enable_shell=False):
"""
Retrieves output of command
Returns tuple success (boolean)/ stdout(string) / stderr (string)
Don't use this function with programs that outputs lots of data since the output is saved
in one variable
"""
returncode = None
try:
proc = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=enable_shell)
out, stderr = proc.communicate()
out = out.decode("UTF-8")
stderr = stderr.decode("UTF-8")
returncode = proc.returncode
except OSError as e:
out = e.strerror
stderr = e.strerror
except subprocess.CalledProcessError as e:
out = e.output
return returncode, out, stderr

View File

@ -1,6 +1,7 @@
from i3pystatus.core.util import KeyConstraintDict from i3pystatus.core.util import KeyConstraintDict
from i3pystatus.core.exceptions import ConfigKeyError, ConfigMissingError from i3pystatus.core.exceptions import ConfigKeyError, ConfigMissingError
import inspect import inspect
import logging
class SettingsBase: class SettingsBase:
@ -18,7 +19,7 @@ class SettingsBase:
""" """
settings = ( settings = (
("enable_log", "Set to true to log error to .i3pystatus-<pid> file"), ("log_level", "Set to true to log error to .i3pystatus-<pid> file"),
) )
"""settings should be tuple containing two types of elements: """settings should be tuple containing two types of elements:
@ -31,7 +32,8 @@ class SettingsBase:
required = tuple() required = tuple()
"""required can list settings which are required""" """required can list settings which are required"""
enable_log = False log_level = logging.NOTSET
logger = None
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
def get_argument_dict(args, kwargs): def get_argument_dict(args, kwargs):
@ -71,6 +73,8 @@ class SettingsBase:
self.__name__ = "{}.{}".format( self.__name__ = "{}.{}".format(
self.__module__, self.__class__.__name__) self.__module__, self.__class__.__name__)
self.logger = logging.getLogger(self.__name__)
self.logger.setLevel(self.log_level)
self.init() self.init()
def init(self): def init(self):

View File

@ -1,7 +1,5 @@
import subprocess
from i3pystatus import SettingsBase, IntervalModule from i3pystatus import SettingsBase, IntervalModule
from i3pystatus.core.util import internet, require from i3pystatus.core.command import run_through_shell
class Backend(SettingsBase): class Backend(SettingsBase):
@ -69,7 +67,9 @@ class Mail(IntervalModule):
def on_leftclick(self): def on_leftclick(self):
if self.email_client: if self.email_client:
subprocess.Popen(self.email_client.split()) retcode, _, stderr = run_through_shell(self.email_client)
if retcode != 0 and stderr:
self.logger.error(stderr)
def on_rightclick(self): def on_rightclick(self):
self.run() self.run()

View File

@ -1,5 +1,8 @@
from i3pystatus import IntervalModule from i3pystatus import IntervalModule
from subprocess import check_output, CalledProcessError from i3pystatus.core.command import run_through_shell
import logging
# logger = logging.getLogger(__name__)
class Shell(IntervalModule): class Shell(IntervalModule):
@ -19,21 +22,17 @@ class Shell(IntervalModule):
required = ("command",) required = ("command",)
def run(self): def run(self):
try: retvalue, out, stderr = run_through_shell(self.command, enable_shell=True)
out = check_output(self.command, shell=True)
color = self.color
except CalledProcessError as e:
out = e.output
color = self.error_color
out = out.decode("UTF-8").replace("\n", " ") if retvalue != 0:
try: self.logger.error(stderr if stderr else "Unknown error")
if out[-1] == " ":
out = out[:-1] if out:
except: out.replace("\n", " ").strip()
out = "" elif stderr:
out = stderr
self.output = { self.output = {
"full_text": out, "full_text": out if out else "Command `%s` returned %d" % (self.command, retvalue),
"color": color "color": self.color if retvalue == 0 else self.error_color
} }

View File

@ -11,7 +11,8 @@ class IntervalModuleMetaTest(unittest.TestCase):
def test_no_settings(self): def test_no_settings(self):
class NoSettings(IntervalModule): class NoSettings(IntervalModule):
pass pass
self.assertTrue('interval' in NoSettings.settings) for element in ('interval', ):
self.assertIn(element, NoSettings.settings)
def test_no_interval_setting(self): def test_no_interval_setting(self):
class NoIntervalSetting(IntervalModule): class NoIntervalSetting(IntervalModule):
@ -20,9 +21,9 @@ class IntervalModuleMetaTest(unittest.TestCase):
(('option', 'desc'), 'interval')) (('option', 'desc'), 'interval'))
def test_settings_with_interval(self): def test_settings_with_interval(self):
class SettingsInteval(IntervalModule): class SettingsInterval(IntervalModule):
settings = ('option', 'interval') settings = ('option', 'interval')
self.assertEqual(SettingsInteval.settings, ('option', 'interval')) self.assertEqual(SettingsInterval.settings, ('option', 'interval'))
def test_settings_with_interval_desc(self): def test_settings_with_interval_desc(self):
class SetttingsIntervalDesc(IntervalModule): class SetttingsIntervalDesc(IntervalModule):

24
tests/test_shell.py Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import logging
from i3pystatus.shell import Shell
from i3pystatus.core.command import run_through_shell
class ShellModuleMetaTest(unittest.TestCase):
valid_output = "hello world"
def test_shell_correct_output(self):
# ShellTest test
# http://python.readthedocs.org/en/latest/library/unittest.html
retcode, out, err = run_through_shell("echo '%s'" % (self.valid_output), enable_shell=True)
self.assertTrue(retcode == 0)
self.assertEqual(out.strip(), self.valid_output)
def test_program_failure(self):
success, out, err = run_through_shell("thisshouldtriggeranerror")
self.assertFalse(success)