Skip to content

Instantly share code, notes, and snippets.

@rajaramanathan
Created January 10, 2015 07:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rajaramanathan/0fef003196d5ccf654b7 to your computer and use it in GitHub Desktop.
Save rajaramanathan/0fef003196d5ccf654b7 to your computer and use it in GitHub Desktop.
Strategy pattern in python
from __future__ import print_function
import os
import csv
from csv import Sniffer
from csv import reader
from csv import DictReader
HTML_TEMPLATE="""<html><body><table>%s</table></body></html>"""
class CsvConverter:
''' Abstract class or interface for conversion of csv file'''
def convert(self,csv):
pass #abstract method
class Csv2Html(CsvConverter):
''' Covert Csv to html table with alternating row colors'''
def convert(self,csv):
''' convert the csv file to html file '''
htmltable = ''
csvfile = open(csv)
dialect = Sniffer().sniff(csvfile.read(2048))
csvfile.seek(0) #rewind after sniffing
csvreader = reader(csvfile,dialect)
i = 0
for line in csvreader:
#print line
if i == 0: #header row
htmltable += '<tr class="head">'
elif i % 2 == 0: #even row
htmltable += '<tr class="even">'
else: #odd row
htmltable += '<tr class="odd">'
for col in line:
htmltable += '<td>%s</td>'%col
htmltable += '</tr>'
i += 1
return HTML_TEMPLATE%htmltable
def __str__(self):
return 'Csv2Html'
class Csv2Xml(CsvConverter):
''' Covert Csv to Xml '''
def __init__(self,linetag='row'):
''' Constructor '''
self.linetag = linetag
def convert(self,csv):
''' convert the csv file to xml file '''
xml = '<?xml version="1.0" encoding="UTF-8"?>'
xml += "<table>" + os.linesep
csvfile = open(csv)
csvreader = DictReader(csvfile)
for row in csvreader:
xml += '<%s>'%self.linetag + os.linesep
for colname,colvalue in row.iteritems():
xml += '<%s>%s</%s>'%(colname,colvalue.replace('\n', ' ').replace('\r', ''),colname) + os.linesep
xml += '</%s>'%self.linetag + os.linesep
xml += "</table>" + os.linesep
return xml
def __str__(self):
return 'Csv2Xml'
class CsvUtil(object):
''' A wrapper or utility class for dealing with csv files '''
def __init__(self,csv):
''' constructor '''
self.csv = csv
self._numlines = None #this information is computed lazily
self._numcols = None #this information is gathered lazily
self._wellformed = None #this information is gathered lazily
self._converter = Csv2Html() #default converter
def _gatherstats(self):
''' gather basic stats on the csv '''
with open(self.csv) as csvfile:
dialect = csv.Sniffer().sniff(csvfile.read(2048))
csvfile.seek(0) #rewind
reader = csv.reader(csvfile,dialect)
self._numlines = 0
self._wellformed = True
self._numcols = 0
for line in reader:
self._numlines += 1
if self._numcols != len(line):
self._wellformed = False
def convert(self):
''' convert the csv file to another format '''
return self._converter.convert(self.csv)
def get_wellformed(self):
''' a csv is wellformed if all the lines have same number of columns '''
if not self._wellformed:
self._gatherstats()
return self._wellformed
def get_numlines(self):
''' number of lines in the csv files '''
if not self._numlines:
self._gatherstats()
return self._numlines
def get_numcols(self):
''' number of lines in the csv files '''
if not self._numcols:
self._gatherstats()
return self._numcols
def get_converter(self):
''' getter for converter '''
return self._converter
def set_converter(self,value):
self._converter = value
#properties
wellformed = property(get_wellformed)
numlines = property(get_numlines)
numcols = property(get_numcols)
converter = property(get_converter,set_converter)
def main():
csvfile = os.path.expanduser(r"~/Downloads/sample.csv")
outputDir = os.path.dirname(csvfile) #write the html and xml to this directory
util = CsvUtil(csvfile) # my utility class for handling csv
htmlFile = os.path.join(outputDir,"sample.csv.html")
with open(htmlFile, 'w') as f:
print(util.convert(), file=f)
#now changing my converter at run time :-)
util.converter = Csv2Xml()
xmlFile = os.path.join(outputDir,"sample.csv.xml")
with open(xmlFile, 'w') as f:
print(util.convert(), file=f)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment