[Checkins] SVN: z3c.coverage/trunk/ - Feature: The ``main()`` coverage report function now accepts the arguments

Stephan Richter srichter at cosmos.phy.tufts.edu
Tue Jan 29 13:22:32 EST 2008


Log message for revision 83302:
  - Feature: The ``main()`` coverage report function now accepts the arguments
    of the script as a function argument, making it easier to configure the
    script from buildout.
  
  - Feature: When the report directory does not exist, the report generator
    creates it for you.
  
  - Feature: Eat your own dog food by creating a buildout that can create
    coverage reports.
  
  - Bug: Improved the test coverage to 100%.
  
  Get ready for release.
  
  

Changed:
  _U  z3c.coverage/trunk/
  U   z3c.coverage/trunk/CHANGES.txt
  U   z3c.coverage/trunk/README.txt
  U   z3c.coverage/trunk/buildout.cfg
  U   z3c.coverage/trunk/setup.py
  A   z3c.coverage/trunk/src/z3c/coverage/README.txt
  U   z3c.coverage/trunk/src/z3c/coverage/coveragediff.txt
  U   z3c.coverage/trunk/src/z3c/coverage/coveragereport.py
  U   z3c.coverage/trunk/src/z3c/coverage/tests.py

-=-

Property changes on: z3c.coverage/trunk
___________________________________________________________________
Name: svn:ignore
   - develop-eggs
eggs
parts
.installed.cfg
build
dist
bin

   + .installed.cfg
bin
build
coverage
develop-eggs
dist
eggs
parts


Modified: z3c.coverage/trunk/CHANGES.txt
===================================================================
--- z3c.coverage/trunk/CHANGES.txt	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/CHANGES.txt	2008-01-29 18:22:32 UTC (rev 83302)
@@ -1,27 +1,47 @@
 CHANGES
 -------
 
+1.1.0 (2008-01-29)
+~~~~~~~~~~~~~~~~~~
+
+- Feature: The ``main()`` coverage report function now accepts the arguments
+  of the script as a function argument, making it easier to configure the
+  script from buildout.
+
+- Feature: When the report directory does not exist, the report generator
+  creates it for you.
+
+- Feature: Eat your own dog food by creating a buildout that can create
+  coverage reports.
+
+- Bug: Improved the test coverage to 100%.
+
+
 1.0.1 (2007-09-26)
 ~~~~~~~~~~~~~~~~~~
 
-- Fixed meta-data.
+- Bug: Fixed meta-data.
 
+
 1.0.0 (2007-09-26)
 ~~~~~~~~~~~~~~~~~~
 
 - First public release.
 
+
 0.2.1
 ~~~~~
 
-- Added the ``--web`` option to ``coveragediff``.
-- Added a test suite.
+- Feature: Added the ``--web`` option to ``coveragediff``.
+- Feature: Added a test suite.
 
+
 0.2.0
 ~~~~~
 
-- Added ``coveragediff.py``.
+- Feature: Added ``coveragediff.py``.
 
+
 0.1.0
 ~~~~~
 

Modified: z3c.coverage/trunk/README.txt
===================================================================
--- z3c.coverage/trunk/README.txt	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/README.txt	2008-01-29 18:22:32 UTC (rev 83302)
@@ -1,7 +1,3 @@
-============
-z3c.coverage
-============
-
 This package produces a nice HTML representation of the coverage data
 generated by the Zope test runner.
 

Modified: z3c.coverage/trunk/buildout.cfg
===================================================================
--- z3c.coverage/trunk/buildout.cfg	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/buildout.cfg	2008-01-29 18:22:32 UTC (rev 83302)
@@ -1,8 +1,19 @@
 [buildout]
 develop = .
-parts = test
+parts = test coverage-test coverage-report
 
 [test]
 recipe = zc.recipe.testrunner
 eggs = z3c.coverage [test]
 defaults = ['--ndiff']
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.coverage [test]
+defaults = ['--ndiff', '--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage
+arguments = ('coverage', 'coverage/report')

Modified: z3c.coverage/trunk/setup.py
===================================================================
--- z3c.coverage/trunk/setup.py	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/setup.py	2008-01-29 18:22:32 UTC (rev 83302)
@@ -23,13 +23,18 @@
 
 setup (
     name='z3c.coverage',
-    version='1.0.1',
+    version='1.1.0',
     author = "Zope Community",
     author_email = "zope3-dev at zope.org",
     description = "A script to visualize coverage reports via HTML",
     long_description=(
         read('README.txt')
         + '\n\n' +
+        'Detailed Documentation\n'
+        '**********************'
+        + '\n\n' +
+        read('src', 'z3c', 'formui', 'README.txt')
+        + '\n\n' +
         read('CHANGES.txt')
         ),
     license = "ZPL 2.1",

Added: z3c.coverage/trunk/src/z3c/coverage/README.txt
===================================================================
--- z3c.coverage/trunk/src/z3c/coverage/README.txt	                        (rev 0)
+++ z3c.coverage/trunk/src/z3c/coverage/README.txt	2008-01-29 18:22:32 UTC (rev 83302)
@@ -0,0 +1,208 @@
+=====================
+Test Coverage Reports
+=====================
+
+The main objective of this package is to convert the text-based coverage
+output into an HTML coverage report. This is simply done by specifying the
+directory of the test reports and the desired output directory.
+
+Luckily we already have the text input ready:
+
+  >>> import os
+  >>> import z3c.coverage
+  >>> inputDir = os.path.join(
+  ...     os.path.split(z3c.coverage.__file__)[0], 'sampleinput')
+
+The output directory has to be created first:
+
+  >>> import tempfile
+  >>> outputDir = os.path.join(tempfile.mkdtemp(), 'report')
+
+We can now simply create the coverage report as follows:
+
+  >>> from z3c.coverage import coveragereport
+  >>> coveragereport.main((inputDir, outputDir))
+
+Looking at the output directory, we now see several files:
+
+  >>> print '\n'.join(os.listdir(outputDir))
+  all.html
+  z3c.coverage.coveragereport.html
+  z3c.coverage.coveragediff.html
+  z3c.coverage.html
+  z3c.coverage.__init__.html
+  z3c.html
+
+
+API Tests
+=========
+
+``CoverageNode`` Class
+----------------------
+
+This class represents a node in the source tree. Simple modules are considered
+leaves and do not have children. Let's create a node for the `z3c` namespace
+first:
+
+  >>> z3cNode = coveragereport.CoverageNode()
+
+Before using the API, let's create a few more nodes and a tree from it:
+
+  >>> coverageNode = coveragereport.CoverageNode()
+  >>> z3cNode['coverage'] = coverageNode
+
+  >>> reportNode = coveragereport.CoverageNode()
+  >>> reportNode._covered, reportNode._total = 40, 134
+  >>> coverageNode['coveragereport'] = reportNode
+
+  >>> diffNode = coveragereport.CoverageNode()
+  >>> diffNode._covered, diffNode._total = 128, 128
+  >>> coverageNode['coveragediff'] = diffNode
+
+  >>> initNode = coveragereport.CoverageNode()
+  >>> initNode._covered, initNode._total = 0, 0
+  >>> coverageNode['__init__'] = initNode
+
+Let's now have a look at the coverage of the `z3c` namespace:
+
+  >>> z3cNode.coverage
+  (168, 262)
+
+We can also ask for the percentile:
+
+  >>> z3cNode.percent
+  64
+  >>> initNode.percent
+  100
+
+We can ask for the amoutn of uncovered lines:
+
+  >>> z3cNode.uncovered
+  94
+
+Finally, we also can get a nice output:
+
+  >>> print z3cNode
+  64% covered (94 of 262 lines uncovered)
+
+
+`index_to_filename()` function
+------------------------------
+
+Takes an indexed Python path and produces the cover filename for it:
+
+  >>> coveragereport.index_to_filename(('z3c', 'coverage', 'coveragereport'))
+  'z3c.coverage.coveragereport.cover'
+
+  >>> coveragereport.index_to_filename(())
+  ''
+
+`index_to_nice_name()` function
+-------------------------------
+
+Takes an indexed Python path and produces a nice "human-readable" string:
+
+  >>> coveragereport.index_to_nice_name(('z3c', 'coverage', 'coveragereport'))
+  '        coveragereport'
+
+  >>> coveragereport.index_to_nice_name(())
+  'Everything'
+
+
+`index_to_name()` function
+--------------------------
+
+Takes an indexed Python path and produces a "human-readable" string:
+
+  >>> coveragereport.index_to_name(('z3c', 'coverage', 'coveragereport'))
+  'z3c.coverage.coveragereport'
+
+  >>> coveragereport.index_to_name(())
+  'everything'
+
+
+`percent_to_colour()` function
+------------------------------
+
+Given a coverage percentage, this function returns a color to represent the
+coverage:
+
+  >>> coveragereport.percent_to_colour(100)
+  'green'
+  >>> coveragereport.percent_to_colour(92)
+  'yellow'
+  >>> coveragereport.percent_to_colour(85)
+  'orange'
+  >>> coveragereport.percent_to_colour(50)
+  'red'
+
+
+`get_svn_revision()` function
+-----------------------------
+
+Given a path, the function tries to determine the revision number of the
+file. If it fails, "UNKNOWN" is returned:
+
+  >>> path = os.path.split(z3c.coverage.__file__)[0]
+  >>> coveragereport.get_svn_revision(path)
+  '8...M'
+
+  >>> coveragereport.get_svn_revision(path + '/__init__.py')
+  'UNKNOWN'
+
+
+`syntax_highlight()` function
+-----------------------------
+
+This function takes a cover file, converts it to a nicely colored HTML output:
+
+  >>> filename = os.path.join(
+  ...     os.path.split(z3c.coverage.__file__)[0], '__init__.py')
+
+  >>> print coveragereport.syntax_highlight(filename)
+  <BLANKLINE>
+  <I><FONT COLOR="#B22222"># Make a package.
+  </FONT></I>
+
+If the highlighing command is not available, no coloration is done:
+
+  >>> command_orig = coveragereport.HIGHLIGHT_COMMAND
+  >>> coveragereport.HIGHLIGHT_COMMAND = 'foobar %s'
+
+  >>> print coveragereport.syntax_highlight(filename)
+  # Make a package.
+  <BLANKLINE>
+
+  >>> coveragereport.HIGHLIGHT_COMMAND = command_orig
+
+
+`coveragereport.py` is a script
+-------------------------------
+
+For convenience you can download the ``coveragereport.py`` module and run it
+as a script:
+
+  >>> import sys
+  >>> sys.argv = ['coveragereport', inputDir, outputDir]
+
+  >>> script_file = os.path.join(
+  ...     z3c.coverage.__path__[0], 'coveragereport.py')
+
+  >>> execfile(script_file, dict(__name__='__main__'))
+
+Defaults are chosen, when no input and output dir is specified:
+
+  >>> def make_coverage_reports_stub(path, report_path):
+  ...     print path
+  ...     print report_path
+
+  >>> make_coverage_reports_orig = coveragereport.make_coverage_reports
+  >>> coveragereport.make_coverage_reports = make_coverage_reports_stub
+
+  >>> sys.argv = ['coveragereport']
+  >>> coveragereport.main()
+  coverage
+  coverage/reports
+
+  >>> coveragereport.make_coverage_reports = make_coverage_reports_orig
+


Property changes on: z3c.coverage/trunk/src/z3c/coverage/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: z3c.coverage/trunk/src/z3c/coverage/coveragediff.txt
===================================================================
--- z3c.coverage/trunk/src/z3c/coverage/coveragediff.txt	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/src/z3c/coverage/coveragediff.txt	2008-01-29 18:22:32 UTC (rev 83302)
@@ -1,3 +1,4 @@
+======================
 coveragediff internals
 ======================
 

Modified: z3c.coverage/trunk/src/z3c/coverage/coveragereport.py
===================================================================
--- z3c.coverage/trunk/src/z3c/coverage/coveragereport.py	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/src/z3c/coverage/coveragereport.py	2008-01-29 18:22:32 UTC (rev 83302)
@@ -42,6 +42,9 @@
 import cgi
 
 
+HIGHLIGHT_COMMAND = ('enscript -q --footer --header -h --language=html'
+                     ' --highlight=python --color -o - "%s"')
+
 class CoverageNode(dict):
     """Tree node.
 
@@ -115,8 +118,8 @@
 
     One example is worth a thousand descriptions:
 
-        >>> filename_to_list('schooltool.app.__init__.cover')
-        ['schooltool', 'app', '__init__']
+        >>> filename_to_list('z3c.coverage.__init__.cover')
+        ['z3c', 'coverage', '__init__']
 
     """
     return filename.split('.')[:-1]
@@ -290,7 +293,9 @@
         file_path = os.path.join(path, index_to_filename(my_index))
         text = syntax_highlight(file_path)
         def color_uncov(line):
-            if '&gt;&gt;&gt;&gt;&gt;&gt;' in line:
+            # The line must start with the missing line indicator or some HTML
+            # was put in front of it.
+            if line.startswith('&gt;'*6) or '>'+'&gt;'*6 in line:
                 return ('<div class="notcovered">%s</div>'
                         % line.rstrip('\n'))
             return line
@@ -303,8 +308,7 @@
 def syntax_highlight(filename):
     """Return HTML with syntax-highlighted Python code from a file."""
     # XXX can get painful if filenames contain unsafe characters
-    pipe = os.popen('enscript -q --footer --header -h --language=html'
-                    ' --highlight=python --color -o - "%s"' % filename,
+    pipe = os.popen(HIGHLIGHT_COMMAND % filename,
                     'r')
     text = pipe.read()
     if pipe.close():
@@ -360,8 +364,20 @@
     html.close()
 
 
+def create_report_path(report_path):
+    report_path = os.path.abspath(report_path)
+    missing_dirs = []
+    while not os.path.exists(report_path):
+        report_path, missing_dir = os.path.split(report_path)
+        missing_dirs.append(missing_dir)
+    while missing_dirs:
+        report_path = os.path.join(report_path, missing_dirs.pop())
+        os.mkdir(report_path)
+
+
 def make_coverage_reports(path, report_path):
     """Convert reports from ``path`` into HTML files in ``report_path``."""
+    create_report_path(report_path)
     def filter_fn(filename):
         return (filename.endswith('.cover') and
                 'test' not in filename and
@@ -372,8 +388,8 @@
     timestamp = str(datetime.datetime.utcnow())+"Z"
     footer = "Generated for revision %s on %s" % (rev, timestamp)
     generate_htmls_from_tree(tree, path, report_path, footer)
-    generate_overall_html_from_tree(tree, os.path.join(report_path,
-                                                       'all.html'), footer)
+    generate_overall_html_from_tree(
+        tree, os.path.join(report_path, 'all.html'), footer)
 
 
 def get_svn_revision(path):
@@ -384,16 +400,21 @@
     return rev
 
 
-def main():
+def main(args=None):
     """Process command line arguments and produce HTML coverage reports."""
-    if len(sys.argv) > 1:
-        path = sys.argv[1]
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) > 0:
+        path = args[0]
     else:
         path = 'coverage'
-    if len(sys.argv) > 2:
-        report_path = sys.argv[2]
+
+    if len(args) > 1:
+        report_path = args[1]
     else:
         report_path = 'coverage/reports'
+
     make_coverage_reports(path, report_path)
 
 

Modified: z3c.coverage/trunk/src/z3c/coverage/tests.py
===================================================================
--- z3c.coverage/trunk/src/z3c/coverage/tests.py	2008-01-29 17:15:16 UTC (rev 83301)
+++ z3c.coverage/trunk/src/z3c/coverage/tests.py	2008-01-29 18:22:32 UTC (rev 83302)
@@ -15,10 +15,14 @@
                 (re.compile('^options:', re.MULTILINE), 'Options:'),
                                            ])
     return unittest.TestSuite([
-                doctest.DocFileSuite('coveragediff.txt', checker=checker),
-                doctest.DocTestSuite('z3c.coverage.coveragediff'),
-                doctest.DocTestSuite('z3c.coverage.coveragereport'),
-                               ])
+        doctest.DocFileSuite(
+            'README.txt', checker=checker,
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+            ),
+        doctest.DocFileSuite('coveragediff.txt', checker=checker),
+        doctest.DocTestSuite('z3c.coverage.coveragediff'),
+        doctest.DocTestSuite('z3c.coverage.coveragereport'),
+        ])
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')



More information about the Checkins mailing list