diff options
-rw-r--r-- | .pylintrc | 4 | ||||
-rw-r--r-- | coverage/__init__.py | 12 | ||||
-rw-r--r-- | coverage/html.py | 22 | ||||
-rw-r--r-- | coverage/misc.py | 1 | ||||
-rw-r--r-- | coverage/templite.py | 38 | ||||
-rw-r--r-- | test/coverage_coverage.py | 2 | ||||
-rw-r--r-- | test/coveragetest.py | 18 |
7 files changed, 76 insertions, 21 deletions
@@ -69,7 +69,7 @@ load-plugins= # Messages that are noisy for now, eventually maybe we'll turn them on: # C0111:169:coverage.analyze_morf: Missing docstring # C0103:256:coverage.morf_filename: Invalid name "f" (should match [a-z_][a-z0-9_]{2,30}$) -disable-msg=I0011,W0122,W0142,W0232,C0323,C0324,W0603, R0201,R0401,W0403,E1103, C0111,C0103 +disable-msg=I0011,W0122,W0142,W0232,C0323,C0324,W0603, R0201,R0401,W0403,E1103, C0103 [REPORTS] @@ -123,7 +123,7 @@ required-attributes= # Regular expression which should only match functions or classes name which do # not require a docstring -no-docstring-rgx=__.*__ +no-docstring-rgx=__.*__|test[A-Z_].*|setUp|tearDown # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ diff --git a/coverage/__init__.py b/coverage/__init__.py index c1b95874..c787b341 100644 --- a/coverage/__init__.py +++ b/coverage/__init__.py @@ -23,12 +23,20 @@ from coverage.misc import CoverageException _the_coverage = None def _singleton_method(name): - def func(*args, **kwargs): + """Return a function to the `name` method on a singleton `coverage` object. + + The singleton object is created the first time one of these functions is + called. + + """ + def wrapper(*args, **kwargs): + """Singleton wrapper around a coverage method.""" global _the_coverage if not _the_coverage: _the_coverage = coverage() return getattr(_the_coverage, name)(*args, **kwargs) - return func + return wrapper + # Define the module-level functions. use_cache = _singleton_method('use_cache') diff --git a/coverage/html.py b/coverage/html.py index 6fc49ff5..d8f98c45 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -16,9 +16,7 @@ def data(fname): class HtmlReporter(Reporter): - """HTML reporting. - - """ + """HTML reporting.""" def __init__(self, coverage, ignore_errors=False): super(HtmlReporter, self).__init__(coverage, ignore_errors) @@ -27,7 +25,14 @@ class HtmlReporter(Reporter): self.files = [] - def report(self, morfs, directory=None, omit_prefixes=None): + def report(self, morfs, directory, omit_prefixes=None): + """Generate an HTML report for `morfs`. + + `morfs` is a list of modules or filenames. `directory` is where to put + the HTML files. `omit_prefixes` is a list of strings, prefixes of + modules to omit from the report. + + """ assert directory, "must provide a directory for html reporting" # Process all the files. @@ -147,10 +152,15 @@ def not_empty(t): return t or " " def format_pct(p): + """Format a percentage value for the HTML reports.""" return "%.0f" % p def spaceless(html): - """Squeeze out some of that annoying extra space that comes from - nicely-formatted templates.""" + """Squeeze out some annoying extra space from an HTML string. + + Nicely-formatted templates mean lots of extra space in the result. Get + rid of some. + + """ html = re.sub(">\s+<p ", ">\n<p ", html) return html diff --git a/coverage/misc.py b/coverage/misc.py index 398f9b27..8a8b5117 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -47,4 +47,5 @@ def format_lines(statements, lines): class CoverageException(Exception): + """An exception specific to Coverage.""" pass diff --git a/coverage/templite.py b/coverage/templite.py index f75e2a2d..fabc3dbb 100644 --- a/coverage/templite.py +++ b/coverage/templite.py @@ -8,9 +8,26 @@ import re class Templite(object): """A simple template renderer, for a nano-subset of Django syntax. + + Supported constructs are extended variable access:: + + {{var.modifer.modifier|filter|filter}} + + and loops:: + + {% for var in list %}...{% endfor %} + + Construct a Templite with the template text, then use `render` against a + dictionary context to create a finished string. """ def __init__(self, text, *contexts): + """Construct a Templite with the given `text`. + + `contexts` are dictionaries of values to use for future renderings. + These are good for filters and global values. + + """ self.loops = [] self.text = self._prepare(text) self.context = {} @@ -18,12 +35,17 @@ class Templite(object): self.context.update(context) def render(self, context=None): + """Render this template by applying it to `context`. + + `context` is a dictionary of values to use in this rendering. + + """ # Make the complete context we'll use. ctx = dict(self.context) if context: ctx.update(context) - ctxaccess = ContextAccess(ctx) + ctxaccess = _ContextAccess(ctx) # Render the loops. for iloop, (loopvar, listvar, loopbody) in enumerate(self.loops): @@ -41,7 +63,7 @@ class Templite(object): # Pull out loops. text = re.sub( r"(?s){% for ([a-z0-9_]+) in ([a-z0-9_.|]+) %}(.*?){% endfor %}", - self._loop_repl, text + self._loop_prepare, text ) # Protect actual percent signs in the text. text = text.replace("%", "%%") @@ -49,7 +71,8 @@ class Templite(object): text = re.sub(r"{{([^}]+)}}", r"%(\1)s", text) return text - def _loop_repl(self, match): + def _loop_prepare(self, match): + """Prepare a loop body for `_prepare`.""" nloop = len(self.loops) # Append (loopvar, listvar, loopbody) to self.loops loopvar, listvar, loopbody = match.groups() @@ -58,8 +81,13 @@ class Templite(object): return "{{loop:%d}}" % nloop -class ContextAccess(object): +class _ContextAccess(object): + """A mediator for a context. + Implements __getitem__ on a context for Templite, so that string formatting + references can pull data from the context. + + """ def __init__(self, context): self.context = context @@ -70,7 +98,7 @@ class ContextAccess(object): for func in pipes[1:]: value = self[func](value) elif "." in key: - dots = key.split('.') + dots = key.split('.') value = self[dots[0]] for dot in dots[1:]: try: diff --git a/test/coverage_coverage.py b/test/coverage_coverage.py index 0ab0e2ff..ca10edc3 100644 --- a/test/coverage_coverage.py +++ b/test/coverage_coverage.py @@ -1,4 +1,4 @@ -# Coverage-test Coverage itself. +"""Coverage-test Coverage itself.""" import coverage import os, shutil, sys diff --git a/test/coveragetest.py b/test/coveragetest.py index 5e2c18dc..46572c56 100644 --- a/test/coveragetest.py +++ b/test/coveragetest.py @@ -14,14 +14,14 @@ import coverage class Tee(object): - """A file-like that writes to all the file-likes it was constructed with. - - """ + """A file-like that writes to all the file-likes it has.""" def __init__(self, *files): + """Make a Tee that writes to all the files in `files.`""" self.files = files def write(self, data): + """Write `data` to all the files.""" for f in self.files: f.write(data) @@ -77,8 +77,7 @@ class CoverageTest(unittest.TestCase): f.close() def importModule(self, modname): - """ Import the module named modname, and return the module object. - """ + """Import the module named modname, and return the module object.""" modfile = modname + '.py' f = open(modfile, 'r') @@ -94,6 +93,7 @@ class CoverageTest(unittest.TestCase): return mod def getModuleName(self): + """Return the module name to use for this test run.""" # We append self.n because otherwise two calls in one test will use the # same filename and whether the test works or not depends on the # timestamps in the .pyc file, so it becomes random whether the second @@ -103,6 +103,14 @@ class CoverageTest(unittest.TestCase): return modname def checkCoverage(self, text, lines, missing="", excludes=None, report=""): + """Check the coverage measurement of `text`. + + The source `text` is run and measured. `lines` are the line numbers + that are executable, `missing` are the lines not executed, `excludes` + are regexes to match against for excluding lines, and `report` is + the text of the measurement report. + + """ # We write the code into a file so that we can import it. # Coverage wants to deal with things as modules with file names. modname = self.getModuleName() |