Here's how you can use the Vim and Neovim QuickFix feature to conveniently jump between pytest errors without leaving your editor.
Imagine you're running pytest in your Django project and are testing your project with pytest-django. You've recently changed how your view code works and use the django_assert_num_queries fixture.
Pytest output
Here's an abbreviated example of what pytest outputs when query counts are off:
= test session starts =
[…]
projectify/workspace/test/views/test_project.py FF
= FAILURES =
Here's the first test failing with 21 instead of 20 queries:
_ TestProjectDetailView.test_get_project_detail _
[…]
> with django_assert_num_queries(20):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
projectify/workspace/test/views/test_project.py:38:
[…]
> pytest.fail(msg)
E Failed: Expected to perform 20 queries but 21 were done […]
[…]
Here's the second test failing with 31 instead of 30 queries:
_ TestProjectDetailViewActions.test_mark_task_done _
[…]
> with django_assert_num_queries(30):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
projectify/workspace/test/views/test_project.py:126:
[…]
> pytest.fail(msg)
E Failed: Expected to perform 30 queries but 31 were done […]
[…]
Run pytest and pipe the above output into a file called pytest-errors:
pytest > pytest-errors
Understanding the error format
I'd like to show these errors inside Vim as a QuickFix list1. This is how the Vim help describes the QuickFix feature:
Vim has a special mode to speedup the edit-compile-edit cycle. This is inspired by the quickfix option of the Manx's Aztec C compiler on the Amiga. The idea is to save the error messages from the compiler in a file and use Vim to jump to the errors one by one.
To use the QuickFix feature, you need to give Vim, or Neovim, a file containing specially formatted error messages. You can adjust this format using the errorformat variable:4
'errorformat' 'efm' string (default is very long)
global or local to buffer |global-local|
Scanf-like description of the format for the lines in the error file (see |errorformat|).
Run :set errorformat in Vim to see the default contents of this errorformat variable. Here are the contents, formatted for clarity:
-
%*[^"]"%f"%*\D%l: %m, -
"%f"%*\D%l: %m, -
%-Gg%\?make[%*\d]: *** [%f:%l:%m, -
%-Gg%\?make: *** [%f:%l:%m, -
%-G%f:%l: (Each undeclared identifier is reported only once, -
%-G%f:%l: for each function it appears in.), -
%-GIn file included from %f:%l:%c:, -
%-GIn file included from %f:%l:%c\,, -
%-GIn file included from %f :%l:%c,%-GIn file included from %f:%l, -
%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:, -
%-G%*[ ]from %f:%l\,, -
%-G%*[ ]from %f:%l, -
%f:%l:%c:%m, -
%f(%l):%m,%f:%l:%m, -
"%f"\, line %l%*\D%c%*[^ ] %m, -
%D%*\a[%*\d]: Entering directory %*[`']%f', -
%X%*\a[%*\d]: Leaving directory %*[`']%f', -
%D%*\a: Entering directory %*[`']%f', -
%X%*\a: Leaving directory %*[`']%f', -
%DMaking %*\a in %f,%f|%l| %m
Most of these error formats are good for capturing GCC and GNU make output. We'll pick the simplest %f:%l:%c:%m, format. This means that each line should be of this form:
file_name.py:123:23:MESSAGE
^ ^
line column
number number
Rewrite your errors
Use sed to rewrite your pytest-errors file to an errors.err3 file that Vim's QuickFix can work with:
sed -n -E -e '
s/^.+Failed.+$/\0/p
s/^(projectify\/.*\.py):([0-9]+):.+$/\1:\2:0:/p
' pytest-errors > errors.err
Here's what errors.err contains after running the above sed command:
projectify/workspace/test/views/test_project.py:38:0:
E Failed: Expected to perform 20 queries but 21 were done […]
projectify/workspace/test/views/test_project.py:126:0:
E Failed: Expected to perform 30 queries but 31 were done […]
Load into Vim
Then, read this file witherrorformat compatible strings with the :cfile command or shorter :cf:5
:cf[ile][!] [errorfile]Read the error file and jump to the first error. This is done automatically when Vim is started with the -q option. You can use this command when you keep Vim running while compiling. If you give the name of the errorfile, the 'errorfile' option will be set to [errorfile]. See |:cc| for [!]. If the encoding of the error file differs from the 'encoding' option, you can use the 'makeencoding' option to specify the encoding.
Vim and Neovim assume that errors.err contains your errors by default so you don't have to type a file name after :cfile.
Navigate between errors with the following two shortcuts:
]q: jump to next error[q: jump to previous error
You can now comfortable jump between errors in Vim and Neovim.
-
Or shorter:
:set efm↩ -
"'errorfile' 'ef' 'errorfile' 'ef' string (default "errors.err")", see Neovim docs ↩
-
See
:h errorformat↩ -
See
:h cfile↩