Historical note. As originally conceived,
the taxonomic tree was stored within the Txny
class in an attribute named .root that contained
a Taxon instance representing the root taxon
(Class Aves). So that we can support lookup of taxa by
scientific name or taxonomic key number, we must maintain two
dictionaries along with the tree that map scientific name and
key number to the corresponding taxon.
The operation of adding a taxon to the tree occurs in two places. Most are added while reading the standard forms file. However, subspecific taxa are added to the tree during processing of the alternate forms file. In the Cleanroom intended functions for this operation, three state items were affected: the tree itself, the scientific name map, and the taxonomic key map. The whole point of using classes to create abstract data types is to hide this kind of detail.
Therefore, the taxonomic tree and its associated dictionaries
were moved to this new class, TaxaTree. A number
of methods that were originally in the Txny class
are here because they pertain to the tree, rather than to the
bird code system.
Here is the interface:
# - - - - - c l a s s T a x a T r e e
class TaxaTree(object):
'''Represents the strictly taxonomic tree.
Exports:
TaxaTree ( hier ):
[ hier is a Hier instance ->
return a new, empty TaxaTree instance using the
ranks from hier ]
.hier: [ as passed to constructor, read-only ]
.root:
[ if self is empty -> None
else ->
the root taxon as a Taxon instance with rank.depth==0,
and rooting a tree such that children of any node
have depth greater than that of their parent,
all the children of a node have the same depth,
and the children of a node may not be deeper
than the shallowest required rank deeper than
that of the parent ]
.setRoot ( taxon ):
[ taxon is a Taxon instance ->
if (self is empty) and
(taxon's depth is 0) ->
self := self with taxon as its root
else -> raise ValueError ]
.rankParent ( newRankCode ):
[ newRankCode is the code for a rank in self.hier ->
if a taxon of that rank can be added to self as
its last node in preorder ->
return rank-parent ( self, that rank )
else -> raise ValueError ]
.canAddChild ( parent, childRankCode ):
[ (parent is a Taxon in self) and
(childRankCode is the code of a Rank in self.hier) ->
if can-add-child(self.hier, parent, that rank) ->
return None
else -> raise ValueError ]
.addTaxon ( parent, rawTaxon ):
[ (parent is a taxon in self, or None for the root) and
(rawTaxon is a RawTaxon instance) and
(can-add-child(parent, rawTaxon)) ->
parent := parent with a new child Taxon added, made
from rawTaxon
return that new Taxon ]
.lookupTxKey ( txKey ):
[ txKey is a string ->
if txKey matches the taxonomic key of a taxon in self ->
return that taxon
else -> raise KeyError ]
.__getitem__ ( sci ):
[ sci is a string ->
if sci matches the name of a taxon in self ->
return that taxon
else -> raise KeyError ]
.__contains__(self, sci):
[ if sci is a scientific name in self ->
return True
else -> return False ]
.writeXML ( parent ):
[ parent is an et.Element ->
parent := parent with an rnc.TAXONOMY_N element
added representing self's taxonomic tree ]
Here are the internals of the class.
State/Invariants:
.__sciMap:
[ a dictionary whose keys are the scientific names of
the taxa in self, and each related value is that
Taxon instance ]
.__txKeyMap:
[ a dictionary whose keys are the taxonomic key numbers
of the taxa in self, and each related value is that
Taxon instance ]
'''