[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