[Zope3-checkins] SVN: zope.testing/trunk/src/zope/testing/testrunner Make --auto-color actually check whether the terminal supports colors. Some

Marius Gedminas marius at pov.lt
Mon Jul 23 17:40:13 EDT 2007


Log message for revision 78300:
  Make --auto-color actually check whether the terminal supports colors.  Some
  terminals don't (e.g. the emacs built-in one), which makes some people (e.g.
  my coworker Albertas) unhappy when --auto-color is present in the test script.
  
  

Changed:
  U   zope.testing/trunk/src/zope/testing/testrunner-colors.txt
  U   zope.testing/trunk/src/zope/testing/testrunner.py

-=-
Modified: zope.testing/trunk/src/zope/testing/testrunner-colors.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-colors.txt	2007-07-23 18:11:26 UTC (rev 78299)
+++ zope.testing/trunk/src/zope/testing/testrunner-colors.txt	2007-07-23 21:40:12 UTC (rev 78300)
@@ -311,12 +311,36 @@
 Autodetecting colors
 --------------------
 
-The --auto-color option will determine if stdout is a terminal, and only enable
-colorized output if so.  Our ``Terminal`` wrapper pretends it is a terminal, so
-we get colors:
+The --auto-color option will determine if stdout is a terminal that supports
+colors, and only enable colorized output if so.  Our ``Terminal`` wrapper
+pretends it is a terminal, but the curses module will realize it isn't:
 
     >>> sys.argv = 'test --layer 122 --auto-color'.split()
     >>> testrunner.run(defaults)
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+    False
+
+We can fake it
+
+    >>> class FakeCurses(object):
+    ...     class error(Exception):
+    ...         pass
+    ...     def setupterm(self):
+    ...         pass
+    ...     def tigetnum(self, attr):
+    ...         return dict(colors=8).get(attr, -2)
+    >>> sys.modules['curses'] = FakeCurses()
+
+    >>> sys.argv = 'test --layer 122 --auto-color'.split()
+    >>> testrunner.run(defaults)
     {normal}Running samplelayers.Layer122 tests:{normal}
       Set up samplelayers.Layer1 in {green}0.000{normal} seconds.
       Set up samplelayers.Layer12 in {green}0.000{normal} seconds.
@@ -328,6 +352,8 @@
       Tear down samplelayers.Layer1 in {green}0.000{normal} seconds.
     False
 
+    >>> del sys.modules['curses']
+
 The real stdout is not a terminal in a doctest:
 
     >>> sys.stdout = real_stdout

Modified: zope.testing/trunk/src/zope/testing/testrunner.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner.py	2007-07-23 18:11:26 UTC (rev 78299)
+++ zope.testing/trunk/src/zope/testing/testrunner.py	2007-07-23 21:40:12 UTC (rev 78300)
@@ -259,6 +259,33 @@
 """
 
 
+def tigetnum(attr, default=None):
+    """Return a value from the terminfo database.
+
+    Terminfo is used on Unix-like systems to report various terminal attributes
+    (such as width, height or the number of supported colors).
+
+    Returns ``default`` when the ``curses`` module is not available, or when
+    sys.stdout is not a terminal.
+    """
+    try:
+        import curses
+    except ImportError:
+        # avoid reimporting a broken module in python 2.3
+        sys.modules['curses'] = None
+    else:
+        try:
+            curses.setupterm()
+        except (curses.error, TypeError):
+            # You get curses.error when $TERM is set to an unknown name
+            # You get TypeError when sys.stdout is not a real file object
+            # (e.g. in unit tests that use various wrappers).
+            pass
+        else:
+            return curses.tigetnum(attr)
+    return default
+
+
 class OutputFormatter(object):
     """Test runner output formatter."""
 
@@ -280,19 +307,8 @@
 
     def compute_max_width(self):
         """Try to determine the terminal width."""
-        try:
-            # Note that doing this every time is more test friendly.
-            import curses
-        except ImportError:
-            # avoid reimporting a broken module in python 2.3
-            sys.modules['curses'] = None
-        else:
-            try:
-                curses.setupterm()
-            except TypeError:
-                pass
-            else:
-                self.max_width = curses.tigetnum('cols')
+        # Note that doing this every time is more test friendly.
+        self.max_width = tigetnum('cols', self.max_width)
 
     def getShortDescription(self, test, room):
         """Return a description of a test that fits in ``room`` characters."""
@@ -2348,14 +2364,23 @@
     '--suite-name', 'test_suite',
     ]
 
+
+def terminal_has_colors():
+    """Determine whether the terminal supports colors.
+
+    Some terminals (e.g. the emacs built-in one) don't.
+    """
+    return tigetnum('colors', -1) >= 8
+
+
 def get_options(args=None, defaults=None):
     # Because we want to inspect stdout and decide to colorize or not, we
     # replace the --auto-color option with the appropriate --color or
     # --no-color option.  That way the subprocess doesn't have to decide (which
-    # it would do incorrectly anyway because stdout wouled be a pipe).
+    # it would do incorrectly anyway because stdout would be a pipe).
     def apply_auto_color(args):
         if args and '--auto-color' in args:
-            if sys.stdout.isatty():
+            if sys.stdout.isatty() and terminal_has_colors():
                 colorization = '--color'
             else:
                 colorization = '--no-color'



More information about the Zope3-Checkins mailing list