HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

csview: A tiny utility to view csv files

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
csviewcsvutilityviewtinyfiles

Problem

Seeing a csv in table form is nicer then viewing it as row text, for example the csv from Calculate food company sales for the year (with headers added by me) looks much nicer in this table form than in plain-text:





Kind
Brand
Sales in 2014
Sales in 2015

Cereal
Magic Balls
2200
2344

Cereal
Kaptain Krunch
3300
3123

Cereal
Coco Bongo
1800
2100

Cereal
Sugar Munch
4355
6500

Cereal
Oats n Barley
3299
5400

Sugar Candy
Pop Rocks
546
982

Sugar Candy
Lollipop
1233
1544

Sugar Candy
Gingerbud
2344
2211

Sugar Candy
Respur
1245
2211

Chocolate
Coco Jam
3322
4300

Chocolate
Larkspur
1600
2200

Chocolate
Mighty Milk
1234
2235

Chocolate
Almond Berry
998
1233

Condiments
Peanut Butter
3500
3902

Condiments
Hot Sauce
1234
1560

Condiments
Jelly
346
544

Condiments
Spread
2334
5644




To view a .csv file, I just translate it into HTML and call the browser on it.

The code is short because the task is simple, but I feel like it could be written better:

"""
This utility shows a csv file in table format
by translating it to html and calling the browser on the newly created file.

The html file is not deleted after being viewed
and has name `original_file.split('.')[0] + '.html'`

Example usage:
  python3 csview.py example.csv
"""
import webbrowser
import sys

def csv_to_html(csv):
    START = '''\n\n'''
    END = ''''''

    lines = [line for line in csv.split("\n") if line]

    html_lines = ["" + lines[0].replace(',', '\n') + ''] +\
                 ["" + line.replace(',', '\n') for line in lines[1:]]
    body = '\n' + '\n\n\n\n'.join(html_lines)
    return START + body + END

if __name__ == "__main__":
    html_filename = sys.argv[1].split('.')[0] + '.html'
    with open(html_filename, "w+") as out_file:
        with open(sys.argv[1]) as in_file:
            out_file.write(csv_to_html(in_file.read()))
    webbrowser.open(html_filename)

Solution

Constants

They are better defined outside of functions; there is no need in reinitializing them each call.

Also they are not balanced, fixing it will avoid a weird body = '\n' + ....
Files management

Just in case the path of the input file contained a dot, I recommend you use rsplit('.', 1).

Also you should try to open the input file before the ouput one. Just in case an error happen during the access to the file, you won't create an empty output file.

And since you're dealing with CSV files, why not use the csv module? It will allow you to handle edge-case data (such as fields containing comas or newlines) easily.
Wrap stuff into tags

Since you're outputing HTML, it may be a better idea to build it as such: by wrapping stuff into tags.

You could define a PATTERN = "{{}}" and a formatter:

def formatter(tag):
    return PATTERN.format(tag=tag).format


map that formatter at will to wrap stuff into tags.
Proposed improvements

import webbrowser
import sys
import csv

PATTERN = "{{}}"

def formatter(tag):
    return PATTERN.format(tag=tag).format

def csv_to_html(csv_file):
    reader = csv.reader(csv_file)

    header = formatter('tr')(
        '\n'.join(map(formatter('th'), next(reader)))
    )

    data = '\n'.join(
        map(formatter('tr'),
            '\n'.join(map(formatter('td'), row))
            for row in reader
        )
    )

    return formatter('table')('\n'.join((header, data)))

if __name__ == "__main__":
    csv_filename = sys.argv[1]
    html_filename = csv_filename.rsplit('.', 1)[0] + '.html'
    with open(csv_filename) as in_file:
        with open(html_filename, "w+") as out_file:
            out_file.write(csv_to_html(in_file))
    webbrowser.open(html_filename)

Code Snippets

def formatter(tag):
    return PATTERN.format(tag=tag).format
import webbrowser
import sys
import csv

PATTERN = "<{tag}>{{}}</{tag}>"

def formatter(tag):
    return PATTERN.format(tag=tag).format

def csv_to_html(csv_file):
    reader = csv.reader(csv_file)

    header = formatter('tr')(
        '\n'.join(map(formatter('th'), next(reader)))
    )

    data = '\n'.join(
        map(formatter('tr'),
            '\n'.join(map(formatter('td'), row))
            for row in reader
        )
    )

    return formatter('table')('\n'.join((header, data)))

if __name__ == "__main__":
    csv_filename = sys.argv[1]
    html_filename = csv_filename.rsplit('.', 1)[0] + '.html'
    with open(csv_filename) as in_file:
        with open(html_filename, "w+") as out_file:
            out_file.write(csv_to_html(in_file))
    webbrowser.open(html_filename)

Context

StackExchange Code Review Q#119090, answer score: 4

Revisions (0)

No revisions yet.