def test_degen(self):
     s = UnnamedOpetopicSet.point(UnnamedOpetopicSet.Sequent(), "x")
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.degen(s, "y")
     s = UnnamedOpetopicSet.degen(s, "x")
     self.assertIsNotNone(s.pastingDiagram.degeneracy)
     self.assertEqual(s.pastingDiagram.degeneracy, "x")
     self.assertIsNone(s.pastingDiagram.nodes)
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.degen(s, "x")
def tfill(seq: UnnamedOpetopicSet.Sequent, targetName: str,
          fillerName: str) -> UnnamedOpetopicSet.Sequent:
    """
    This function takes a :class:`opetopy.UnnamedOpetopicSet.Sequent`, (recall
    that the context of a sequent derivable in :math:`\\textbf{OptSet${}^?$}`
    is a finite opetopic set) typing a pasting diagram :math:`\\mathbf{P}`, and
    solves the Kan filler problem by adding

    * a new cell :math:`t` with name ``targetName``;
    * a new cell :math:`\\alpha : \\mathbf{P} \\longrightarrow t` with name
      ``fillerName``.

    """
    if seq.pastingDiagram is None:
        raise DerivationError(
            "Kan filling, target",
            "Argument sequent expecting to type a pasting diagram")

    # Source of alpha
    P = seq.pastingDiagram
    tPshapeProof = UnnamedOpetope.ProofTree(P.shapeTarget().toDict())

    # Start deriving
    res = deepcopy(seq)
    res.pastingDiagram = None

    # Derive t
    if P.shape.dimension - 1 == 0:
        # t is a point
        res = UnnamedOpetopicSet.point(res, targetName)
    else:
        # Set u, target of t
        if P.shape.isDegenerate:
            u = P.degeneracyVariable()
        else:
            u = seq.context.target(
                P.source(UnnamedOpetope.address([], P.shape.dimension - 1)))
        # Derive Q, source of t
        if P.shapeTarget().isDegenerate:
            Q = UnnamedOpetopicSet.pastingDiagram(tPshapeProof,
                                                  seq.context.target(u))
        else:
            nodes = {}  # type: Dict[UnnamedOpetope.Address, str]
            if P.shape.isDegenerate:
                nodes[UnnamedOpetope.address([], P.shape.dimension - 2)] = \
                    P.degeneracyVariable()
            else:
                readdress = P.shapeProof.eval().context
                for l in P.shape.leafAddresses():
                    p, q = l.edgeDecomposition()
                    nodes[readdress(l)] = seq.context.source(P[p], q)
            Q = UnnamedOpetopicSet.pastingDiagram(tPshapeProof, nodes)
        if Q.shape.isDegenerate:
            res = UnnamedOpetopicSet.degen(res, Q.degeneracyVariable())
        else:
            res = UnnamedOpetopicSet.graft(res, Q)
        # Derive t, target of alpha
        res = UnnamedOpetopicSet.shift(res, u, targetName)

    # Derive P, source of alpha
    if P.shape.isDegenerate:
        res = UnnamedOpetopicSet.degen(res, u)
    else:
        res = UnnamedOpetopicSet.graft(res, P)

    # Derive alpha
    res = UnnamedOpetopicSet.shift(res, targetName, fillerName)

    # Mark t as universal in the type of alpha
    rawFillerType = res.context[fillerName].type
    fillerType = Type(rawFillerType.source, rawFillerType.target)
    fillerType.targetUniversal = True
    res.context[fillerName].type = fillerType

    # Done
    return res