с использованием BeautifulSoup:
from BeautifulSoup import BeautifulSoup
html = "<p><ul><li>Foo"
soup = BeautifulSoup(html)
print soup.prettify()
получает вас
<p>
<ul>
<li>
Foo
</li>
</ul>
</p>
Насколько я знаю, вы не можете контролировать размещение тегов
на отдельных строках от Foo.
с использованием Tidy:
import tidy
html = "<p><ul><li>Foo"
print tidy.parseString(html, show_body_only=True)
получает вас
<ul>
<li>Foo</li>
</ul>
К сожалению, я не знаю, как сохранить тег
в этом примере. Tidy интерпретирует его как пустой, а не закрытый абзац, так что
print tidy.parseString(html, show_body_only=True, drop_empty_paras=False)
выходит как
<p></p>
<ul>
<li>Foo</li>
</ul>
В конечном счете, конечно, тег
в вашем примере является избыточным, так что вы можете потерять его.
Наконец, Tidy также может делать отступы:
print tidy.parseString(html, show_body_only=True, indent=True)
становится
<ul>
<li>Foo
</li>
</ul>
Все они имеют свои взлеты и падения, но, надеюсь, один из них достаточно близко.