November 14, 2008

lxml.usedoctest is basically awesome

Hi. I know it’s been a while.

I’m here today to tell you how awesome lxml.usedoctest is. Check out a doctest:

def something_doing_xml_stuff():
    """
    >>> import lxml.usedoctest

    Namespaces are inherited as you'd expect.

    >>> print xml.a(xmlns="uri:a")[
    ...     xml.b[
    ...         xml.c(xmlns="uri:c")[
    ...             xml.d[ "I'm down here at D!" ]
    ...         ]
    ...     ]
    ... ]
    <ns0:a xmlns:ns0="uri:a">
        <ns0:b>
            <ns1:c xmlns:ns1="uri:c">
                <ns1:d>I'm down here at D!</ns1:d>
            </ns1:c>
        </ns0:b>
    </ns0:a>

    """
    pass

Now check some example output when it fails:

----------------------------------------------------------------------
File "tags.py", line 230, in __main__.Element
Failed example:
    print xml.a(xmlns="uri:a")[
        xml.b[
            xml.c(xmlns="uri:c")[
                xml.d[ "I'm down here at D!" ]
            ]
        ]
    ]
Expected:
  <{uri:a}a>
    <{uri:a}b>
      <{uri:c}c>
        <{uri:c}d>I'm down here at D!</{uri:c}d>
      </{uri:c}c>
    </{uri:a}b>
  </{uri:a}a>

Got:
  <{uri:a}a>
    <b>
      <{uri:c}c>
        <d>I'm down here at D!</d>
      </{uri:c}c>
    </b>
  </{uri:a}a>

Diff:
  <{uri:a}a>
    <{uri:a}b (got: b)>
      <{uri:c}c>
        <{uri:c}d (got: d)>I'm down here at D!</{uri:c}d (got: d)>
      </{uri:c}c>
    </{uri:a}b (got: b)>
  </{uri:a}a>

Putting aside the ugly ElementTree-like qname syntax, lxml.usedoctest:

  • Lets me make the XML in my doctest pretty
  • Shows me the expected/actual output pretty-printed as well
  • Goes on to show me a diff! (Maybe not the easiest to read, but it works.)