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 <[EMAIL PROTECTED]> To: Kent Johnson <[EMAIL PROTECTED]> [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> ------------------------------------------------------- _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor