在MATLAB中将警告转换为错误

时间:2012-02-24 13:44:01

标签: matlab error-handling warnings

在我的一些功能中,我想将一些警告转换为错误。例如,如果我想在str2func产生MATLAB:str2func:invalidFunctionName警告时抛出错误,我会执行以下操作:

invalid_func_id = 'MATLAB:str2func:invalidFunctionName';
%hide warning of interest
warning('off', invalid_func_id);
%this might yield the warning of interest
predicate_func_try = str2func(predicate_func);
[~, warn_id] = lastwarn;
assert(~strcmp(warn_id, invalid_func_id)...
    , 'MyFunc:InvalidFunctionName'...
    , 'The predicate function %s does not have a valid name'...
    , predicate_func...
    );
warning on all

如果我知道特定的代码块可以提供一小组警告,那么这种方法很好。但是它很冗长,可能无法扩展到更大的代码块。有没有更好的方法呢?理想情况下,我想要一个可以将某些警告转换为整个块中的错误的函数。它允许我将我的例子修改为:

warnings2errors('MATLAB:str2func:invalidFunctionName');
predicate_func_try = str2func(predicate_func);
warnings2errors('off');

3 个答案:

答案 0 :(得分:5)

另一种方法是重载警告本身。请参阅下面的warning.m和warning2error.m的实现。我从中看到的最大的副作用是你会在堆栈上看到一个额外的“warning.m”,显示所有警告信息。不确定是否有办法解决这个问题。此外,您需要禁用MATLAB:dispatcher:nameConflict警告,因为我们正在重载内置函数。

编辑:刚刚在matlabcentral.com上发现了一个未记录的内置警告用法: http://www.mathworks.com/matlabcentral/newsreader/view_thread/158768 http://undocumentedmatlab.com/blog/trapping-warnings-efficiently/

>> warning('error','MATLAB:str2func:invalidFunctionName')

从命令行使用

  
    

warning2error( '添加', 'MATLAB:str2func:invalidFunctionName')

  

Warning.m:

% Overload of warning.m to enable conversion of certain warnings to errors
% via warning2error.m
%
% Will want to disable warning "MATLAB:dispatcher:nameConflict" via command
% warning('off','MATLAB:dispatcher:nameConflict');
%
% Jesse Hopkins
% Oct. 2 2012

function varargout = warning(varargin)
    %check for component:mnemonic syntax
    if nargin >= 2 && ischar(varargin{1}) && any(regexp(varargin{1},'^(\w+:\w+){1,}$','start','once'))
        %we've captured  <component>[:<component>]:<mnemonic>syntax

        %check if this is in the list
        if warning2error('query',varargin{1})
            %YES, convert to error
            ME = MException(varargin{1},varargin{2:end});
            ME = ME.addCause(MException('Warning2Error:ConvertedWarning','Converted warning "%s" to error becuase it was registered via warning2error.m.',varargin{1}));
            ME.throwAsCaller;
        end
    end

    %pass through to built-in warning
    varargout{1:nargout} = builtin('warning',varargin{:});
end

Warning2Error.m:

%warning2error.m
%USAGE:
%   Add warnings to convert to errors.
%  warning2error('add','<component>[:<component>]:<mnemonic>',...
%
%   Remove warnings to convert to errors
%   warning2error('remove','<component>[:<component>]:<mnemonic>',...
%
%   Query warnings to convert to errors 
%   tf = warning2error('query','<component>[:<component>]:<mnemonic>')
%
%   Get entire list of warnings converted to errors
%   list = warning2error('get')
%
% Jesse Hopkins
% Oct 2 2012

function varargout = warning2error(op,varargin)
    persistent list;
    if isempty(list)
        list = {};
    end
    varargout={};

    switch lower(op)
        case 'add'
            list = unique([list(:);varargin(:)]);
        case 'remove'
            for i = 1:length(varargin)
                [tf idx] = ismember(varargin{i},list);
                allidx = 1:length(list);
                newidx = setdiff(allidx,idx);
                list = list(newidx);
            end
        case 'clear'
            list = {};
        case 'get'
            varargout{1} = list;
        case 'query'
            out = false(1,length(varargin));
            for i = 1:length(varargin)
                out(i) = ismember(varargin{1},list);
            end
            varargout{1} = out;
    end
end

答案 1 :(得分:1)

我不知道一个干净的方法来完全按照自己的意愿行事。根据您希望将错误转换为警告的原因,您可以使用:

dbstop if warning

dbstop if warning MyFunc:InvalidFunctionName

您还可以查看warning on stacktrace,以便在出现警告时获得更多信息。

如果您需要实际的错误消息(而不仅仅是一种打入调试器的方法),那么我对您在问题中包含的方法印象非常深刻。

答案 2 :(得分:0)

我找到了一种方法来概括这一点。它的工作方式如下(类似于tictoc):

warn_ids = setwarnings2errors('MATLAB:str2func:invalidFunctionName');
predicate_func_try = str2func(predicate_func);
getwarnings2errors(warn_ids);

setwarnings2errorsgetwarnings2errors之间,如果它们是最后一次警告,则所有警告设置都将引发错误。因此,它不应该用于可能发生许多不同警告的大块。我通过以下方式实现了这些功能:

setwarnings2errors:

function warning_ids = setwarnings2errors(varargin)
warning_ids = cell(nargin, 1);
for x_ = 1:nargin
    local_arg = varargin{x_};
    assert(ischar(local_arg));
    evalin('caller', sprintf('warning off %s', local_arg));
    warning_ids{x_} = local_arg;
end
end

getwarnings2errors:

function getwarnings2errors(warning_ids)
[lastwarn_str, lastwarn_id] = evalin('caller', 'lastwarn');
num_warns = numel(warning_ids);
try
    for x_ = 1:num_warns
        local_warn = warning_ids{x_};
        assert(~strcmp(local_warn, lastwarn_id)...
            , lastwarn_id...
            , lastwarn_str...
            );
    end
catch m_e
    evalin('caller', 'warning on all');
    throwAsCaller(m_e);
end
evalin('caller', 'warning on all');
end