Anticipating that derived classes may do almost anything differently from each other, we try to restrict the code in the constructor to contain only operations that are always the same. Accordingly, the constructor calls a few generalized methods, any of which can be replaced in a derived class.
# - - - B a s e C o m p i l e r . _ _ i n i t _ _ - - -
def __init__(self, fileName, stationSet, speciesSet):
'''Constructor for BaseCompiler.
'''
One thing we'll always do is to remember the station and species authority objects, and initialize all the internal state items.
#-- 1 --
self.fileName = fileName
self.stationSet = stationSet
self.speciesSet = speciesSet
self.pageHeader = None
self.prefix = None
self.oldEncounter = None
Next we need to analyze the fileName to
insure that it conforms to the batch file naming scheme.
This step will also set the .location and
.station state items. See Section 19.4, “BaseCompiler.parseFileName(): Parse the
batch file name”.
#-- 2 --
# [ if self.fileName conforms to the batch file naming scheme and
# represents a multi-station location in self.stationSet ->
# self.location := a Location object representing that
# location
# self.station := None
# self.year := year from self.fileName
# else if self.fileName conforms to the batch file naming
# scheme and represents a single-station location in
# self.stationSet ->
# self.location := None
# self.station := a Station object representing that
# station
# self.year := year from self.fileName
# else ->
# Log() +:= error message(s)
# raise ValueError ]
self.parseFileName()
All that remains is to attempt to open the input file for
reading, using the Scan class. The callback keyword argument is used to report our
current band size and page number as part of each error
message; see Section 19.8, “BaseCompiler.scanCallback(): Error
localization string”.
This is an interesting use of Python's “bound
method” feature. The reference to self.scanCallback gives us an object of function
type, but the current value of “self” is bound into it. Hence, it can be called by
the scan object, even though scan has no idea where to find the BaseCompiler object that contains the band
size and page number that we need to see in any syntax
error message.
#-- 3 --
# [ if self.fileName can be opened for reading ->
# self.scan := a Scan object pointing at the start
# of that file
# else ->
# Log() +:= error message(s)
# raise ValueError ]
try:
self.scan = Scan(self.fileName,
callback=self.scanCallback)
except IOError, detail:
message = ("Can't open input file '%s': %s" %
(self.fileName, detail))
Log().error(message)
raise ValueError, message
Processing will continue when the caller calls our .__iter__() method.