[Tutor] doctest question
Steven D'Aprano
steve at pearwood.info
Mon Nov 26 23:02:45 CET 2012
On 27/11/12 08:06, Albert-Jan Roskam wrote:
> Hi,
>
> I am using doctest and I am struggling with newlines characters
> (see below). One is the newline escape (backslash) for a long
>dictionary definition. The other is an embedded \n in the output.
> I used the +NORMALIZE_WHITESPACE directive. I also tried using a
> triple-quoted raw docstring. Any ideas?
Yes, quite a few.
Your following example is hard to understand and, as they say in
English, "as clear as mud". It would help a lot if you laid out the
example dictionary so that it was easier to read, and if you followed
the standard convention to end the docstring with a single """ so
that it separates the end of the docstring from the start of the code.
Function name "_setMultRespDefsEx" is not self-explanatory, or even
*hint* at what the function is supposed to do. It appears to take a
dictionary of stuff, and formats it as a string. It would be nice[1]
if your docstring explained what sort of stuff.
The example given should be simple, not complex. If you must give a
complex example, always give a simple example first.
Examples should be written for clarity, not as code golf. There is no
prize for stuffing everything into one or two lines.
Doctext directives are not global to the docstring, they must appear
on the same line as the doctest itself.
Take advantage of Python's implicit line continuation to avoid
problems with backslash line continuations.
Doctesting anything to do with dictionaries is tricky, because you
cannot rely on the order of a dict. There are a couple of different
ways to solve that:
* the lazy solution: always use doctests on dicts with a single item;
* change the function to always process the dict in a known order;
* change the doctest to post-process the function result, e.g. pull
the string apart into separate lines, sort the lines, put it
back together.
Here's my attempt:
import doctest
import copy
def _setMultRespDefsEx(multRespDefs):
"""Format a dictionary of stuff as a string. Expects that dict contains:
{breakfast: {spam: foo, ham: bar} blah blah blah ...} # or whatever
>>> xdict = {'countedValue': '1', 'firstVarIsLabel': True, 'label': '',
... 'setType': 'E','varNames': ['mevar1', 'mevar2', 'mevar3']}
>>> ydict = {'countedValue': 'Yes', 'firstVarIsLabel': False,
... 'label': 'Enhanced set with user specified label',
... 'setType': 'E', 'varNames': ['mevar4', 'mevar5', 'mevar6']}
>>> adict = {'mesetx': xdict, 'mesety': ydict}
>>> print(_setMultRespDefsEx(adict))
$mesetx=E 11 1 1 0 mevar1 mevar2 mevar3
$mesety=E 1 3 Yes 38 Enhanced set with user specified label mevar4 mevar5 mevar6
KNOWN BUGS:
1) Sometimes this function returns a dict instead of a string.
2) The formatted string output is ambiguous.
"""
mrDefs = [] # "That's Mister Defs to you" :-)
for setName, rest in sorted(multRespDefs.iteritems()):
if rest["setType"] != "E":
return {}
rest["setName"] = setName
v = int(rest["firstVarIsLabel"])
rest["firstVarIsLabel"] = v if v == 1 else ""
rest["valueLen"] = len(rest["countedValue"])
rest["lblLen"] = len(rest["label"])
rest["label"] = rest["label"]
rest["varNames"] = " ".join(rest["varNames"])
mrDef = "$%(setName)s=%(setType)s 1%(firstVarIsLabel)s %(valueLen)s "
mrDef += "%(countedValue)s %(lblLen)s %(label)s %(varNames)s"
mrDefs.append((mrDef % rest).replace(" ", " "))
return "\n".join(mrDefs)
And running the doctest:
py> doctest.testmod()
TestResults(failed=0, attempted=4)
[1] By "nice" I mean *essential*.
--
Steven
More information about the Tutor
mailing list