<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def lineage(self, tax_id=None, tax_name=None):
 """Public method for returning a lineage; includes tax_name and rank """


        if not bool(tax_id) ^ bool(tax_name):
            msg = 'Exactly one of tax_id and tax_name may be provided.'
            raise ValueError(msg)

        if tax_name:
            tax_id, primary_name, is_primary = self.primary_from_name(tax_name)
        else:
            primary_name = None

        # assumes stable ordering of lineage from root --> leaf
        lintups = self._get_lineage(tax_id)
        ldict = dict(lintups)

        ldict['tax_id'] = tax_id
        try:
            # parent is second to last element, except for root
            __, ldict['parent_id'] = lintups[-2]
        except IndexError:
            ldict['parent_id'] = None

        ldict['rank'], __ = lintups[-1]  # this taxon is last element in lineage
        ldict['tax_name'] = primary_name or self.primary_from_id(tax_id)

        return ldict