Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #16121

Template class and class design on concrete example xl2csv writer

Path csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!gegeweb.org!de-l.enfer-du-nord.net!feeder2.enfer-du-nord.net!feeds.phibee-telecom.net!newsfeed.xs4all.nl!newsfeed6.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail
Return-Path <kliateni@gmail.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.000
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; 'elif': 0.04; 'args': 0.05; 'classes.': 0.05; 'main()': 0.05; '"""': 0.07; 'ascii': 0.07; 'none:': 0.07; '__future__': 0.09; 'csv': 0.09; 'derived': 0.09; 'parsing': 0.09; 'skip:[ 30': 0.09; 'skip:_ 120': 0.09; 'sys,': 0.09; 'exception': 0.12; 'def': 0.13; 'method.': 0.15; "';'": 0.16; '@property': 0.16; '__all__': 0.16; 'argparse,': 0.16; 'csv,': 0.16; 'delimited': 0.16; 'function).': 0.16; 'int):': 0.16; 'main():': 0.16; 'row': 0.16; 'str):': 0.16; 'subject:design': 0.16; 'subject:example': 0.16; 'sys.exit(1)': 0.16; 'xlrd': 0.16; 'arguments': 0.18; 'template': 0.19; 'sfxlen:2': 0.19; 'to:2**1': 0.21; 'extension': 0.21; 'received:209.85.212.46': 0.23; 'received:mail- vw0-f46.google.com': 0.23; 'welcome.': 0.23; 'code': 0.25; 'classes': 0.26; 'skip:_ 20': 0.26; 'import': 0.27; 'all,': 0.28; 'raise': 0.28; 'pass': 0.29; "skip:' 30": 0.29; "skip:' 10": 0.29; 'usual': 0.29; 'class': 0.29; 'correct': 0.29; 'objects.': 0.30; 'os,': 0.30; 'pattern': 0.30; 'writer': 0.30; 'usually': 0.31; 'quite': 0.32; 'to:addr:tutor': 0.32; 'implement': 0.32; 'message- id:@gmail.com': 0.33; 'header:User-Agent:1': 0.33; 'object': 0.33; 'to:addr:python-list': 0.34; 'received:209.85.212': 0.34; 'skip:@ 10': 0.34; 'try:': 0.34; 'to:no real name:2**1': 0.35; 'skip:m 40': 0.35; 'file': 0.36; 'properties': 0.36; 'element': 0.37; 'skip:" 10': 0.37; 'but': 0.37; 'except': 0.37; 'received:google.com': 0.37; 'skip:_ 10': 0.37; 'could': 0.37; 'allows': 0.38; 'received:209.85': 0.38; 'put': 0.38; 'non': 0.38; 'should': 0.39; 'goes': 0.39; 'format.': 0.39; 'received:209': 0.40; 'to:addr:python.org': 0.40; 'type': 0.61; 'design': 0.61; 'property': 0.63; 'skip:w 30': 0.63; 'strategy': 0.64; 'factory': 0.73; 'satisfied': 0.84; 'critics': 0.84; 'hook': 0.84; 'sheets': 0.84; 'sheet': 0.96
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject :content-type:content-transfer-encoding; bh=NtTSiLyyN9d6gmDfzHM8gNjx69Ug4Z6Ke2ogoHJ41Oo=; b=JjF7OgGuoroKk2aTrh/NdZFE6kIxxkRL0uFgGx3XLZ/gwlw+XzDQRRSwEglHMjn45q j/jfyy1yEs5y0T/KYVMOZ0NC0fr1kQHkBHyT9Ti0HhVxkWlRZ0U7pRUDjf+0IJNgIP6L QzEO6pYflOW48IPHt32rSVKHXhgnKF+RXod94=
Date Wed, 23 Nov 2011 19:04:54 +0100
From Karim <kliateni@gmail.com>
User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20110929 Thunderbird/7.0.1
MIME-Version 1.0
To tutor@python.org, python-list@python.org
Subject Template class and class design on concrete example xl2csv writer
Content-Type text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding 7bit
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.12
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <http://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <http://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.2978.1322071503.27778.python-list@python.org> (permalink)
Lines 155
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1322071503 news.xs4all.nl 6949 [2001:888:2000:d::a6]:46196
X-Complaints-To abuse@xs4all.nl
Xref x330-a1.tempe.blueboxinc.net comp.lang.python:16121

Show key headers only | View raw


Hello All,

I have the following code and I am quite satisfied with its design BUT I 
have the feeling I can do better.
Basically the, main() execute the program (I did not put the parsing of 
arguments function). I am opening
an Excel document and writing content in a CSV one w/ different format. 
The design is an abstract template
class XLWriter, and derived  'Xl2Csv', 'Xl2Scsv', 'Xl2text' classes to 
write the correct ASCII DOCUMENT to correct format.
The property hook method file_format is implement in these classes and 
return an object of type 'XlCsvFileFormat' or 'XlTabFileFormat'.
It allows to put the right file extension and delimiter. These class are 
derived from standard csv.excel and csv.excel_tab.
At last a Factory class MakeXlWriter has the job to create the correct 
writer.

For now I did not add a strategy pattern which usually goes with the 
Template pattern.

Except from that all better design or others critics will be welcome.


Regards
karim

_______________________________________________________________________________________________________________________________________

from __future__ import print_function

import sys, os, argparse, csv, xlrd

__all__  = ['main', 'Xl2CsvError', 'XLWriter', 'XlCsvFileFormat', 
'XlTabFileFormat', 'Xl2Csv', 'Xl2Scsv', 'Xl2text', 'MakeXlWriter']


class Xl2CsvError(Exception):
     """The exception class to manage the internal program errors."""
     pass

class XlWriter(object):
     """Abstract template class."""
     def __init__(self, xlfilename=None, sheets=None):
         """Initializer."""
         if self.__class__.__name__ == 'XlWriter':
             raise TypeError('Abstract template Class XlWriter could not 
be instanciated directly!')

         if not xlfilename:
             raise Xl2CsvError('Please provide a non empty file name!')
         else:
             self._source_name = xlfilename

         self._book = xlrd.open_workbook(xlfilename)

         if sheets is not None:
             if isinstance(sheets[0], int):
                 self._selected_sheets = 
[self._book.sheet_by_index(sheetnum-1) for sheetnum in sheets]
             elif isinstance(sheets[0], str):
                 try:
                     self._selected_sheets = 
[self._book.sheet_by_name(sheetname) for sheetname in sheets]
                 except xlrd.biffh.XLRDError, e:
                     print('{0} in file document {1}'.format(e, xlfilename))
                     sys.exit(1)
             else:
                 raise Xl2CsvError('Sheets element type not recognized!')
         else:
             self._selected_sheets = self._book.sheets()

     def write(self):
         """The file extraction public method."""

         for sheet in self._selected_sheets:
             xlfilename = '{sheet}{ext}'.format(sheet=sheet.name, 
ext='.'+self.file_format.extension.lower())
             try:
                 writer = csv.writer(open(xlfilename, 'wb'), 
delimiter=self.file_format.delimiter)
                 print("Creating csv file '{file}' for sheet '{sheet}' 
contained in document {src} ...".format(
                        sheet=sheet.name, file=xlfilename, 
src=self._source_name), end=' ')
                 for row in xrange(sheet.nrows):
                     writer.writerow(sheet.row_values(row))
                 print('Done.')
             except csv.Error, e:
                 print(e)
                 return 1

         return 0

     @property
     def file_format(self):
         """Hook method. Need to implement in derived classes.

         Should return an XLAsciiFileFormat object to get file extension 
and inner delimiter.
         """
         pass

class XlCsvFileFormat(csv.excel):
     """Add file extension to the usual properties of Excel-generated 
CSV files."""
     extension = 'CSV'

class XlTabFileFormat(csv.excel_tab):
     """Add file extension to the usual properties of Excel-generated 
<TAB> delimited files."""
     extension = 'TXT'

class Xl2Csv(XlWriter):
     @property
     def file_format(self):
         """Hook factory method"""
         return  XlCsvFileFormat()

class Xl2Scsv(XlWriter):
     @property
     def file_format(self):
         """Hook factory method"""
         _format = XlCsvFileFormat()
         _format.extension = 'SCSV'
         _format.delimiter = ';'
         return _format

class Xl2Text(XlWriter):
     @property
     def file_format(self):
         """Hook factory method"""
         return  XlTabFileFormat()

class MakeXlWriter(object):
     """Factory class for XLWriter objects.
     """
     @staticmethod
     def make(xlfilename=None, sheets=None, extension='CSV'):
         if extension == "TXT":
            return Xl2Text(xlfilename=xlfilename, sheets=sheets)
         elif extension == "SCSV":
            return Xl2Scsv(xlfilename=xlfilename, sheets=sheets)
         elif extension == "CSV":
            return Xl2Csv(xlfilename=xlfilename, sheets=sheets)

def main():
     """Main of this application"""
     args = _process_command_line()
     args.xl.close()
     writer = MakeXlWriter.make(xlfilename=args.xl.name, 
sheets=args.sheets, extension=args.ext)
     return writer.write()

___________________________________________________________________________________________________________________________

Back to comp.lang.python | Previous | Next | Find similar | Unroll thread


Thread

Template class and class design on concrete example xl2csv writer Karim <kliateni@gmail.com> - 2011-11-23 19:04 +0100

csiph-web