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 ] '''
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
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
.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
getattr() or otherwise references an
undefined attribute. We can simply define that method so
that any attempt to retrieve an undefined attribute will
For details of see Customizing attribute access in the Python online documentation.
So, to sum up, here is the life cycle of a
The caller passes a
(with the context of the record) and a
instance (with the raw encounter record) to the class
method starts out with a
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
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
on that instance to convert the content into a flat
file record represented as a single string.
.flatten() method uses a class
.OUT_FIELD_LIST to do
the flattening. This is a list of tuples
(, in output order,
is the name of a class that has a static
the name of the attribute in the
BaseEncounter instance. For each pair in
OUT_FIELD_LIST, we extract the value
of the given
getattr(), so that we get either the stored
None if the field was never
.flatten() methods in those
classes take an argument that is either an instance
of the class, or the value
it is an instance, the
method should format that instance's value as a
fixed-length format string. If the argument is
should return a string of blanks of the same size.
Therefore, the definitive list of field names for each
derived variant of the
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