Function Repository Resource:

MessageReplace

Source Notebook

Modify any messages generated during an evaluation using a set of replacement rules

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["MessageReplace"][eval,rules]

transforms any messages that are issued during evaluation of eval using rules.

ResourceFunction["MessageReplace"][eval,rules,replacer]

uses the replacement function replacer to make transformations.

Details and Options

In ResourceFunction["MessageReplace"][eval,rules,replacer], the value for replacer can be any of the following:
Automaticchoose a replacement function automatically based on rules
Allequivalent to ReplaceRepeated.
"type"a predefined replacement function
funcan arbitrary replacement function
The value for "type" specifies which part of Message[symbol::tag,arg1,arg2,] is replaced and can be one of the following:
"Symbol"replaces symbol
"Tag"replaces tag
"Parameters"replaces in the arg1,arg2,
If a message is modified via the given replacements, the original message is not issued, so it cannot be caught with other handlers such as Check.

Examples

Basic Examples (4) 

Change which symbol a message is issued from:

In[1]:=
ResourceFunction["MessageReplace"][1/0, Power -> MyFunction]
Out[1]=

Compare to the normal message:

In[2]:=
1/0
Out[2]=

Replace message tags:

In[3]:=
MyFunction::test1 = "First test message";
MyFunction::test2 = "Second test message";
In[4]:=
ResourceFunction["MessageReplace"][Message[MyFunction::test1], "test1" -> "test2"]

Replace using patterns:

In[5]:=
ResourceFunction["MessageReplace"][First[1]/0, HoldPattern[
   MessageName[sym_, tags__] /; Context@sym === "System`"] :> MessageName[MyFunction, tags]]
Out[5]=

Replace using a list of rules:

In[6]:=
ResourceFunction["MessageReplace"][
 StringLength[x, y, z], {StringLength -> MyFunction, _Integer -> Style["a whole bunch of", Bold]}]
Out[6]=

Scope (7) 

Specify a replacement function:

In[7]:=
ResourceFunction["MessageReplace"][First[x];, n_Integer /; n < 10 :> With[{m = n + 1}, m /; True], ReplaceAll]
In[8]:=
ResourceFunction["MessageReplace"][First[x];, n_Integer /; n < 10 :> With[{m = n + 1}, m /; True], ReplaceRepeated]

Named replacement functions (3) 

Replace only the message symbol:

In[9]:=
ResourceFunction["MessageReplace"][StringLength[x];, StringLength -> MyStringLength, "Symbol"]

Replace only the message tag:

In[10]:=
MyFunction::test1 = "First test message: `1`";
MyFunction::test2 = "Second test message: `1`";
In[11]:=
ResourceFunction["MessageReplace"][
 Message[MyFunction::test1, "test1"], "test1" -> "test2", "Tag"]

Replace only in message parameters:

In[12]:=
ResourceFunction["MessageReplace"][StringLength[x];, StringLength -> Style[StringLength, Bold], "Parameters"]

Automatic replacement function (4) 

When the replacement function is Automatic, the type of replacement differs depending on the rules given. Here are some test messages:

In[13]:=
MyFunction::test1 = "Test 1: the symbol is `1`, the tag is `2`.";
MyFunction::test2 = "Test 2: the symbol is `1`, the tag is `2`.";

Symbol replacements change the message symbol (first argument of MessageName):

In[14]:=
ResourceFunction["MessageReplace"][
 Message[MyFunction::test1, MyFunction, "test1"], MyFunction -> OtherFunction, Automatic]

String replacements change the message tag (second argument of MessageName):

In[15]:=
ResourceFunction["MessageReplace"][
 Message[MyFunction::test1, MyFunction, "test1"], "test1" -> "test2", Automatic]

Mixing rules results in replacement across the whole message (including parameters):

In[16]:=
ResourceFunction["MessageReplace"][
 Message[MyFunction::test1, MyFunction, "test1"], {MyFunction -> OtherFunction, "test1" -> "test2"}, Automatic]

Applications (1) 

Define a function that takes ownership of messages issued:

In[17]:=
MyPart[args___] := ResourceFunction["MessageReplace"][
   Check[Part[args], $Failed], _ -> MyPart, "Symbol"];
In[18]:=
MyPart[f[], 1]
Out[18]=

Properties and Relations (2) 

See the expression structure that's passed to the replacement function:

In[19]:=
ResourceFunction["MessageReplace"][1/0, Power -> MyFunction, EchoEvaluation[ReplaceAll[##]] &]
Out[19]=

If the target symbol and tag is not a defined message, it will be defined temporarily in order to print the message:

In[20]:=
ClearAll[MyFunction, OtherFunction];
MyFunction::test = "This is a test message.";
In[21]:=
ResourceFunction["MessageReplace"][Message[MyFunction::test], MyFunction -> OtherFunction]

The temporary message definition is cleared:

In[22]:=
Messages[OtherFunction]
Out[22]=

If the message is already defined for the target symbol and tag, it won't be changed:

In[23]:=
OtherFunction::test = "This is a different test message.";
In[24]:=
ResourceFunction["MessageReplace"][Message[MyFunction::test], MyFunction -> OtherFunction]
In[25]:=
Messages[OtherFunction]
Out[25]=

Possible Issues (2) 

Changing the target message template can result in additional errors if the number of template slots increases:

In[26]:=
MyFunction::param1 = "One parameter: `1`";
MyFunction::param2 = "Two parameters: `1` and `2`";
In[27]:=
ResourceFunction["MessageReplace"][Message[MyFunction::param1, f[x]], "param1" -> "param2"];

Compare to the original:

In[28]:=
Message[MyFunction::param1, f[x]];

If the number of template slots decreases, some parameters will be dropped:

In[29]:=
ResourceFunction["MessageReplace"][
  Message[MyFunction::param2, f[x], g[y]], "param2" -> "param1"];

Compare to the original:

In[30]:=
Message[MyFunction::param2, f[x], g[y]];

The original message is never issued, so inner code that checks for specific messages may give unexpected results:

In[31]:=
ResourceFunction["MessageReplace"][Check[1/0, fail, Power::infy], Power -> MyFunction]
Out[31]=

MessageReplace does not affect quieted messages, so the underlying code will work as expected:

In[32]:=
ResourceFunction["MessageReplace"][
 Quiet[Check[1/0, fail, Power::infy]], Power -> MyFunction]
Out[32]=

Neat Examples (2) 

Replace numbers in messages using IntegerName:

In[33]:=
ResourceFunction["MessageReplace"][
 StringCases["abc", "a", 1, 2, 3, 4];, n_Integer :> RuleCondition[IntegerName[n]]]

Use replacement rules to temporarily define alternate behavior for messages:

In[34]:=
ResourceFunction["MessageReplace"][First[1]/0, HoldPattern[Message[MessageName[symbol_, tag_], args___]] :> Print[Panel[
Grid[{{"Symbol:", 
RawBoxes[
ResourceFunction["StringTemplateInput"][
SymbolName[symbol]]]}, {"Tag:", 
Row[{tag, " ", 
If[
StringQ[
MessageName[symbol, tag]], 
Button["»", 
SystemOpen["paclet:ref/message/" <> ToString[symbol] <> "/" <> tag], Appearance -> None, BaseStyle -> "Hyperlink"], 
Button["»", 
SystemOpen["paclet:ref/message/General/" <> tag], Appearance -> None, BaseStyle -> "Hyperlink"]]}]}, {"Parameters:", 
Iconize[{args}]}}, Alignment -> Left]]]]
Out[34]=

Version History

  • 1.0.0 – 14 June 2021

Related Resources

License Information