[Tutor] Posting a large amount of code?

Bill Burns billburns at pennswoods.net
Sun Jan 16 16:49:30 CET 2005


I accidentally sent my reply to Kent only. So I'm forwarding it to the list.
Bill
----------  Forwarded Message  ----------

Subject: Re: [Tutor] Posting a large amount of code?
Date: Sunday 16 January 2005 10:14 am
From: Bill Burns <billburns at pennswoods.net>
To: Kent Johnson <kent37 at tds.net>

[Bill]
<SNIP>

> I guess my question is, would it be acceptable to post this much code to
> the list? Maybe this really isn't a lot of code, but it seems like a lot to
> me, so I figured I'd ask first.

<SNIP>

[Kent]

> I don't know if there is any convention for how much code is too much to
> post. If you have a web site you could put it on that is a good
> alternative. I don't mind if you just post it...

[Bill]
Thanks for the reply Kent. I don't have a web site so I guess that option is
ruled out. So if you don't mind the post (and hopefully nobody else minds)
here we go............ I appreciate all feedback.

Thanks,

Bill

<CODE>

#! /usr/bin/env python

"""
    pipeCalc.py - Calculates various data about HVAC/Plumbing pipe.

    This program calculates the following data:

        A). Total volume (US gallons) of water inside the pipe.
        B). The weight of the water inside the pipe (weight based on 60 F).
        C). The actual weight of the pipe, itself.

    The only input required from the user, is a pipe length (in feet).

    Currently the program works on the following types of pipe:

        A). Carbon Steel (Standard)
        B). Carbon Steel (Extra Strong)
        C). Copper (Type L)
        D). PVC (Schedule 40)
        E). PVC (Schedule 80)
        F). PEX tubing.

    All of the pipe calculations and totals can be written out to a csv file.
    After the report is written to disk, the user is given the option to open
    the report. I've also provided a method to write out the data that is
    used in making all of the calculations. This method writes to disk a file
    called PipeData.csv.

    I built the GUI using QT Designer and pyuic. The GUI is a separate module
    which is imported into this module. There's also a separate dialog which
    was created and gets imported in the same manner. The GUI contains a
    tabbed widget with multiple pages (tabs). Each page corresponds to a
    specific type of pipe. There are multiple lineEdits on each page, with
    each lineEdit representing a different size of pipe. The user selects a
    page representing a certain type of pipe and then enters the pipe length
    into the lineEdit corresponding to the size they want. The GUI also has a
    lineEdit separate from the others which displays the total gallons of
    water. This total is continuously updated as the user enters pipe
 lengths. The GUI also contains four pushButtons. They are labeled and
 function as follows:

        A). Report - after all data is entered, the user clicks this button
            and the PipeReport is written. A dialog will then popup allowing
            the report to be opened.
        B). Pipe Data - writes to disk the pipe specifications that are used
            to calculate all of the data. A dialog will popup allowing the
            user to write out the data for *all* pipes or the user has the
            option to choose any combination of individual pipe(s).
        C). Clear - clears the user input from all lineEdits.
        D). Exit - exits the program.

    I've also provided access to all of the above functions/methods via a
    popup menu that is shown when the user right-clicks on the form.

    The dictionary (pipeDict) holds all of the various data pertaining to the
    pipes. The dict *key* holds the following information (in this order):

        0). lineEdit - This is the name of the the lineEdit which corresponds
            to a specific type and size of pipe as shown on the GUI. The
            numbering scheme provides the correct sort - Thanks, Bob ;)

        1). material type - The type of pipe, I.e., Steel, Copper, Plastic.

        2). size - The size designation of the pipe, expressed in inches.

        3). weight - The weight of the pipe per foot (LBS).

    The dict *value* holds the inside diameter of each pipe. This value is
    used for calculating volume.
"""

pipeDict = \
{
('lineEdit001','Copper(Type L)','1/2"',.285): .585,
('lineEdit002','Copper(Type L)','3/4"',.455): .83,
('lineEdit003','Copper(Type L)','1"',.655): 1.075,
('lineEdit004','Copper(Type L)','1-1/4"',.884): 1.32,
('lineEdit005','Copper(Type L)','1-1/2"',1.14): 1.565,
('lineEdit006','Copper(Type L)','2"',1.75): 2.055,
('lineEdit007','Copper(Type L)','2-1/2"',2.48): 2.545,
('lineEdit008','Copper(Type L)','3"',3.33): 3.035,
('lineEdit009','Copper(Type L)','3-1/2"',4.29): 3.525,
('lineEdit010','Copper(Type L)','4"',5.38): 4.015,
('lineEdit011','Copper(Type L)','5"',7.61): 5.00,
('lineEdit012','Copper(Type L)','6"',10.2): 5.985,
('lineEdit013','Copper(Type L)','8"',19.3): 7.925,
('lineEdit014','Copper(Type L)','10"',30.1): 9.875,
('lineEdit015','Copper(Type L)','12"',40.4): 11.845,

('lineEdit016','PEX Tubing','1/4"',.0261): .25,
('lineEdit017','PEX Tubing','3/8"',.0413): .35,
('lineEdit018','PEX Tubing','1/2"',.0535): .475,
('lineEdit019','PEX Tubing','5/8"',.0752): .574,
('lineEdit020','PEX Tubing','3/4"',.1023): .671,
('lineEdit021','PEX Tubing','1"',.1689): .863,
('lineEdit022','PEX Tubing','1-1/4"',.2523): 1.053,
('lineEdit023','PEX Tubing','1-1/2"',.3536): 1.243,
('lineEdit024','PEX Tubing','2"',.6010): 1.629,

('lineEdit025','PVC(Sch40)','1/2"',.16): .731,
('lineEdit026','PVC(Sch40)','3/4"',.22): .937,
('lineEdit027','PVC(Sch40)','1"',.32): 1.182,
('lineEdit028','PVC(Sch40)','1-1/4"',.43): 1.52,
('lineEdit029','PVC(Sch40)','1-1/2"',.52): 1.755,
('lineEdit030','PVC(Sch40)','2"',.7): 2.221,
('lineEdit031','PVC(Sch40)','2-1/2"',1.1): 2.672,
('lineEdit032','PVC(Sch40)','3"',1.44): 3.284,
('lineEdit033','PVC(Sch40)','4"',2.05): 4.263,
('lineEdit034','PVC(Sch40)','6"',3.61): 6.345,
('lineEdit035','PVC(Sch40)','8"',5.45): 8.303,
('lineEdit036','PVC(Sch40)','10"',7.91): 10.385,
('lineEdit037','PVC(Sch40)','12"',10.35): 12.344,

('lineEdit038','PVC(Sch80)','1/2"',.21): .693,
('lineEdit039','PVC(Sch80)','3/4"',.28): .896,
('lineEdit040','PVC(Sch80)','1"',.4): 1.136,
('lineEdit041','PVC(Sch80)','1-1/4"',.57): 1.469,
('lineEdit042','PVC(Sch80)','1-1/2"',.69): 1.70,
('lineEdit043','PVC(Sch80)','2"',.95): 2.157,
('lineEdit044','PVC(Sch80)','2-1/2"',1.45): 2.599,
('lineEdit045','PVC(Sch80)','3"',1.94): 3.20,
('lineEdit046','PVC(Sch80)','4"',2.83): 4.163,
('lineEdit047','PVC(Sch80)','6"',5.41): 6.193,
('lineEdit048','PVC(Sch80)','8"',8.22): 8.125,
('lineEdit049','PVC(Sch80)','10"',12.28): 10.157,
('lineEdit050','PVC(Sch80)','12"',17.1): 12.063,

('lineEdit051','Steel(Std)','1/2"',.85): .622,
('lineEdit052','Steel(Std)','3/4"',1.13): .824,
('lineEdit053','Steel(Std)','1"',1.678): 1.049,
('lineEdit054','Steel(Std)','1-1/4"',2.272): 1.38,
('lineEdit055','Steel(Std)','1-1/2"',2.717): 1.61,
('lineEdit056','Steel(Std)','2"',3.652): 2.067,
('lineEdit057','Steel(Std)','2-1/2"',5.79): 2.469,
('lineEdit058','Steel(Std)','3"',7.57): 3.068,
('lineEdit059','Steel(Std)','3-1/2"',9.11): 3.548,
('lineEdit060','Steel(Std)','4"',10.79): 4.026,
('lineEdit061','Steel(Std)','5"',14.62): 5.047,
('lineEdit062','Steel(Std)','6"',18.97): 6.065,
('lineEdit063','Steel(Std)','8"',28.55): 7.981,
('lineEdit064','Steel(Std)','10"',40.48): 10.02,
('lineEdit065','Steel(Std)','12"',49.6): 12.00,
('lineEdit066','Steel(Std)','14"',55): 13.25,
('lineEdit067','Steel(Std)','16"',63): 15.25,
('lineEdit068','Steel(Std)','18"',71): 17.25,
('lineEdit069','Steel(Std)','20"',79): 19.25,
('lineEdit070','Steel(Std)','22"',87): 21.25,
('lineEdit071','Steel(Std)','24"',95): 23.25,
('lineEdit072','Steel(Std)','30"',119): 29.25,
('lineEdit073','Steel(Std)','36"',143): 35.25,
('lineEdit074','Steel(Std)','42"',167): 41.25,
('lineEdit075','Steel(Std)','48"',191): 47.25,

('lineEdit076','Steel(XS)','1/2"',1.087): .546,
('lineEdit077','Steel(XS)','3/4"',1.473): .742,
('lineEdit078','Steel(XS)','1"',2.171): .957,
('lineEdit079','Steel(XS)','1-1/4"',2.996): 1.278,
('lineEdit080','Steel(XS)','1-1/2"',3.631): 1.50,
('lineEdit081','Steel(XS)','2"',5.022): 1.939,
('lineEdit082','Steel(XS)','2-1/2"',7.66): 2.323,
('lineEdit083','Steel(XS)','3"',10.25): 2.90,
('lineEdit084','Steel(XS)','3-1/2"',12.51): 3.364,
('lineEdit085','Steel(XS)','4"',14.98): 3.826,
('lineEdit086','Steel(XS)','5"',20.78): 4.813,
('lineEdit087','Steel(XS)','6"',28.57): 5.761,
('lineEdit088','Steel(XS)','8"',43.39): 7.625,
('lineEdit089','Steel(XS)','10"',54.74): 9.75,
('lineEdit090','Steel(XS)','12"',65.4): 11.75,
('lineEdit091','Steel(XS)','14"',72): 13.00,
('lineEdit092','Steel(XS)','16"',83): 15.00,
('lineEdit093','Steel(XS)','18"',93): 17.00,
('lineEdit094','Steel(XS)','20"',105): 19.00,
('lineEdit095','Steel(XS)','22"',115): 21.00,
('lineEdit096','Steel(XS)','24"',125): 23.00,
('lineEdit097','Steel(XS)','30"',158): 29.00,
('lineEdit098','Steel(XS)','36"',190): 35.00,
('lineEdit099','Steel(XS)','42"',222): 41.00,
('lineEdit100','Steel(XS)','48"',254): 47.50
}

import sys
import os
import types
import csv
from qt import *

try:
    import psyco
    psyco.full()
except ImportError:
        pass

from pipeCalcGUI import PipeForm
from dataform import DataForm

class PipeConnector(PipeForm):
    """This class contains all of the methods used to make all of the pipe
       calculations. First, some connections are made between the buttons on
       the main form and their methods. Then I set the text alignment for
       lineEditTotal. Provide a 'connection' to the DataDialog class and the
       EventFilter class. Create a list (self.lineEdits) to hold all of the
       various data about the lineEdits and pipe, then create a second list
       (self.lineEditIns) to hold all lineEdit instances. The lists are then
       populated. Next, a connection is made to the galCalc() method, the
       text alignment is set on the remaining lineEdits and a validator is
 set that only allows numbers to be entered into the lineEdits.
    """

    def __init__(self, parent=None):
       PipeForm.__init__(self, parent)
       self.connect(self.buttonClear,SIGNAL("clicked()"),
 self.clearLineEdits)
 self.connect(self.buttonExit,SIGNAL("clicked()"),self,SLOT("close()"))
 self.connect(self.buttonPrint,SIGNAL("clicked()"),self.pipeReport)
 self.lineEditTotal.setAlignment(QLineEdit.AlignRight)

       self.dataDialog = DataDialog(self, parent)
       self.connect(self.buttonData,SIGNAL("clicked()"),
                    self.dataDialog.showDialog)

       self.eventfilter = EventFilter(self)
       self.installEventFilter(self.eventfilter)

       self.lineEdits = []
       self.lineEditIns = []
       for name, typ, size, weight in pipeDict:
           ins = getattr(self, name)
           ID = pipeDict[name, typ, size, weight]
           self.lineEdits.append([ins,name,typ,size,weight,ID])
           self.lineEditIns.append(ins)

           self.connect(ins,SIGNAL("textChanged(const QString &)"),
                        self.galCalc)
           ins.setAlignment(QLineEdit.AlignRight)
           validator=QIntValidator(0.00, 9999999.00, ins)
           ins.setValidator(validator)

    def volCalc(self, ID, length):
        """Calculates the volume/gallons of water inside of
           the various pipe.
        """
        from math import pi
        gal = ((ID*.5)**2)*pi*(12*length)/(230.9429931)
        return gal

    def galCalc(self):
        """Displays a running tally of the total gallons for all
           pipe entered into each lineEdit. Recalculates whenever
           the data changes in any of the lineEdits.
        """
        tmp = []
        for ins, name, typ, size, weight, ID in self.lineEdits:
            if name != "lineEditTotal":
                length = ins.displayText()
                if length:
                    length = int(str(length),10)
                    gal = self.volCalc(ID, length)
                    tmp.append(gal)
        total = sum(tmp)
        total = "%0.2f" % total
        self.lineEditTotal.setText(total)

    def pipeReport(self):
        """Calculates the gallons of water, water weight and weight of the
           pipe for each pipe entered. Provides a summation of total gallons,
           total water weight and total pipe weight. Sends the data to
           writeReport() to be written to a csv file.
        """
        if self.lineEditTotal.displayText():
            data = []
            waterWeightTotal = []
            pipeWeightTotal = []
            for ins, name, typ, size, weight, ID in self.lineEdits:
                if name != "lineEditTotal":
                    length = ins.displayText()
                    if length:
                        length = int(str(length))
                        gal = self.volCalc(ID, length)
                        waterWeight = (8.338*gal)
                        waterWeightTotal.append(waterWeight)
                        waterWeightSum = sum(waterWeightTotal)
                        pipeWeight = (weight*length)
                        pipeWeightTotal.append(pipeWeight)
                        pipeWeightSum = sum(pipeWeightTotal)
                        data.append([name,typ,size,ID,length,
                                     gal,waterWeight,pipeWeight])
                        data.sort()
                        filteredData = self.filterPipeData(data)
            self.writeReport('PipeReport.csv',filteredData,
                              waterWeightSum,pipeWeightSum)

    def pipeSpecs(self, pipes):
        """Method to write out the pipe specifications, I.e., material, size
           ID, gallons, water weight & pipe weight. All data is based on one
           (1) foot of pipe. Essentially, I wanted a method that allowed the
           user to see what data is being used for the various calculations.

           The data is then sent to writeReport() to be written to csv file.
           This method is called from within the DataDialog class below.
           Specifically it's called from writeData().
        """
        specs = []
        for pipe in pipes:
            for name, typ, size, weight in pipeDict:
                if pipe == typ:
                    ID = pipeDict[name, typ, size, weight]
                    length = None
                    gal = self.volCalc(ID,1)
                    waterWeight = (8.338*gal)
                    specs.append([name,typ,size,ID,length,
                                     gal,waterWeight,weight])
                    specs.sort()
                    filteredPipeSpec = self.filterPipeData(specs)
        self.writeReport('PipeData.csv',filteredPipeSpec,None,None)

    def writeReport(self, fname, data, wwSum, pwSum):
        """Writes the csv file for both pipeReport() and pipeSpecs(), then
           calls openReport() which prompts the user to open the files.

           The data generated from pipeSpecs() does *not* contain a water
           weight sum (wwSum), pipe weight sum (pwSum) or a pipe length. I
           need to distinguish between the two reports. If 'wwSum == None',
           the method was called from pipeSpecs(), and we write the report
           one way, else it was called from pipeReport() and it is written
           a different way.
        """
        report = file(fname, 'w')
        writer = csv.writer(report) #,dialect='excel')
        if wwSum == None:
            fields = ("Material Type","Size","ID","Gallons/Ft",
                      "Water Weight/Ft", "Pipe Weight/Ft")
            writer.writerow(fields)
            for row in data:
                writer.writerow(row)
            report.close()
            self.openReport(fname)
        else:
            fields = ("Material Type","Size","ID","Pipe Length",
                      "Gallons","Water Weight", "Pipe Weight")
            writer.writerow(fields)
            for row in data:
                writer.writerow(row)
            galTotal = self.lineEditTotal.displayText()
            writer.writerow(("Totals:","","","",galTotal,wwSum,pwSum))
            report.close()
            self.openReport(fname)

    def openReport(self, file):
        """Method to open either PipeReport.csv or PipeData.csv. Opens the
           reports using OpenOffice Calc.
        """
        msgBox = QMessageBox.question(self, "Report",
                        "Report written. Open the Report?",
                        "Yes","No","Cancel",2,-1)
        if msgBox == 0:
            os.popen2('/opt/OpenOffice.org/program/soffice -calc %s' % file)
            #I use CrossOver Office, so I can optionally open the csv files
            #with Excel.
            #os.popen2('~/cxoffice/bin/excel %s' % file)
        else:
            pass

    def filterPipeData(self, data):
        """Method to remove the lineEdit name from the lists. If called by
           pipeSpecs(), also removes the length, as the length is
           not needed in that report.

           I need to incorporate Kent's list comprehension into this!
        """
        fData = []
        for name,typ,size,ID,length,gal,waterWeight,pipeWeight in data:
            if length == None: #True, if called from PipeSpecs()
                fData.append([typ,size,ID,gal,waterWeight,pipeWeight])
            else:
                fData.append([typ,size,ID,length,gal,waterWeight,pipeWeight])
        return fData

    def clearLineEdits(self):
        """Clears the data in all lineEdits.
        """
        for ins in self.lineEditIns:
            ins.clear()
        self.lineEditTotal.setText("")

class DataDialog(DataForm):
    """A class for a dialog which displays options for writing the pipe
       specifications. The dialog contains two radioButtons, six checkboxes
       and two pushButtons. The first radioButton is tagged All Pipe Data and
       is used to write out all of the pipe data (go figure). The second is
       tagged Individual Pipe Data and when it is selected the six checkboxes
       become enabled (they are initally 'grayed out' and not active). Each
       checkbox represents a specific type of pipe and the user has the
 option to select any combination of the six pipe to write to file.
    """

    def __init__(self,parent=None,name = None,modal=1,fl=0):
        DataForm.__init__(self, parent,name,modal,fl)
        self.connect(self.radioButtonAll,SIGNAL("clicked()"), self.selectAll)
        self.connect(self.radioButtonIndivid,SIGNAL("clicked()"),
                     self.selectIndividual)
        self.connect(self.cancelButton,SIGNAL("clicked()"),
                     self,SLOT("close()"))
        self.connect(self.printButton,SIGNAL("clicked()"),self.writeData)

        checkBoxes = ['checkBox1','checkBox2',
                      'checkBox3','checkBox4',
                      'checkBox5','checkBox6']
        self.checkBoxIns = []
        for checkBox in checkBoxes:
            ins = getattr(self, checkBox)
            self.checkBoxIns.append(ins)

    def showDialog(self):
        """This method will 'show' the pipe data dialog. When the dialog is
           shown, the checkBoxes should *not* be checked or enabled and
           radioButtonAll should be checked.
        """
        for checkBox in self.checkBoxIns:
            checkBox.setChecked(0)
        self.radioButtonAll.setChecked(1)
        self.selectAll()
        self.show()

    def selectAll(self):
        """User is selecting all pipe. The checkBoxes are disabled and they
           should not be checked.
        """
        for checkBox in self.checkBoxIns:
            checkBox.setEnabled(0)
            checkBox.setChecked(0)

    def selectIndividual(self):
        """User is selecting individual pipe so enable the checkBoxes.
        """
        for checkBox in self.checkBoxIns:
            checkBox.setEnabled(1)

    def writeData(self):
        """Used to write out the pipe data. This calls the pipeSpecs() method
           in the PipeConnector class.

           If radioButtonAll is checked then all pipe data is written out.
           Else radioButtonIndivid and the user can make individual pipe
           selections via the one of the six checkBoxes.
        """
        self.pipeCon = PipeConnector()
        if self.radioButtonAll.isChecked():
            self.pipeCon.pipeSpecs(('Steel(Std)',
                                    'Steel(XS)',
                                    'Copper(Type L)',
                                    'PVC(Sch40)',
                                    'PVC(Sch80)',
                                    'PEX Tubing'))
            self.close()
        else:
            try:
                pipes = []
                for checkBox in self.checkBoxIns:
                    if checkBox.isChecked():
                        pipe = str(checkBox.text())
                        pipes.append(pipe)
                self.pipeCon.pipeSpecs(pipes)
                self.close()
            except UnboundLocalError:
                QMessageBox.warning(self, "Selection Error",
                                    "Please select a pipe.", "OK")

class PopupMenu(QPopupMenu):
    """class for a pop-up menu used in the EventFilter class. The popup will
       be displayed at the current cursor position.
    """

    def __init__(self, parent=None):
        QPopupMenu.__init__(self, parent)

    def showMenu(self):
        self.exec_loop(QCursor.pos())

class EventFilter(PipeConnector):
    """This will show the popup menu, when a right mouse click event occurs.
       The pop-up displays various functions available to the user. Most of
       these functions are also available via buttons on the 'main' form. Two
       functions that are only available here are fill() and writeDict().
    """

    def __init__(self, parent):
        PipeForm.__init__(self, parent)
        self.parent = parent

    def eventFilter(self, object, event):
        if event.type() == QEvent.MouseButtonPress and \
        event.button() == QMouseEvent.RightButton:
            pm = PopupMenu()
            pm.insertItem("Pipe Report", self.report)
            pm.insertItem("Pipe Data", self.pipeData)
            pm.insertItem("Clear", self.clr)
            pm.insertItem("Fill w/100's", self.fill)
            pm.insertItem("Write Dict to File", self.writeDict)
            pm.insertItem("Exit Pipe Calc", self.closePipeCalc)
            pm.showMenu()
            return 1
        return 0

    def report(self):
        """Calls the pipeReport() method in the PipeConnector class.
        """
        self.parent.pipeReport()

    def pipeData(self):
        """Calls showDialog() in the DataDialog class, which in turn calls
           pipeSpecs() in the PipeConnector class.
        """
        dd = DataDialog(self)
        dd.showDialog()

    def clr(self):
        """Calls the clearLineEdits() method in the PipeConnector class.
        """
        self.parent.clearLineEdits()

    def fill(self):
        """Fills all lineEdits will a value of '100'. Used just for testing.
        """
        for ins in self.parent.lineEditIns:
            ins.setText("100")

    def writeDict(self):
        """Writes the dict (pipeDict) to a text file. The last line (which is
           commented out) can 'import' the file as 'importedpipeDict.

           Found this on comp.lang.python. Not sure where I'm going with this
           but I'm thinking of taking the pipeDict out of this module and
           putting it into a separate config file/module. Then at runtime,
           I'll load the dict from that file. I'm thinking if the dictionary
           is separate from this module, I can provide user access to the
           data. Then maybe thru an interface, the user could see, adjust, or
           change the pipe data. Who knows?
        """
        print >>file('pipeDict.txt','w+'),str(pipeDict)
        #exec('importedpipeDict=dict('+file('pipeDict.txt','r').read()+')')

    def closePipeCalc(self):
        """Exit the program."""
        self.parent.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    QObject.connect(app, SIGNAL("lastWindowClosed()"),
                    app, SLOT("quit()"))
    win = PipeConnector()
    app.setMainWidget(win)
    win.show()
    app.exec_loop()

</CODE>

-------------------------------------------------------


More information about the Tutor mailing list