[Doc-SIG] Diffing reStructuredText documents that only differ by formatting

Jeffrey C. Jacobs docutils.org.timehorse at neverbox.com
Tue Mar 3 18:57:12 CET 2009


Gael Varoquaux <gael.varoquaux <at> normalesup.org> writes:
> 
> wdiff.

Thanks for the suggestions!  Unfortunately, one thing I forgot to mention
was that the concatenations should not span different paragraphs.  Thus:

Hello!  World!

is not the same as:

Hello!

World!

Since the first represents 2 paragraphs, but the second only 1.

Instead, I propose the following python script that diffs the docutil
trees instead of the original text files.  I don't know how it could tell
whether the 2 imputs are reStructuredText documents vs. regular text
documents and only perform the doc-tree step if rst, and am welcome to
suggestions for improvements but so far this does a good job of what I am
trying to achieve.  Such a tool could be handy to rst documenters in
cases where a document may have a bunch of lines through years of editing
that go beyond 80 columns and thus the file is edited to bring it back in
line, which produces massive standard diffs when the result really should
more or less be the same document.  This script could be used to confirm
that the two versions of documents are more or less the same.

----------

#!/usr/bin/python

import sys
import subprocess
import tempfile
import docutils.core
import os
import re

# Regexp for removing inconsequential characters
trimwhite = re.compile(r'(?<!>)\n\s*(?![< ])', re.M + re.U + re.L)
webspace = re.compile(r'(?<=[.?!):])\s{2,}(?=[\w\d(])', re.M + re.U + re.L)
repl = r' '

if __name__ == '__main__':
  # To Do: verify that document 1 and document 2 are both
  # reStructuredText documents

  # Last 2 parameters are the left hand side and right hand side file
  lhs, rhs = sys.argv[-2:]

  # Parse the left and right file into docutils tree strings
  lhss1 = docutils.core.publish_string(file(lhs).read())
  rhss2 = docutils.core.publish_string(file(rhs).read())

  # Concatenate multi-line text that lies within a node
  lhss1, lhsr1 = trimwhite.subn(repl, lhss1)
  rhss2, rhsr2 = trimwhite.subn(repl, rhss2)
  #sys.stdout.write('Removed returns (left, right): %d, %d\n' %
  #                 (lhsr1, rhsr2))

  # Trim multiple white spaces between full-stop (.?!) and the next phrase
  lhss1, lhsr1 = webspace.subn(repl, lhss1)
  rhss2, rhsr2 = webspace.subn(repl, rhss2)
  #sys.stdout.write('Removed double space (left, right): %d, %d\n' %
  #                 (lhsr1, rhsr2))

  # Make sure the last line is properly terminated
  lhss1 += '\n'
  rhss2 += '\n'

  # Allocate temporary files to hold the left and right doc-trees
  lhsh1, lhst1 = tempfile.mkstemp(text=True)
  rhsh2, rhst2 = tempfile.mkstemp(text=True)

  # Open the left and write temp files for writing
  lhso1 = os.fdopen(lhsh1, 'w')
  rhso2 = os.fdopen(rhsh2, 'w')

  # Write the doc-trees to the temp files
  lhso1.write(lhss1)
  rhso2.write(rhss2)

  # Close the temp files
  lhso1.close()
  rhso2.close()

  # Spawn [UNIX] diff and wait for it to complete
  # Stdout and Stderr are passed directly to this application
  sp = subprocess.Popen(['diff'] + sys.argv[1:-2] + [lhst1, rhst2])
  sp.wait()

  # Delete the temp files
  os.remove(lhst1)
  os.remove(rhst2)






More information about the Doc-SIG mailing list