This class is the abstract base class for output encounter records. Here is the interface:
# - - - - - c l a s s B a s e E n c o u n t e r - - - - -
class BaseEncounter:
'''Abstract base class for output encounter records.
Exports:
BaseEncounter(compiler):
[ compiler is a BaseCompiler object ->
return a new BaseEncounter object with that compiler ]
.compiler: [ as passed to constructor, read-only ]
.captureCode: [ CaptureCodeField, or None ]
.flatten():
[ return self as a string containing a flat-file record ]
BaseEncounter.scanLine(compiler, scan): # Static method
[ (compiler is a BaseCompiler object) and
(scan is a Scan object) ->
if the line in scan is a valid encounter record
in the context of compiler ->
scan := scan advanced no farther than end of line
return a new BaseEncounter object representing
that line
else ->
Log() +:= error message
raise SyntaxError ]
'''
The BaseEncounter object, and classes
derived from it, are the workhorse data structures for
representing most of the data on the banding sheet.
In practice, an instance may have many fields, one for each possible field on the banding sheet. However, the exact set of fields will be different for each protocol. For example, the MAPS 2006 protocol does not allow for color bands, but MAWS 2004 protocol does.
Also, some instances may have only a few attributes. For example, the representation of a destroyed band will contain very little other than the band number.
So what we want is an object that holds a set of named
values. So far that sounds like a Python dictionary.
However, we want more than just a dictionary; we want to
be able to add methods such as .flatten()
to the object to translate it into flat-file form.
It is quite straightforward to use regular Python
attributes to store the fields of the encounter record.
One possibility is to have the constructor create all the
fields that may be used, and set each unused field to
None; fields actually used in the input
record will be copied over those values as they are
parsed, using the Python function setattr(. Then the
object,
name).flatten() method will fill in a blank
field of the appropriate size for each field that never
had a value stored into it.
However, there is a way to avoid this process of setting
each field to None initially. Python
allows a class to define a special method called .__getattr__() that is called whenever the user
uses getattr() or otherwise references an
undefined attribute. We can simply define that method so
that any attempt to retrieve an undefined attribute will
return None.
For details of see Customizing attribute access in the Python online documentation.
So, to sum up, here is the life cycle of a BaseEncounter object:
The caller passes a BaseCompiler instance
(with the context of the record) and a Scan
instance (with the raw encounter record) to the class
method BaseEncounter.scanLine(). That
method starts out with a BaseCompiler
instance with only a few attributes filled in.
As field values are recognized in the encounter
record, their values are stored in attributes of the
BaseEncounter record using Python's
setattr() function. For example, if
we have an encounter record enc and
an age code as an AgeCodeField object named age, we store the
value like this:
setattr(enc, 'ageCode', age)
Assuming the encounter record is valid, the BaseEncounter.scanLine() method returns the
instance to the caller.
The caller uses the .flatten()method
on that instance to convert the content into a flat
file record represented as a single string.
The .flatten() method uses a class
attribute called .OUT_FIELD_LIST to do
the flattening. This is a list of tuples (, in output order,
where the class, fieldName) is the name of a class that has a static
method named class.flatten(), and is
the name of the attribute in the fieldNameBaseEncounter instance. For each pair in
OUT_FIELD_LIST, we extract the value
of the given using fieldNamegetattr(), so that we get either the stored
value, or None if the field was never
stored.
The .flatten() methods in those
classes take an argument that is either an instance
of the class, or the value None. If
it is an instance, the .flatten()
method should format that instance's value as a
fixed-length format string. If the argument is None, the .flatten() method
should return a string of blanks of the same size.
Therefore, the definitive list of field names for each
derived variant of the BaseEncounter class
will be in its class variable .OUT_FIELD_LIST. Each bit of field-processing
logic should use the field name from that list to store
its result.