def METHOD_NAME(self, expr, affine_above: bool) -> Tuple[Expression, list]:
    """Recursively canonicalize an Expression.
    Parameters
    ----------
    expr : The expression tree to canonicalize.
    affine_above : The path up to the root node is all affine atoms.
    Returns
    -------
    A tuple of the canonicalized expression and generated constraints.
    """
    # TODO don't copy affine expressions?
    if type(expr) == cvxtypes.partial_problem():
        canon_expr, constrs = self.METHOD_NAME(
          expr.args[0].objective.expr, False)
        for constr in expr.args[0].constraints:
            canon_constr, aux_constr = self.METHOD_NAME(constr, False)
            constrs += [canon_constr] + aux_constr
    else:
        affine_atom = type(expr) not in self.cone_canon_methods
        canon_args = []
        constrs = []
        for arg in expr.args:
            canon_arg, c = self.METHOD_NAME(arg, affine_atom and affine_above)
            canon_args += [canon_arg]
            constrs += c
        canon_expr, c = self.canonicalize_expr(expr, canon_args, affine_above)
        constrs += c
    return canon_expr, constrs