преобразование предупреждений в ошибки в MATLAB - PullRequest
8 голосов
/ 24 февраля 2012

В некоторых моих функциях я хочу преобразовать некоторые предупреждения в ошибки.Например, если я хочу выдать ошибку, когда 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 ]

5 голосов
/ 03 октября 2012

Другим методом будет перегрузка самого предупреждения.Смотрите реализацию 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 ('add', '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 голос
/ 24 февраля 2012

Я не знаю чистого способа сделать именно то, что вы хотите.В зависимости от причины, по которой вы хотите превратить ошибки в предупреждения, вы можете получить:

dbstop if warning

или

dbstop if warning MyFunc:InvalidFunctionName

Вы также можете посмотреть на warning on stacktrace, чтобыполучите больше информации о предупреждениях по мере их появления.

Если вам нужно реальное сообщение об ошибке (а не просто способ проникнуть в отладчик), то я на самом деле очень впечатлен методом, который вы включили в вопрос.

0 голосов
/ 25 февраля 2012

Я нашел способ несколько обобщить это.Он работает следующим образом (аналогично tic и toc):

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

Между setwarnings2errors и getwarnings2errors все установленные предупреждения будут выдавать ошибку, если они были выброшены последним.Поэтому его не следует использовать в больших блоках, где может появляться много разных предупреждений.Я реализовал функции следующим образом:

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
...