[tor-commits] [stem/master] Less verbose usage of the test.output module

atagar at torproject.org atagar at torproject.org
Sun Apr 14 04:33:47 UTC 2013


commit e7513978c0a39fb815eecaff2f8d9a8c958236df
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Apr 13 12:41:22 2013 -0700

    Less verbose usage of the test.output module
    
    We use the print_line() function throughout the runner and run_tests.py.
    Shortening it to 'println()' (pity we can't call it print()) and making its
    usage a little nicer by flattening the input attributes.
---
 run_tests.py          |   59 +++++++++++++++++++++++++------------------------
 test/integ/process.py |    1 -
 test/output.py        |   57 +++++++++++++++++++++++++++++++++--------------
 test/runner.py        |   42 +++++++++++++++-------------------
 4 files changed, 89 insertions(+), 70 deletions(-)

diff --git a/run_tests.py b/run_tests.py
index 5e80441..4116e40 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -25,6 +25,7 @@ import test.output
 import test.runner
 import test.util
 
+from test.output import println, STATUS, ERROR, NO_NL
 from test.runner import Target
 
 OPT = "auist:l:h"
@@ -67,7 +68,7 @@ def _python3_setup(python3_destination, clean):
     shutil.rmtree(python3_destination, ignore_errors = True)
 
   if os.path.exists(python3_destination):
-    test.output.print_error("Reusing '%s'. Run again with '--clean' if you want to recreate the python3 export." % python3_destination)
+    println("Reusing '%s'. Run again with '--clean' if you want to recreate the python3 export." % python3_destination, ERROR)
     print
     return True
 
@@ -81,21 +82,21 @@ def _python3_setup(python3_destination, clean):
       else:
         return []
 
-    test.output.print_noline("  copying stem to '%s'... " % python3_destination, *test.runner.STATUS_ATTR)
+    println("  copying stem to '%s'... " % python3_destination, STATUS, NO_NL)
     shutil.copytree('stem', os.path.join(python3_destination, 'stem'))
     shutil.copytree('test', os.path.join(python3_destination, 'test'), ignore = _ignore)
     shutil.copy('run_tests.py', os.path.join(python3_destination, 'run_tests.py'))
-    test.output.print_line("done", *test.runner.STATUS_ATTR)
+    println("done", STATUS)
   except OSError, exc:
-    test.output.print_error("failed\n%s" % exc)
+    println("failed\n%s" % exc, ERROR)
     return False
 
   try:
-    test.output.print_noline("  running 2to3... ", *test.runner.STATUS_ATTR)
+    println("  running 2to3... ", STATUS, NO_NL)
     system.call("2to3 --write --nobackups --no-diffs %s" % python3_destination)
-    test.output.print_line("done", *test.runner.STATUS_ATTR)
+    println("done", STATUS)
   except OSError, exc:
-    test.output.print_error("failed\n%s" % exc)
+    println("failed\n%s" % exc, ERROR)
     return False
 
   return True
@@ -112,23 +113,23 @@ def _print_static_issues(run_unit, run_integ, run_style):
     if system.is_available("pyflakes"):
       static_check_issues.update(test.util.get_pyflakes_issues(SOURCE_BASE_PATHS))
     else:
-      test.output.print_error("Static error checking requires pyflakes. Please install it from ...\n  http://pypi.python.org/pypi/pyflakes\n")
+      println("Static error checking requires pyflakes. Please install it from ...\n  http://pypi.python.org/pypi/pyflakes\n", ERROR)
 
   if run_style:
     if system.is_available("pep8"):
       static_check_issues = test.util.get_stylistic_issues(SOURCE_BASE_PATHS)
     else:
-      test.output.print_error("Style checks require pep8. Please install it from...\n  http://pypi.python.org/pypi/pep8\n")
+      println("Style checks require pep8. Please install it from...\n  http://pypi.python.org/pypi/pep8\n", ERROR)
 
   if static_check_issues:
-    test.output.print_line("STATIC CHECKS", term.Color.BLUE, term.Attr.BOLD)
+    println("STATIC CHECKS", term.Color.BLUE, term.Attr.BOLD)
 
     for file_path in static_check_issues:
-      test.output.print_line("* %s" % file_path, term.Color.BLUE, term.Attr.BOLD)
+      println("* %s" % file_path, term.Color.BLUE, term.Attr.BOLD)
 
       for line_number, msg in static_check_issues[file_path]:
         line_count = "%-4s" % line_number
-        test.output.print_line("  line %s - %s" % (line_count, msg))
+        println("  line %s - %s" % (line_count, msg))
 
       print
 
@@ -259,7 +260,7 @@ if __name__ == '__main__':
   if run_python3:
     for required_cmd in ("2to3", "python3"):
       if not system.is_available(required_cmd):
-        test.output.print_error("Unable to test python 3 because %s isn't in your path" % required_cmd)
+        println("Unable to test python 3 because %s isn't in your path" % required_cmd, ERROR)
         sys.exit(1)
 
   if run_python3 and sys.version_info[0] != 3:
@@ -273,7 +274,7 @@ if __name__ == '__main__':
       sys.exit(1)  # failed to do python3 setup
 
   if not run_unit and not run_integ and not run_style:
-    test.output.print_line("Nothing to run (for usage provide --help)\n")
+    println("Nothing to run (for usage provide --help)\n")
     sys.exit()
 
   # if we have verbose logging then provide the testing config
@@ -297,18 +298,18 @@ if __name__ == '__main__':
 
   test.output.print_divider("INITIALISING", True)
 
-  test.output.print_line("Performing startup activities...", *test.runner.STATUS_ATTR)
-  test.output.print_noline("  checking for orphaned .pyc files... ", *test.runner.STATUS_ATTR)
+  println("Performing startup activities...", STATUS)
+  println("  checking for orphaned .pyc files... ", STATUS, NO_NL)
 
   orphaned_pyc = test.util.clean_orphaned_pyc(SOURCE_BASE_PATHS)
 
   if not orphaned_pyc:
     # no orphaned files, nothing to do
-    test.output.print_line("done", *test.runner.STATUS_ATTR)
+    println("done", STATUS)
   else:
     print
     for pyc_file in orphaned_pyc:
-      test.output.print_error("    removed %s" % pyc_file)
+      println("    removed %s" % pyc_file, ERROR)
 
   print
 
@@ -364,12 +365,12 @@ if __name__ == '__main__':
             if opt in test.runner.Torrc.keys():
               torrc_opts.append(test.runner.Torrc[opt])
             else:
-              test.output.print_line("'%s' isn't a test.runner.Torrc enumeration" % opt)
+              println("'%s' isn't a test.runner.Torrc enumeration" % opt)
               sys.exit(1)
 
         integ_runner.start(target, attribute_targets, tor_path, extra_torrc_opts = torrc_opts)
 
-        test.output.print_line("Running tests...", term.Color.BLUE, term.Attr.BOLD)
+        println("Running tests...", term.Color.BLUE, term.Attr.BOLD)
         print
 
         for test_class in test.util.get_integ_tests(test_prefix):
@@ -391,15 +392,15 @@ if __name__ == '__main__':
         active_threads = threading.enumerate()
 
         if len(active_threads) > 1:
-          test.output.print_error("Threads lingering after test run:")
+          println("Threads lingering after test run:", ERROR)
 
           for lingering_thread in active_threads:
-            test.output.print_error("  %s" % lingering_thread)
+            println("  %s" % lingering_thread, ERROR)
 
           testing_failed = True
           break
       except KeyboardInterrupt:
-        test.output.print_error("  aborted starting tor: keyboard interrupt\n")
+        println("  aborted starting tor: keyboard interrupt\n", ERROR)
         break
       except OSError:
         testing_failed = True
@@ -411,7 +412,7 @@ if __name__ == '__main__':
 
       for target in skip_targets:
         req_version = stem.version.Requirement[CONFIG["target.prereq"][target]]
-        test.output.print_line("Unable to run target %s, this requires tor version %s" % (target, req_version), term.Color.RED, term.Attr.BOLD)
+        println("Unable to run target %s, this requires tor version %s" % (target, req_version), ERROR)
 
       print
 
@@ -430,16 +431,16 @@ if __name__ == '__main__':
   has_error = testing_failed or error_tracker.has_error_occured()
 
   if has_error:
-    test.output.print_error("TESTING FAILED %s" % runtime_label)
+    println("TESTING FAILED %s" % runtime_label, ERROR)
 
     for line in error_tracker:
-      test.output.print_error("  %s" % line)
+      println("  %s" % line, ERROR)
   elif skipped_test_count > 0:
-    test.output.print_line("%i TESTS WERE SKIPPED" % skipped_test_count, term.Color.BLUE, term.Attr.BOLD)
-    test.output.print_line("ALL OTHER TESTS PASSED %s" % runtime_label, term.Color.GREEN, term.Attr.BOLD)
+    println("%i TESTS WERE SKIPPED" % skipped_test_count, term.Color.BLUE, term.Attr.BOLD)
+    println("ALL OTHER TESTS PASSED %s" % runtime_label, term.Color.GREEN, term.Attr.BOLD)
     print
   else:
-    test.output.print_line("TESTING PASSED %s" % runtime_label, term.Color.GREEN, term.Attr.BOLD)
+    println("TESTING PASSED %s" % runtime_label, term.Color.GREEN, term.Attr.BOLD)
     print
 
   sys.exit(1 if has_error else 0)
diff --git a/test/integ/process.py b/test/integ/process.py
index 414d233..3429adf 100644
--- a/test/integ/process.py
+++ b/test/integ/process.py
@@ -4,7 +4,6 @@ Tests the stem.process functions with various use cases.
 
 import os
 import shutil
-import signal
 import subprocess
 import tempfile
 import time
diff --git a/test/output.py b/test/output.py
index 22f3605..b39e650 100644
--- a/test/output.py
+++ b/test/output.py
@@ -18,7 +18,14 @@ COLOR_SUPPORT = sys.stdout.isatty() and not system.is_windows()
 DIVIDER = "=" * 70
 HEADER_ATTR = (term.Color.CYAN, term.Attr.BOLD)
 CATEGORY_ATTR = (term.Color.GREEN, term.Attr.BOLD)
-ERROR_ATTR = (term.Color.RED, term.Attr.BOLD)
+
+NO_NL = "no newline"
+
+# formatting for various categories of messages
+
+STATUS = (term.Color.BLUE, term.Attr.BOLD)
+SUBSTATUS = (term.Color.BLUE, )
+ERROR = (term.Color.RED, term.Attr.BOLD)
 
 LineType = stem.util.enum.Enum("OK", "FAIL", "ERROR", "SKIPPED", "CONTENT")
 
@@ -38,41 +45,40 @@ LINE_ATTR = {
 }
 
 
-def print_line(msg, *attr):
-  if COLOR_SUPPORT:
-    msg = term.format(msg, *attr)
-
-  print msg
+def println(msg, *attr):
+  attr = _flatten(attr)
+  no_newline = False
 
+  if NO_NL in attr:
+    no_newline = True
+    attr.remove(NO_NL)
 
-def print_noline(msg, *attr):
   if COLOR_SUPPORT:
     msg = term.format(msg, *attr)
 
-  sys.stdout.write(msg)
-  sys.stdout.flush()
-
-
-def print_error(msg):
-  print_line(msg, *ERROR_ATTR)
+  if no_newline:
+    sys.stdout.write(msg)
+    sys.stdout.flush()
+  else:
+    print msg
 
 
 def print_divider(msg, is_header = False):
   attr = HEADER_ATTR if is_header else CATEGORY_ATTR
-  print_line("%s\n%s\n%s\n" % (DIVIDER, msg.center(70), DIVIDER), *attr)
+  println("%s\n%s\n%s\n" % (DIVIDER, msg.center(70), DIVIDER), *attr)
 
 
 def print_logging(logging_buffer):
   if not logging_buffer.is_empty():
     for entry in logging_buffer:
-      print_line(entry.replace("\n", "\n  "), term.Color.MAGENTA)
+      println(entry.replace("\n", "\n  "), term.Color.MAGENTA)
 
     print
 
 
 def print_config(test_config):
   print_divider("TESTING CONFIG", True)
-  print_line("Test configuration... ", term.Color.BLUE, term.Attr.BOLD)
+  println("Test configuration... ", term.Color.BLUE, term.Attr.BOLD)
 
   for config_key in test_config.keys():
     key_entry = "  %s => " % config_key
@@ -81,7 +87,7 @@ def print_config(test_config):
     value_div = ",\n" + (" " * len(key_entry))
     value_entry = value_div.join(test_config.get_value(config_key, multiple = True))
 
-    print_line(key_entry + value_entry, term.Color.BLUE)
+    println(key_entry + value_entry, term.Color.BLUE)
 
   print
 
@@ -225,3 +231,20 @@ class ErrorTracker(object):
   def __iter__(self):
     for error_line in self._errors:
       yield error_line
+
+
+def _flatten(seq):
+  # Flattens nested collections into a single list. For instance...
+  #
+  # >>> _flatten([1, [2, 3], 4])
+  # [1, 2, 3, 4]
+
+  result = []
+
+  for item in seq:
+    if (isinstance(item, (tuple, list))):
+      result.extend(_flatten(item))
+    else:
+      result.append(item)
+
+  return result
diff --git a/test/runner.py b/test/runner.py
index bcff7a0..2de1852 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -42,7 +42,6 @@ about the tor test instance they're running against.
 import logging
 import os
 import shutil
-import signal
 import stat
 import tempfile
 import threading
@@ -57,7 +56,7 @@ import stem.util.enum
 import stem.version
 import test.output
 
-from stem.util import term
+from test.output import println, STATUS, SUBSTATUS, NO_NL
 
 CONFIG = stem.util.conf.config_dict("test", {
   "integ.test_directory": "./test/data",
@@ -79,9 +78,6 @@ Target = stem.util.enum.UppercaseEnum(
   "RUN_ALL",
 )
 
-STATUS_ATTR = (term.Color.BLUE, term.Attr.BOLD)
-SUBSTATUS_ATTR = (term.Color.BLUE, )
-
 SOCKS_HOST = "127.0.0.1"
 SOCKS_PORT = 1112
 
@@ -295,7 +291,7 @@ class Runner(object):
       if self._tor_process:
         self.stop()
 
-      test.output.print_line("Setting up a test instance...", *STATUS_ATTR)
+      println("Setting up a test instance...", STATUS)
 
       # if 'test_directory' is unset then we make a new data directory in /tmp
       # and clean it up when we're done
@@ -357,7 +353,7 @@ class Runner(object):
     """
 
     with self._runner_lock:
-      test.output.print_noline("Shutting down tor... ", *STATUS_ATTR)
+      println("Shutting down tor... ", STATUS, NO_NL)
 
       if self._tor_process:
         # if the tor process has stopped on its own then the following raises
@@ -386,7 +382,7 @@ class Runner(object):
       self._custom_opts = None
       self._tor_process = None
 
-      test.output.print_line("done", *STATUS_ATTR)
+      println("done", STATUS)
 
   def is_running(self):
     """
@@ -631,13 +627,13 @@ class Runner(object):
 
     # makes a temporary data directory if needed
     try:
-      test.output.print_noline("  making test directory (%s)... " % self._test_dir, *STATUS_ATTR)
+      println("  making test directory (%s)... " % self._test_dir, STATUS, NO_NL)
 
       if os.path.exists(self._test_dir):
-        test.output.print_line("skipped", *STATUS_ATTR)
+        println("skipped", STATUS)
       else:
         os.makedirs(self._test_dir)
-        test.output.print_line("done", *STATUS_ATTR)
+        println("done", STATUS)
     except OSError, exc:
       test.output.print_error("failed (%s)" % exc)
       raise exc
@@ -649,16 +645,16 @@ class Runner(object):
     if Torrc.SOCKET in self._custom_opts:
       try:
         socket_dir = os.path.dirname(CONTROL_SOCKET_PATH)
-        test.output.print_noline("  making control socket directory (%s)... " % socket_dir, *STATUS_ATTR)
+        println("  making control socket directory (%s)... " % socket_dir, STATUS, NO_NL)
 
         if os.path.exists(socket_dir) and stat.S_IMODE(os.stat(socket_dir).st_mode) == 0700:
-          test.output.print_line("skipped", *STATUS_ATTR)
+          println("skipped", STATUS)
         else:
           if not os.path.exists(socket_dir):
             os.makedirs(socket_dir)
 
           os.chmod(socket_dir, 0700)
-          test.output.print_line("done", *STATUS_ATTR)
+          println("done", STATUS)
       except OSError, exc:
         test.output.print_error("failed (%s)" % exc)
         raise exc
@@ -668,7 +664,7 @@ class Runner(object):
 
     if logging_path:
       logging_path = stem.util.system.expand_path(logging_path, STEM_BASE)
-      test.output.print_noline("  configuring logger (%s)... " % logging_path, *STATUS_ATTR)
+      println("  configuring logger (%s)... " % logging_path, STATUS, NO_NL)
 
       # delete the old log
       if os.path.exists(logging_path):
@@ -681,23 +677,23 @@ class Runner(object):
         datefmt = '%D %H:%M:%S',
       )
 
-      test.output.print_line("done", *STATUS_ATTR)
+      println("done", STATUS)
     else:
-      test.output.print_line("  configuring logger... skipped", *STATUS_ATTR)
+      println("  configuring logger... skipped", STATUS)
 
     # writes our testing torrc
     torrc_dst = os.path.join(self._test_dir, "torrc")
     try:
-      test.output.print_noline("  writing torrc (%s)... " % torrc_dst, *STATUS_ATTR)
+      println("  writing torrc (%s)... " % torrc_dst, STATUS, NO_NL)
 
       torrc_file = open(torrc_dst, "w")
       torrc_file.write(self._torrc_contents)
       torrc_file.close()
 
-      test.output.print_line("done", *STATUS_ATTR)
+      println("done", STATUS)
 
       for line in self._torrc_contents.strip().splitlines():
-        test.output.print_line("    %s" % line.strip(), *SUBSTATUS_ATTR)
+        println("    %s" % line.strip(), SUBSTATUS)
 
       print
     except Exception, exc:
@@ -714,7 +710,7 @@ class Runner(object):
     :raises: OSError if we either fail to create the tor process or reached a timeout without success
     """
 
-    test.output.print_line("Starting tor...\n", *STATUS_ATTR)
+    println("Starting tor...\n", STATUS)
     start_time = time.time()
 
     try:
@@ -723,13 +719,13 @@ class Runner(object):
       complete_percent = 100 if Target.ONLINE in self.attribute_targets else 5
 
       # prints output from tor's stdout while it starts up
-      print_init_line = lambda line: test.output.print_line("  %s" % line, *SUBSTATUS_ATTR)
+      print_init_line = lambda line: println("  %s" % line, SUBSTATUS)
 
       torrc_dst = os.path.join(self._test_dir, "torrc")
       self._tor_process = stem.process.launch_tor(tor_cmd, None, torrc_dst, complete_percent, print_init_line)
 
       runtime = time.time() - start_time
-      test.output.print_line("  done (%i seconds)\n" % runtime, *STATUS_ATTR)
+      println("  done (%i seconds)\n" % runtime, STATUS)
     except OSError, exc:
       test.output.print_error("  failed to start tor: %s\n" % exc)
       raise exc





More information about the tor-commits mailing list