From ddff1fb2bddb84619765de617510eea2f5b9027b Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Mar 2018 15:43:23 +0100 Subject: [PATCH 1/6] Add a test to confirm failure with #55 --- tests/test_integration.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index 4500dfbe..7d93866e 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -50,6 +50,10 @@ def test_faulty_command(self): with self.assertRaises(OSError): warnings_wrapper(['--sphinx', '--command', 'blahahahaha', 'tests/sphinx_single_warning.txt']) + def test_command_revtal_err(self): + retval = warnings_wrapper(['--sphinx', '--command', 'false']) + self.assertEqual(1, retval) + def test_wildcarded_arguments(self): # note: no shell expansion simulation (e.g. as in windows) retval = warnings_wrapper(['--junit', 'tests/junit*.xml']) From bac58d4d3d2ec92083ded7bcd6bc8bf5cb85c9aa Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Mar 2018 15:43:42 +0100 Subject: [PATCH 2/6] Implementing a return code value. If it is non-zero we return that In case command returns non-0 return value we should forward that to the program requesting us to run the command. --- src/mlx/warnings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 7f23c106..323b4dfb 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -338,7 +338,9 @@ def warnings_wrapper(args): cmd = args.logfile if args.flags: cmd.extend(args.flags) - warnings_command(warnings, cmd) + retval = warnings_command(warnings, cmd) + if retval != 0: + return retval else: warnings_logfile(warnings, args.logfile) @@ -369,6 +371,7 @@ def warnings_command(warnings, cmd): except AttributeError as e: warnings.check(err) print(err, file=sys.stderr) + return proc.returncode except OSError as e: if e.errno == os.errno.ENOENT: print("It seems like program " + str(cmd) + " is not installed.") From b2ab2e0b46774e3071bcb7ef4005cba8da7c21d2 Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Mar 2018 17:05:35 +0100 Subject: [PATCH 3/6] Add test for ignore return value of executed command --- tests/test_integration.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index 7d93866e..9bc771a2 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -54,6 +54,10 @@ def test_command_revtal_err(self): retval = warnings_wrapper(['--sphinx', '--command', 'false']) self.assertEqual(1, retval) + def test_command_revtal_err_supress(self): + retval = warnings_wrapper(['--sphinx', '--ignore-retval', '--command', 'false']) + self.assertEqual(0, retval) + def test_wildcarded_arguments(self): # note: no shell expansion simulation (e.g. as in windows) retval = warnings_wrapper(['--junit', 'tests/junit*.xml']) From ac0d76d4c6995a82cd35fb52a15ce2a1fb6a551a Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Mar 2018 17:05:43 +0100 Subject: [PATCH 4/6] Add ignore executed command return value option to plugin For some commands we want to ignore return value of the command and still parse the output data. In this cases flag is added so that such usage is enabled. --- src/mlx/warnings.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 323b4dfb..627e945d 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -319,6 +319,8 @@ def warnings_wrapper(args): parser.add_argument('-v', '--verbose', dest='verbose', action='store_true') parser.add_argument('--command', dest='command', action='store_true', help='Treat program arguments as command to execute to obtain data') + parser.add_argument('--ignore-retval', dest='ignore', action='store_true', + help='Ignore return value of the executed command') parser.add_argument('-m', '--maxwarnings', type=int, required=False, default=0, help='Maximum amount of warnings accepted') parser.add_argument('--minwarnings', type=int, required=False, default=0, @@ -338,7 +340,7 @@ def warnings_wrapper(args): cmd = args.logfile if args.flags: cmd.extend(args.flags) - retval = warnings_command(warnings, cmd) + retval = warnings_command(warnings, cmd, args.ignore) if retval != 0: return retval else: @@ -348,7 +350,26 @@ def warnings_wrapper(args): return warnings.return_check_limits() -def warnings_command(warnings, cmd): +def warnings_command(warnings, cmd, ignore): + ''' Execute command to obtain input for parsing for warnings + + Usually log files are output of the commands. To avoid this additional step + this function runs a command instead and parses the stderr and stdout of the + command for warnings. + + Args: + warnings (WarningsPlugin): Object for warnings where errors should be logged + cmd: Command list, which should be executed to obtain input for parsing + ignore: Flag to ignore return value of the command + + Return: + retval: Return value of executed command + 0: If ignore flag is used. + + Raises: + OSError: When program is not installed. + ''' + try: print("Executing: ", end='') print(cmd) @@ -371,7 +392,11 @@ def warnings_command(warnings, cmd): except AttributeError as e: warnings.check(err) print(err, file=sys.stderr) - return proc.returncode + + if ignore: + return 0 + else: + return proc.returncode except OSError as e: if e.errno == os.errno.ENOENT: print("It seems like program " + str(cmd) + " is not installed.") From 0546974b6c4130ad7067285878bd4d5e3e04cb12 Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Mar 2018 17:28:27 +0100 Subject: [PATCH 5/6] Refactoring to make less complex warnings_command function The CodeClimate complained that function is too big, so we shorten it a bit. Also cognitive complexity of the wrapper is increasing, but I would assume there is no way around it. --- src/mlx/warnings.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 627e945d..aa15dbe4 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -340,8 +340,9 @@ def warnings_wrapper(args): cmd = args.logfile if args.flags: cmd.extend(args.flags) - retval = warnings_command(warnings, cmd, args.ignore) - if retval != 0: + retval = warnings_command(warnings, cmd) + + if (not args.ignore) and (retval != 0): return retval else: warnings_logfile(warnings, args.logfile) @@ -350,7 +351,7 @@ def warnings_wrapper(args): return warnings.return_check_limits() -def warnings_command(warnings, cmd, ignore): +def warnings_command(warnings, cmd): ''' Execute command to obtain input for parsing for warnings Usually log files are output of the commands. To avoid this additional step @@ -364,7 +365,6 @@ def warnings_command(warnings, cmd, ignore): Return: retval: Return value of executed command - 0: If ignore flag is used. Raises: OSError: When program is not installed. @@ -392,11 +392,7 @@ def warnings_command(warnings, cmd, ignore): except AttributeError as e: warnings.check(err) print(err, file=sys.stderr) - - if ignore: - return 0 - else: - return proc.returncode + return proc.returncode except OSError as e: if e.errno == os.errno.ENOENT: print("It seems like program " + str(cmd) + " is not installed.") From c195ee78e12c9a7031aab3f266666a7f6732bea3 Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Mar 2018 17:43:11 +0100 Subject: [PATCH 6/6] Adding toggle prinout to the warnings plugin class for everyone to use --- src/mlx/warnings.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index aa15dbe4..894f7993 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -213,6 +213,7 @@ def __init__(self, sphinx = False, doxygen = False, junit = False, verbose = Fal self.warn_min = 0 self.warn_max = 0 self.count = 0 + self.printout = False def activate_checker(self, checker): ''' @@ -244,6 +245,8 @@ def check(self, content): if len(self.checkerList) == 0: print("No checkers activated. Please use activate_checker function") else: + if self.printout: + print(content) for name, checker in self.checkerList.items(): checker.check(content) @@ -309,6 +312,16 @@ def return_check_limits(self, name = None): return 0 + def toggle_printout(self, printout): + ''' Toggle printout of all the parsed content + + Useful for command input where we want to print content as well + + Args: + printout: True enables the printout, False provides more silent mode + ''' + self.printout = printout + def warnings_wrapper(args): parser = argparse.ArgumentParser(prog='mlx-warnings') @@ -340,6 +353,7 @@ def warnings_wrapper(args): cmd = args.logfile if args.flags: cmd.extend(args.flags) + warnings.toggle_printout(True) retval = warnings_command(warnings, cmd) if (not args.ignore) and (retval != 0): @@ -379,19 +393,15 @@ def warnings_command(warnings, cmd): # Check stdout if out: try: - print(out.decode(encoding="utf-8")) warnings.check(out.decode(encoding="utf-8")) except AttributeError as e: warnings.check(out) - print(out) # Check stderr if err: try: warnings.check(err.decode(encoding="utf-8")) - print(err.decode(encoding="utf-8"), file=sys.stderr) except AttributeError as e: warnings.check(err) - print(err, file=sys.stderr) return proc.returncode except OSError as e: if e.errno == os.errno.ENOENT: