3

I am writing python 3 code from within vim.

There is a function within my file like this:

def seconds_to_text(seconds):
    return str(datetime.timedelta(seconds=seconds))

Is there a way for me to see what it outputs for certain input values from within vim?

How can I see what seconds_to_text(30) would output without leaving vim?

3 Answers 3

5

Not really a "Vim answer", but writing a unit test and running the unit test(s) for the current file is probably the best way to do this.

Specifically for Python you can use doctests:

import datetime

def seconds_to_text(seconds):
    """Convert number of seconds to a textual representation.

    >>> seconds_to_text(42)
    '0:00:42'
    >>> str(datetime.timedelta(seconds=666))
    '0:11:06'
    """
    return str(datetime.timedelta(seconds=seconds))

if __name__ == '__main__':
    import doctest
    doctest.testmod()

And then just use :!python % to run this file.

Or if you don't want to modify the Python files, you can use:

:!python -m doctest %

Or as a more convenient mapping:

augroup python_test
    autocmd!
    autocmd Filetype python nnoremap <Leader>t :execute ':!python -m doctest %'<CR>
augroup end

If you only want to run the current function, you can use something like:

if __name__ == '__main__':
    import doctest, sys
    if len(sys.argv) < 2:
        doctest.testmod()
    else:
        for f in sys.argv[1:]:
            doctest.run_docstring_examples(globals()[f], globals())

And then use :!python % seconds_to_text; a useful mapping might be something like:

fun! TestFunction()
    " Find function under cursor
    let l:save = winsaveview()
    normal [[
    let l:fun = substitute(getline('.'), 'def \(\w*\)(.*', '\1', '')
    execute ':!python % ' . l:fun
    call winrestview(l:save)
endfun

augroup python_test
    autocmd!
    autocmd Filetype python nnoremap <Leader>t :call TestFunction()<CR>
augroup end

Which will run the tests for the current function. Typically you shouldn't really need this though, since typically unit tests are be fast enough to not notice any meaningful difference between running just one vs. running all tests for a single file.

0

I'm not sure if this is the intended solution, because you technically don't leave vim, ie you are still in the vim window, but you use a shell command to run the script.

Here is a sample python3 script I created

def b(a):
  return str(a)

print(b(123))

This creates a function that returns the string representation of the parameter.

Now I save the file using :w and then run the script by calling executing a terminal command :!python3 file_name.py and this outputs 123. So this is a way you can call a Python function. Sure, you can replace the b(a) function with your own function seconds_to_text(seconds) and do the same process.

2
  • Using a shell command is fine ;) However, I already know this isn't the best possible solution, because I don't have to save the file to be able to pass a section of it to python, I can select some lines and run: :'<,'>!python
    – user9024
    Commented Dec 25, 2016 at 11:36
  • 1
    @theonlygusti :w and then !python3 is shorter :)
    – user41805
    Commented Dec 25, 2016 at 11:47
0

Here is a command that should work (but it's not pretty):

command! -nargs=1 Pt echomsg system("python -c 'from " . expand("%:r") . " import *;print ". <f-args> . "'")

Decomposing:

command! -nargs=1 Pt            " Define a command named Pt that takes 1 argument.
echomsg system("                " The command echo the result of a system call.
python -c '                     " Execute a python string as the whole program.
from " . expand("%:r")          " Build a `from X import *` statement where X ..
. " import *;                   " .. is the current filename without extension
print ". <f-args>               " Print the command argument (see below)
. "'")                          " Close everything

You can use the command like so:

# test.py
def test(a):
   return a*2

And run:

:Pt test(21)
42

See:

  • :h command
  • :h nargs
  • :h echomsg
  • :h system
  • :h expand
  • :h f-args

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.