MathGroup Archive 2002

[Date Index] [Thread Index] [Author Index]

Search the Archive

RE: Full text of the current warning message(s)

  • To: mathgroup at smc.vnet.net
  • Subject: [mg33405] RE: [mg33389] Full text of the current warning message(s)
  • From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>
  • Date: Wed, 20 Mar 2002 01:53:12 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

> -----Original Message-----
> From: Vladimir Bondarenko [mailto:vvb at mail.strace.net]
To: mathgroup at smc.vnet.net
> Sent: Tuesday, March 19, 2002 5:39 AM
> To: mathgroup at smc.vnet.net
> Subject: [mg33405] [mg33389] Full text of the current warning message(s)
> 
> 
> $MessageList is a global variable that gives a *list* of the 
> names of messages
> generated by Mathematica during the evaluation of the current 
> input line.
> 
> How can I get the WHOLE text of the warning message(s)? (not 
> only a template
> like "Expression `1` contains`2`" which are stored in Message.m) ?
> 
> For example,  NSum[1, {n, 1, foo}] generates the following 
> warning message
> 
>               NSum::"nslim": "Limit of summation foo is not a number."
> 
> 
> What is the simplest way to store this string into a variable?
> 
> 
> Vladimir Bondarenko
> 
> 
> 
Vladimir,

one idea would be to write the error messages to a file, and retrieve them
when needed:

 
In[1]:= Attributes[saveMessages] = {HoldAllComplete};
In[59]:=
saveMessages[expression_, append_:True] := 
  Block[{$Messages = If[append,
          OpenAppend["thoseMessages"],
          OpenWrite["thoseMessages"]], x},
    Write[$Messages, Line[$Line]]; (* current line no *)
    (* begin of your code *)
    x = expression; 
    (* end of your code *)
    Write[$Messages]; (* an empty line *)
    Close[$Messages]; x]

In[66]:=
recallMessages[] :=
  Block[{s = OpenRead["thoseMessages"]}, 
    Fold[If[#2 === "", Print[StringDrop[#1, -1]]; "", #1 <> #2 <> "\n"] &, 
         "",
         ReadList["thoseMessages", String]];
    Close[s];]



In[71]:= saveMessages[
     Exp[a, b, c];
     Log[-1/0, a], 
     False]
Out[71]= 0

In[72]:= saveMessages[
     Log[a, b, c];
     Exp[-1/0, a]
     ]
Out[72]= Exp[ComplexInfinity, a]

In[78]:= recallMessages[]
>From In[78]:= "Line[71]"
>From In[78]:=
"Exp::argx: Exp called with 3 arguments; 1 argument is expected."
>From In[78]:= 
"                                 1\n
 Power::infy: Infinite expression - encountered.\n
                                  0"
>From In[78]:= "Line[72]"
>From In[78]:= 
"Log::argt: Log called with 3 arguments; 1 or 2 arguments are expected."
>From In[78]:=
"                                 1\n
 Power::infy: Infinite expression - encountered.\n
                                  0"
>From In[78]:=
"Exp::argx: Exp called with 2 arguments; 1 argument is expected."

In[79]:= saveMessages[Sqrt[a, b, c], False]
Out[79]= Sqrt[a, b, c]

In[80]:= recallMessages[]
>From In[80]:= "Line[79]"
>From In[80]:=
"Sqrt::argx: Sqrt called with 3 arguments; 1 argument is expected."

(I edited the output a little bit, as to indicate the actual printed
representation.)
Of course you may recall the messages differently, but they are essentially
in a printed format as seen.



Here another, more complicated idea, yet, perhaps with a better result: the
messages are retrieved in there original form:


 
In[63]:= Attributes[storeMessages] = {HoldAllComplete, SequenceHold}
Out[63]= {HoldAllComplete, SequenceHold}

In[64]:= storeMessages[expression_] := 
  Block[{$MessagePrePrint = 
        Block[{m = Short[#]}, AppendTo[messageArgs, m]; m] &}, 
    messageArgs = {};
    $Post := (messagesSaved = $MessageList; $Post =.; #) &;
    expression]

$MessagePrePrint accumulates the expressions that were ##2 arguments to
Message.

$Post saves $MessageList and immediately resets itself, as not overwrite the
saved message list when evaluating the next expression. This was necessary
since just localizing $Post within Block is of no avail, because $Post is
only called at the top-level of the main evaluation loop, and such not
within Block.


In[65]:= storeMessages[Log[a, b, c]; Exp[-1/0, 10]]
>From In[65]:=
Log::"argt": "Log called with 3 arguments; 1 or 2 arguments are expected."
>From In[65]:=
Power::"infy": "Infinite expression 1/0 encountered."
>From In[65]:=
Exp::"argx": "Exp called with 2 arguments; 1 argument is expected."
Out[65]=
Exp[ComplexInfinity, 10]


In[66]:= messagesSaved
Out[66]= {Log::"argt", Power::"infy", Exp::"argx"}

In[67]:= messageArgs // InputForm
Out[67]//InputForm=
{Short[HoldForm[Log]], Short[HoldForm[3]], 
 Short[HoldForm[1]], Short[HoldForm[2]], 
 Short[HoldForm[0^(-1)]], Short[HoldForm[Exp]], 
 Short[HoldForm[2]]}

The messages and the arguments have been saved


In[68]:=
retrieveMessages[] := 
  Module[{rawmsg, rawpos, posns, partargs},
    Block[{$Messages = OpenWrite["tmp"]}, Message @@@ messagesSaved; 
      rawmsg = ReadList[OpenRead["tmp"], String]; Close /@ Streams["tmp"]]; 
    rawpos = Length /@ (StringPosition[#, "`"] &) /@ rawmsg;
    posns = 
      Rest[FoldList[{#1[[2]] + 1, #1[[2]] + #2} &, 
          {0, 0}, Last[Transpose[Partition[rawpos, 2]]]/2]];
    partargs = Take[messageArgs, #] & /@ posns;
    Message @@@ MapThread[Join, {messagesSaved, HoldForm @@@ partargs}];
    ]


In[69]:= retrieveMessages[]
>From In[69]:=
Log::"argt": "Log called with 3 arguments; 1 or 2 arguments are expected."
>From In[69]:=
Power::"infy": "Infinite expression 1/0 encountered."
>From In[69]:=
Exp::"argx": "Exp called with 2 arguments; 1 argument is expected."

The error messages have been retrieved in full blossom.

Do it again!

In[72]:= storeMessages[Sqrt[a, b, c]]
>From In[72]:=
Sqrt::"argx": "Sqrt called with 3 arguments; 1 argument is expected."
Out[72]= 
Sqrt[a, b, c]

In[73]:= retrieveMessages[]
>From In[73]:=
Sqrt::"argx": "Sqrt called with 3 arguments; 1 argument is expected."


Retrieve Messages is a little bit complicated though. This all was
neccessary since I found no way to splice in a delimiter between the
arguments of consecutive error messages. (Have you got an idea? tell!)

So I had to count the number of arguments needed. For that I looked at the
control string for the first StringForm parameter of Message. Normally it
would suffice to evaluate i.e. Power::"infy" by putting off the wrapper
HoldForm. This did not work for Log::"argt" and Exp::"argx", since evidently
those messages are not stored with MessageName[...]; obviously they are
treated in a special way within Message to extract "Log" and "Exp" as
paramaters for a message unknown to me (couldn't get at it). So I needed
Message again to extract that raw form. This is done with  Message @@@
messagesSaved . Again we intercepted the message stream. (It certainly is a
bit nasty to do that via a file "tmp"; I would have prefered something like
StringToStream to write to; found no way however.)

The next two lines are more easy: rawpos is (twice) the number of arguments
expected within every message. Also there is an empty line preceeding each
raw message; parargs then gives the ranges for the corresponding actual
parameters in messagesSaved.

As told, message has to be applied directly to its unevaluated (first)
argument. So I Joined those with the corresponding actual arguments. To
achieve that, they had to be wrapped with HoldForm (as the "message names"
were).

Perhaps this could be done more easily; I'd be eager to know.

--
Hartmut Wolf



  • Prev by Date: Re: Creating List of Sequence Iterates
  • Next by Date: Re: Mathlink for Excel
  • Previous by thread: Re:Full text of the current warning message(s)
  • Next by thread: Re: Re: Full text of the current warning message(s)