From 3220b94d2053e8051023fc6f79c00651071b1440 Mon Sep 17 00:00:00 2001 From: w0rp Date: Mon, 8 Jul 2024 03:22:46 +0100 Subject: [PATCH] Fix #4714 - Handle ruff garbage When ruff outputs errors are invalid JSON text, handle that and stop ALE from throwing exceptions. --- ale_linters/python/ruff.vim | 28 +++++++++++------- test/handler/test_ruff_handler.vader | 43 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 test/handler/test_ruff_handler.vader diff --git a/ale_linters/python/ruff.vim b/ale_linters/python/ruff.vim index aa605ba5..f30d42c0 100644 --- a/ale_linters/python/ruff.vim +++ b/ale_linters/python/ruff.vim @@ -61,17 +61,25 @@ endfunction function! ale_linters#python#ruff#Handle(buffer, lines) abort let l:output = [] + " Read all lines of ruff output and parse use all the valid JSONL lines. for l:line in a:lines - let l:item = json_decode(l:line) - call add(l:output, { - \ 'lnum': l:item.location.row, - \ 'col': l:item.location.column, - \ 'end_lnum': l:item.end_location.row, - \ 'end_col': l:item.end_location.column - 1, - \ 'code': l:item.code, - \ 'text': l:item.message, - \ 'type': l:item.code =~? '\vE\d+' ? 'E' : 'W', - \}) + try + let l:item = json_decode(l:line) + catch + let l:item = v:null + endtry + + if !empty(l:item) + call add(l:output, { + \ 'lnum': l:item.location.row, + \ 'col': l:item.location.column, + \ 'end_lnum': l:item.end_location.row, + \ 'end_col': l:item.end_location.column - 1, + \ 'code': l:item.code, + \ 'text': l:item.message, + \ 'type': l:item.code =~? '\vE\d+' ? 'E' : 'W', + \}) + endif endfor return l:output diff --git a/test/handler/test_ruff_handler.vader b/test/handler/test_ruff_handler.vader new file mode 100644 index 00000000..82012706 --- /dev/null +++ b/test/handler/test_ruff_handler.vader @@ -0,0 +1,43 @@ +Before: + runtime ale_linters/python/ruff.vim + +After: + call ale#linter#Reset() + +Execute(We should handle basic output of ruff correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 2, + \ 'col': 1, + \ 'code': 'F821', + \ 'type': 'W', + \ 'end_col': 7, + \ 'end_lnum': 2, + \ 'text': 'Undefined name example', + \ }, + \ ], + \ ale_linters#python#ruff#Handle(bufnr(''), [ + \ '{"cell":null,"code":"F821","end_location":{"column":8,"row":2},"filename":"/home/eduardo/Code/Python/test.py","fix":null,"location":{"column":1,"row":2},"message":"Undefined name example","noqa_row":2,"url":"https://docs.astral.sh/ruff/rules/undefined-name"}', + \ ]) + +Execute(We should handle totally broken output from ruff): + AssertEqual [], ale_linters#python#ruff#Handle(bufnr(''), ['ERROR: oh noes!']) + +Execute(We should handle mixed error lines and JSON output from ruff): + AssertEqual + \ [ + \ { + \ 'lnum': 2, + \ 'col': 1, + \ 'code': 'F821', + \ 'type': 'W', + \ 'end_col': 7, + \ 'end_lnum': 2, + \ 'text': 'Undefined name example', + \ }, + \ ], + \ ale_linters#python#ruff#Handle(bufnr(''), [ + \ 'ERROR: oh noes!', + \ '{"cell":null,"code":"F821","end_location":{"column":8,"row":2},"filename":"/home/eduardo/Code/Python/test.py","fix":null,"location":{"column":1,"row":2},"message":"Undefined name example","noqa_row":2,"url":"https://docs.astral.sh/ruff/rules/undefined-name"}', + \ ])