Function Repository Resource:

FlattenFailure

Source Notebook

Merge nested failure information

Contributed by: Sjoerd Smit

ResourceFunction["FlattenFailure"][Failure[]]

checks a failure for nested Failure objects and puts all the information in the "Information" field of the main object.

ResourceFunction["FlattenFailure"][fail, handler]

applies handler to nested Failure objects and puts the result in the in the "Information" field of the main object.

ResourceFunction["FlattenFailure"][expr,]

returns expr if it's not a Failure object.

Details

The default handler is Function[#["Information"]].
The handler is also allowed to be a String that extracts a property from Failure objects.
FlattenFailure will also make the failure messages more readable by replacing nested failures inside the message with an elided form.

Examples

Basic Examples (4) 

Nested failures can occur when multiple instances of Enclose/Confirm are nested inside each other:

In[1]:=
fail = Enclose[
  ConfirmBy[
   Enclose[
    ConfirmBy[1, EvenQ, "Expected an even number at lvl 2"]
    ],
   IntegerQ,
   "Expected an integer at lvl 1"
   ]
  ]
Out[1]=

The "Information" property of the Failure object only holds the outer message:

In[2]:=
fail["Information"]
Out[2]=

FlattenFailure makes the messages more readable and finds the messages embedded inside deeper Failure objects and puts them in the outer object to make it easy to see the trace of everything that went wrong:

In[3]:=
newFailure = ResourceFunction["FlattenFailure"][fail]
Out[3]=
In[4]:=
newFailure["Information"]
Out[4]=

Use the Identity handler to extract all internal Failure objects and display them:

In[5]:=
ResourceFunction["FlattenFailure"][fail, Identity][
  "Information"] // Column
Out[5]=

Scope (2) 

Anything that's not a Failure object will simply be returned:

In[6]:=
ResourceFunction["FlattenFailure"][1 + 1]
Out[6]=
In[7]:=
ResourceFunction["FlattenFailure"][$Failed]
Out[7]=

The handler can also be a property to extract from a Failure object:

In[8]:=
fail = Failure[
  "ConfirmationFailed", <|"MessageTemplate" -> "``[``] did not return True.", "MessageParameters" :> {IntegerQ, 
Failure["ConfirmationFailed", <|"MessageTemplate" -> "``[``] did not return True.", "MessageParameters" :> {EvenQ, 1}, "ConfirmationType" -> "ConfirmBy", "Expression" :> 1, "Function" :> EvenQ, "Information" :> "Expected an even number at lvl 2"|>]}, "ConfirmationType" -> "ConfirmBy", "Expression" :> Failure[
     "ConfirmationFailed", <|"MessageTemplate" -> "``[``] did not return True.", "MessageParameters" :> {EvenQ, 1}, "ConfirmationType" -> "ConfirmBy", "Expression" :> 1, "Function" :> EvenQ, "Information" :> "Expected an even number at lvl 2"|>], "Function" :> IntegerQ, "Information" :> "Expected an integer at lvl 1"|>];
ResourceFunction["FlattenFailure"][fail, "Expression"]["Information"]
Out[9]=

Applications (1) 

Use FlattenFailure before functions with Enclose to automatically collect all messages as they accumulate:

In[10]:=
ClearAll[f1, f2, f3];
f1[x_] := ResourceFunction["FlattenFailure"]@Enclose[
    ConfirmBy[x, EvenQ, "f1 only works with even numbers"]
    ];
f2[x_] := ResourceFunction["FlattenFailure"]@Enclose[
    1 + ConfirmBy[f1[x], IntegerQ, "Something went wrong in f2"]
    ];
f3[x_] := ResourceFunction["FlattenFailure"]@Enclose[
    ConfirmBy[f2[x], NumericQ, "Something went wrong in f3"]^2
    ];
In[11]:=
err = f3[1]
Out[11]=
In[12]:=
err
Out[12]=
In[13]:=
err["Information"]
Out[13]=

Possible Issues (2) 

If the info messages themselves are lists, the default handler will flatten them out as well:

In[14]:=
fail = Enclose[
   ConfirmBy[
    Enclose[
     ConfirmBy[1, EvenQ, {"Expected an even number", " at lvl 2"}]],
    IntegerQ,
    {{"Expected", " an integer"}, {" at lvl 1"}}
    ]
   ];
ResourceFunction["FlattenFailure"][fail]["Information"]
Out[15]=

Use an inert wrapper to keep the lists intact:

In[16]:=
ResourceFunction["FlattenFailure"][fail, Framed[#["Information"]] &]["Information"]
Out[16]=

Duplicate messages will be shown only once:

In[17]:=
fail = Enclose[
   ConfirmBy[
    Enclose[ConfirmBy[1, EvenQ, "Oops"]],
    IntegerQ,
    "Oops"
    ]
   ];
ResourceFunction["FlattenFailure"][fail]["Information"]
Out[18]=

Use the Identity handler to catch all the different failure objects:

In[19]:=
ResourceFunction["FlattenFailure"][fail, Identity]["Information"]
Out[19]=

Publisher

Sjoerd Smit

Version History

  • 1.0.0 – 01 May 2023

Related Resources

License Information