Try/Catch Evalc and display output if error

14 visualizzazioni (ultimi 30 giorni)
Hi everyone,
I have a tricky question :) I use evalc to call a function (which is not mine and which I don't to modify). But sometimes this function throws an error.
My problem is that the error message sent by this function is not explicit at all and all the details are in some text output before the error. And since I am in evalc I don't see these outputs. Is there a way of displaying that ?
small exemple :
  • the function that I can not to modify
function blackbox()
disp('explicit explanation');
error('see above');
end
  • my function
function my_code()
try
T = evalc('blackbox()');
catch
error(['oops: ' T]);
end
end
What I want is for my_code() to display 'explicit explanation'. But of course if I do what I wrote above, the T is undefined (because evalc/blackbox throwed an exception)
thanks for your help !
update: maybe it was not clear enough: but what I want is to get all the messages that were supposed to be displayed by the function that returned the error ... and I can't find that in the ME .... In the example above, I want to be able to display 'explicit explanation'
  1 Commento
Stephen23
Stephen23 il 3 Lug 2017
Modificato: Stephen23 il 3 Lug 2017
This is basically a search for hack to "fix" bad code design: using disp as the main way of communicating with the user. The best solution would be to rewrite that function:
  1. add a "verbose" control (instead of polluting the user's command window willy-nilly) and to return any status messages.
  2. create one error message with all relevant text in it (because this could be caught and handled trivially).
and then get rid of the inefficient evalc when it is called.
If the person writing that function had done these things then your task would be trivial to solve: to catch the error message is all that would be required. After all, that is exactly what error messages are intended for, and have supporting commands and methods for! Instead, because someone used the wrong tool for the job, you are suffering trying to solve an unsolvable problem.
Bad design can never be properly fixed using hacks, and ultimately just causes more problems and fragility than it is worth. I know that this is not the answer you are looking for, but the best answer is write that function properly to put all text into the error message.

Accedi per commentare.

Risposta accettata

Billy St. John
Billy St. John il 5 Mag 2020
Inefficencies and bad designs aside, for anyone who needs to solve the original problem, try the following:
% General Approach
exception = [];
output = evalc('try, someFunc(); catch E, exception = E; end');
% ... perform processing on 'output' and 'exception' (if not empty)
% Original Example Implementation
function blackbox()
disp('explicit explanation');
error('see above');
end
function my_code()
blackBoxException = [];
T = evalc('try, blackbox(); catch E, blackBoxException = E; end');
disp(T);
if ~isempty(blackBoxException)
disp(getReport(blackBoxException));
end
% Note: I'd recomend reformatting the getReport() output and either rethrowing it or displaying
% it as a warning. A few strsplit's and/or regexprep's can help with formatting.
The above would display the following:
>> my_code();
explicit explanation
Error using my_code>blackbox (line #)
see above
Error in my_code (line #)
T = evalc('try, blackbox(); catch E, blackBoxException = E; end');
>>
  1 Commento
Pierre Maurel
Pierre Maurel il 8 Mag 2020
Modificato: Pierre Maurel il 8 Mag 2020
3 years later, perfect reply :) thanks !
It was (almost) exactly what I wanted to do. I just had to move the "disp(T)" inside the if and perfect !
thanks a lot for this ingenious solution.

Accedi per commentare.

Più risposte (3)

Jan
Jan il 3 Lug 2017
Modificato: Jan il 3 Lug 2017
Why do you need evalc? If the output is written to the command window, you get the information directly without tricks.
try
T = blackbox();
catch ME
error('oops: %s', ME.message);
end
If you want to grab the output to the command line, you can do this with another tool also, e.g. FEX: CmdWinTool:
fprintf('### Start\n');
try
T = blackbox();
catch ME
error('oops: %s', ME.message);
end
Str = CmdWinTool('getText');
Msg = strsplit(Str, '\n');
Ini = find(strcmp(Msg, '### Start'), 1, 'last');
Msg = Msg(Ini + 1:length(Msg));
I use evalc for a code, which spends 25% of the runtime with output to the command window. The output to the screen is useful for a single run of the program, but if it is called with 1000 cases for a self-test, nobody could read this pile of text. Therefore suppressing the output let the code run much faster, but in case of errors, the specific call is restarted without evalc:
try
S = evalc('process(myData)');
catch ME
fprintf(2, '%s\n', ME.message);
fprintf(2, 'Run again with screen output:\n');
process(myData);
end
  2 Commenti
Pierre Maurel
Pierre Maurel il 3 Lug 2017
Modificato: Pierre Maurel il 3 Lug 2017
  • I am not sure to understand the first part of your answer: blackbox() is not returning anything so I can not write T = blackbox(). And the evalc is here to prevent blackbox to display anything: I do not want blackbox() to display something EXCEPT if it throws an error and in that case I would like to get back the text that was supposed to be displayed
  • I will take a look on the second part but I'd like to avoid using a third party if possible
Jan
Jan il 3 Lug 2017
@Pierre: If you cann write "T=blackbox()", use "blackbox()" without "T=". You have two conflicting needs: 1. the function should not output anything, 2. you want to catch the output in case of an error. One of them must be preferred to the other.
I would not consider these 7 lines for warpping the call and hiding the output in case of a successful run as "third party".

Accedi per commentare.


Fangjun Jiang
Fangjun Jiang il 30 Giu 2017
Try this:
function my_code()
try
T = evalc('blackbox()');
catch ME
display(ME.message);
end
end
  1 Commento
Pierre Maurel
Pierre Maurel il 3 Lug 2017
thanks for your answer, however it is not what I want to do: with your code, I will only display "see above" and not the "explicit explanation" in my example ...

Accedi per commentare.


Image Analyst
Image Analyst il 30 Giu 2017
If you use
try
catch ME
end
You can get a lot of information from ME.
Wrap the contents of all your functions in a try/catch block:
% Sample usage
try
% Some code that might throw an error......
catch ME
callStackString = GetCallStack(ME);
errorMessage = sprintf('Error in program %s.\nTraceback (most recent at top):\n%s\nError Message:\n%s', ...
mfilename, callStackString, ME.message);
WarnUser(errorMessage);
end
The function GetCallStack() is attached below.
  5 Commenti
Image Analyst
Image Analyst il 3 Lug 2017
Stephen, thanks for clarifying. After experimenting around it looks like if you use evalc(), it will step into the blackbox function but the disp() function does not print to the command window. I even changed it to fprintf and that didn't either. I didn't expect that. You'd think that since it executes disp, it would spew output to the command window.
Getting rid of evalc() makes it not even step into the blackbox function at all, which I didn't expect. It seems to recognize, before even executing blackbox, that there is an output being requested when none are capable of being returned and it throws the error in the main program before even going into blackbox and the disp function inside.
Indeed curious behavior but as Stephen said, better program design will cure all that.
Stephen23
Stephen23 il 3 Lug 2017
Modificato: Stephen23 il 3 Lug 2017
" You'd think that since it executes disp, it would spew output to the command window."
Surely the whole point of evalc is that it does NOT display anything in the command window? The evalc help states: "anything that would normally be written to the command window, except for error messages, is captured and returned in the character array T".

Accedi per commentare.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by