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
py.test --version
pep8 --version
python3 -mpep8 --version
# Target directory for all build files
BUILD=${1:-ci-build}
mkdir -p $BUILD
pep8 --ignore E501 i3pystatus tests
python3 -mpep8 --ignore E501 i3pystatus tests
# Check that the setup.py script works
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.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__)
__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.exceptions import ConfigKeyError, ConfigMissingError
import inspect
import logging
class SettingsBase:
@ -18,7 +19,7 @@ class SettingsBase:
"""
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:
@ -31,7 +32,8 @@ class SettingsBase:
required = tuple()
"""required can list settings which are required"""
enable_log = False
log_level = logging.NOTSET
logger = None
def __init__(self, *args, **kwargs):
def get_argument_dict(args, kwargs):
@ -71,6 +73,8 @@ class SettingsBase:
self.__name__ = "{}.{}".format(
self.__module__, self.__class__.__name__)
self.logger = logging.getLogger(self.__name__)
self.logger.setLevel(self.log_level)
self.init()
def init(self):

View File

@ -1,7 +1,5 @@
import subprocess
from i3pystatus import SettingsBase, IntervalModule
from i3pystatus.core.util import internet, require
from i3pystatus.core.command import run_through_shell
class Backend(SettingsBase):
@ -69,7 +67,9 @@ class Mail(IntervalModule):
def on_leftclick(self):
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):
self.run()

View File

@ -1,5 +1,8 @@
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):
@ -19,21 +22,17 @@ class Shell(IntervalModule):
required = ("command",)
def run(self):
try:
out = check_output(self.command, shell=True)
color = self.color
except CalledProcessError as e:
out = e.output
color = self.error_color
retvalue, out, stderr = run_through_shell(self.command, enable_shell=True)
out = out.decode("UTF-8").replace("\n", " ")
try:
if out[-1] == " ":
out = out[:-1]
except:
out = ""
if retvalue != 0:
self.logger.error(stderr if stderr else "Unknown error")
if out:
out.replace("\n", " ").strip()
elif stderr:
out = stderr
self.output = {
"full_text": out,
"color": color
"full_text": out if out else "Command `%s` returned %d" % (self.command, retvalue),
"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):
class NoSettings(IntervalModule):
pass
self.assertTrue('interval' in NoSettings.settings)
for element in ('interval', ):
self.assertIn(element, NoSettings.settings)
def test_no_interval_setting(self):
class NoIntervalSetting(IntervalModule):
@ -20,9 +21,9 @@ class IntervalModuleMetaTest(unittest.TestCase):
(('option', 'desc'), 'interval'))
def test_settings_with_interval(self):
class SettingsInteval(IntervalModule):
class SettingsInterval(IntervalModule):
settings = ('option', 'interval')
self.assertEqual(SettingsInteval.settings, ('option', 'interval'))
self.assertEqual(SettingsInterval.settings, ('option', 'interval'))
def test_settings_with_interval_desc(self):
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)