Search code examples
pythonhtmlcsshtml-tabledifflib

Change the width of difflib.make_file() HTML Table?


I am creating diff files for legal documents with the python difflib and make_file(), which outputs HTML files containing a Table with the Diffs.

But the output tables are so wide that they are unreadable.

Is there any way to change the width of the table or add other css from my function call? I can't find anything related in the documentation.

In case it is not possible, what could be a solution to my "table width too wide" problem?

I already tried adding bootstrap and putting the table into a div that is responsive, but it didn't work.


Solution

  • You can use wrapcolumn= in HtmlDiff

    import difflib
    import webbrowser
    
    d = difflib.HtmlDiff(wrapcolumn=10)
    
    lines1 = ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']
    lines2 = ['XXXXXXXXXXXXXaaaaaaaaaYYYaaaaaaZZZZZZZZZZZaaaaZZZZZZZZ']
    
    html = d.make_file(lines1, lines2)
    
    with open('output.html', 'w') as fh: 
        fh.write(html)
    
    webbrowser.open('output.html')
    

    Without wrapcolumn=

    enter image description here

    With wrapcolumn=10

    enter image description here


    EDIT:

    I didn't test it but in source code of diff you can see hidden variables _styles, _table_template, _file_template which you could replace in HtmlDiff to generate different HTML. This way you could add classes and styles to format it.

    It may also need to change hidden _format_line to remove nowrap="nowrap"


    EDIT:

    I use HtmlDiff to create own class with new _format_line() without nowrap="nowrap" and now I can add styles with width and word-break

    import difflib
    import webbrowser
    
    # --- classes ---
    
    class MyHTML(difflib.HtmlDiff):
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
       
            # append new styles inside new class 
            self._styles = self._styles + """
    table.diff {width: 300px}
    .diff_sub {display: inline-block; word-break: break-word;}
    .diff_add {display: inline-block; word-break: break-word;}
    """
    
        # function from source code - I remove only `nowrap="nowrap"`
        def _format_line(self,side,flag,linenum,text):
            """Returns HTML markup of "from" / "to" text lines
            side -- 0 or 1 indicating "from" or "to" text
            flag -- indicates if difference on line
            linenum -- line number (used for line number column)
            text -- line text to be marked up
            """
            try:
                linenum = '%d' % linenum
                id = ' id="%s%s"' % (self._prefix[side],linenum)
            except TypeError:
                # handle blank lines where linenum is '>' or ''
                id = ''
            # replace those things that would get confused with HTML symbols
            text=text.replace("&","&amp;").replace(">","&gt;").replace("<","&lt;")
    
            # make space non-breakable so they don't get compressed or line wrapped
            text = text.replace(' ','&nbsp;').rstrip()
    
            return '<td class="diff_header"%s>%s</td><td>%s</td>' \
                   % (id,linenum,text)
    
    # --- main ---
    
    d = MyHTML()
    
    # >>> changing styles after creating `MyHTML` or in original `HtmlDiff <<<
    #d._styles = d._styles + """
    #table.diff {width: 300px}
    #.diff_sub {display: inline-block; word-break: break-word;}
    #.diff_add {display: inline-block; word-break: break-word;}
    #"""
    
    #d._file_template = """new template"""
        
    
    lines1 = ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']
    lines2 = ['XXXXXXXXXXXXXaaaaaaaaaYYYaaaaaaZZZZZZZZZZZaaaaZZZZZZZZ']
    
    html = d.make_file(lines1, lines2)
    
    with open('output.html', 'w') as fh: 
        fh.write(html)
    
    webbrowser.open('output.html')
    

    Shorter version

    import difflib
    import webbrowser
    
    d = HtmlDiff(wrapcolumn=10)
    
    d._file_template = """new template with %(charset)s %(styles)s %(table)s %(legend)s"""         
    #d._styles = """new styles"""         
    
    lines1 = ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']
    lines2 = ['XXXXXXXXXXXXXaaaaaaaaaYYYaaaaaaZZZZZZZZZZZaaaaZZZZZZZZ']
    
    html = d.make_file(lines1, lines2)
    
    with open('output.html', 'w') as fh: 
        fh.write(html)
    
    webbrowser.open('output.html')