From a7fb465fd184c3f4b1445df0aa74594b06a58b40 Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Wed, 18 Oct 2017 14:51:11 +0200 Subject: [PATCH 001/206] (Update my name) --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index cc3de277..0a800ac5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,7 +42,7 @@ Contributors: * Paweł Korzeniewski (https://github.com/korzeniewskipl); * Pedro Algarvio (http://github.com/s0undt3ch); * Phillip Cloud (http://github.com/cpcloud); -* Piet Delport (http://github.com/pjdelport); +* Pi Delport (http://github.com/pjdelport); * Robert David Grant (http://github.com/bgrant); * Robin Schneider (https://github.com/ypid); * Ronald Andreu Kaiser (http://github.com/cathoderay);; From 70a39ab32ebf437cd62fe0999ca378a47ea2fbb6 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Tue, 7 Nov 2017 20:58:07 -0200 Subject: [PATCH 002/206] rearranged tests and added simple but meaningful bash script for testing --- t/test.py | 8 ---- {t => tests/old}/docs.vim | 0 {t => tests/old}/ftplugin.vim | 0 {t => tests/old}/indent.vim | 0 {t => tests/old}/lint.vim | 0 {t => tests/old}/plugin.vim | 0 {t => tests/old}/rope.vim | 0 {t => tests/old}/syntax.vim | 0 {t => tests/old}/trouble.vim | 0 {t => tests/old}/virtualenv.vim | 0 tests/test.sh | 76 +++++++++++++++++++++++++++++++++ 11 files changed, 76 insertions(+), 8 deletions(-) delete mode 100644 t/test.py rename {t => tests/old}/docs.vim (100%) rename {t => tests/old}/ftplugin.vim (100%) rename {t => tests/old}/indent.vim (100%) rename {t => tests/old}/lint.vim (100%) rename {t => tests/old}/plugin.vim (100%) rename {t => tests/old}/rope.vim (100%) rename {t => tests/old}/syntax.vim (100%) rename {t => tests/old}/trouble.vim (100%) rename {t => tests/old}/virtualenv.vim (100%) create mode 100644 tests/test.sh diff --git a/t/test.py b/t/test.py deleted file mode 100644 index ba7d5efb..00000000 --- a/t/test.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - - -def main(): - unused = 1 - -unknown() diff --git a/t/docs.vim b/tests/old/docs.vim similarity index 100% rename from t/docs.vim rename to tests/old/docs.vim diff --git a/t/ftplugin.vim b/tests/old/ftplugin.vim similarity index 100% rename from t/ftplugin.vim rename to tests/old/ftplugin.vim diff --git a/t/indent.vim b/tests/old/indent.vim similarity index 100% rename from t/indent.vim rename to tests/old/indent.vim diff --git a/t/lint.vim b/tests/old/lint.vim similarity index 100% rename from t/lint.vim rename to tests/old/lint.vim diff --git a/t/plugin.vim b/tests/old/plugin.vim similarity index 100% rename from t/plugin.vim rename to tests/old/plugin.vim diff --git a/t/rope.vim b/tests/old/rope.vim similarity index 100% rename from t/rope.vim rename to tests/old/rope.vim diff --git a/t/syntax.vim b/tests/old/syntax.vim similarity index 100% rename from t/syntax.vim rename to tests/old/syntax.vim diff --git a/t/trouble.vim b/tests/old/trouble.vim similarity index 100% rename from t/trouble.vim rename to tests/old/trouble.vim diff --git a/t/virtualenv.vim b/tests/old/virtualenv.vim similarity index 100% rename from t/virtualenv.vim rename to tests/old/virtualenv.vim diff --git a/tests/test.sh b/tests/test.sh new file mode 100644 index 00000000..cd9f4165 --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,76 @@ +#! /bin/bash + +# Check before starting. +set -e +which vim 1>/dev/null 2>/dev/null + +# Set variables. +export VIM_TEST_FILE=/tmp/pymode.out +export VIM_TEST_VIMRC=/tmp/pymode_vimrc +export VIM_TEST_PYFILE=/tmp/pyfile.py +export VIM_TEST_PYMODECOMMANDS=/tmp/pymode_commands.txt + +# Prepare tests. +set +e +rm $VIM_TEST_FILE $VIM_TEST_VIMRC $VIM_TEST_PYFILE $VIM_TEST_PYMODECOMMANDS 2&>/dev/null +set -e + +# Create minimal vimrc. +echo "call has('python3')" >> $VIM_TEST_VIMRC +echo "set noswapfile" >> $VIM_TEST_VIMRC +echo "set shell=bash" >> $VIM_TEST_VIMRC +echo "set ft=python" >> $VIM_TEST_VIMRC +echo -e "syntax on\nfiletype plugin indent on\nset nocompatible" >> $VIM_TEST_VIMRC +echo -e "set runtimepath+=$(dirname $PWD)\n\n" >> $VIM_TEST_VIMRC +# echo "set runtimepath+=~/.vim/packpathdir/code/start/python-mode" >> $VIM_TEST_VIMRC + +# Start tests. +echo "Starting vim tests." + +# Iterate over each Pymode command. +set +e +vim -u $VIM_TEST_VIMRC -c "redir >> $VIM_TEST_PYMODECOMMANDS" -c "silent! command" -c "xall" $VIM_TEST_PYFILE +touch $VIM_TEST_PYFILE +while IFS= read -r PYCMD +do + # Customize commands which require arguments. + if [ $PYCMD == 'PymodeDoc' ]; + then + export PYCMD="PymodeDoc unittest" + elif [ $PYCMD == 'PymodeVirtualenv' ]; + then + # export PYCMD="PymodeVirtualenv venv" + : + elif [ $PYCMD == 'PymodePython' ]; + then + export PYCMD="PymodePython print(1 + 1)" + fi + echo "--------------- Processing $PYCMD" >> $VIM_TEST_FILE + vim -n -E -u $VIM_TEST_VIMRC -c "redir >> $VIM_TEST_FILE" -c "$PYCMD" -c "xall" $VIM_TEST_PYFILE + echo "" >> $VIM_TEST_FILE + echo "---------------" >> $VIM_TEST_FILE + echo -e "\n" >> $VIM_TEST_FILE +done < <(grep -o -E "Pymode[a-zA-Z]+" $VIM_TEST_PYMODECOMMANDS) +set -e + +# echo "Test 1" >> $VIM_TEST_FILE +# vim -u $VIM_TEST_VIMRC -c "redir >> $VIM_TEST_FILE" -c "silent $PYCMD" -c "quitall" $VIM_TEST_PYFILE +# echo "" >> $VIM_TEST_FILE +# +# echo "Test 2" >> $VIM_TEST_FILE +# vim -u $VIM_TEST_VIMRC -c "redir >> $VIM_TEST_FILE" -c "scriptnames" -c "quit" +# echo "" >> $VIM_TEST_FILE + +# Print errors. +echo "Errors:" +grep -E "^E[0-9]+:" $VIM_TEST_FILE + +echo "Reched end of tests." + +# Cleanup tests. +set +e +# rm $VIM_TEST_VIMRC $VIM_TEST_PYFILE $VIM_TEST_PYMODECOMMANDS 2&>/dev/null +set -e +vim $VIM_TEST_FILE + +# vim: set fileformat=unix filetype=sh wrap tw=0: From 3e37c3c343d6302568aab8cfe27eef23df47f457 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Tue, 7 Nov 2017 23:00:30 -0200 Subject: [PATCH 003/206] updated vim files according to 2082d0b8fed7fff10b3f335cefc6a51dd25ee0b2 (various improvements) --- after/ftplugin/python.vim | 4 +- autoload/pymode.vim | 2 +- autoload/pymode/folding.vim | 140 ++++++++++++-------------- autoload/pymode/lint.vim | 4 +- autoload/pymode/motion.vim | 2 +- autoload/pymode/rope.vim | 16 +-- autoload/pymode/tools/loclist.vim | 2 +- autoload/pymode/troubleshooting.vim | 4 +- doc/pymode.txt | 16 +-- ftplugin/python/pymode.vim | 42 ++++---- plugin/pymode.vim | 146 +++++++++++++++------------- syntax/python.vim | 6 +- 12 files changed, 190 insertions(+), 194 deletions(-) diff --git a/after/ftplugin/python.vim b/after/ftplugin/python.vim index 0dec7542..4f29b753 100644 --- a/after/ftplugin/python.vim +++ b/after/ftplugin/python.vim @@ -53,6 +53,6 @@ if g:pymode_rope && g:pymode_rope_completion if tolower(g:pymode_rope_completion_bind) == '' exe "inoremap =pymode#rope#complete(0)" endif - end + endif -end +endif diff --git a/autoload/pymode.vim b/autoload/pymode.vim index 723af9b5..3127431d 100644 --- a/autoload/pymode.vim +++ b/autoload/pymode.vim @@ -71,7 +71,7 @@ endfunction "}}} fun! pymode#trim_whitespaces() "{{{ if g:pymode_trim_whitespaces let cursor_pos = getpos('.') - silent! %s/\s\+$// + silent! %s/\s\+$//e call setpos('.', cursor_pos) endif endfunction "}}} diff --git a/autoload/pymode/folding.vim b/autoload/pymode/folding.vim index 3b29aebb..24f6b530 100644 --- a/autoload/pymode/folding.vim +++ b/autoload/pymode/folding.vim @@ -1,5 +1,4 @@ " Python-mode folding functions - " Notice that folding is based on single line so complex regular expressions " that take previous line into consideration are not fit for the job. @@ -8,13 +7,13 @@ let s:def_regex = g:pymode_folding_regex let s:blank_regex = '^\s*$' " Spyder, a very popular IDE for python has a template which includes " '@author:' ; thus the regex below. -let s:decorator_regex = '^\s*@\(author:\)\@!' -let s:doc_begin_regex = '^\s*[uUrR]\=\%("""\|''''''\)' -let s:doc_end_regex = '\%("""\|''''''\)\s*$' +let s:decorator_regex = '^\s*@\(author:\)\@!' +let s:docstring_line_regex = '^\s*[uUrR]\=\("""\|''''''\).\+\1\s*$' +let s:docstring_begin_regex = '^\s*[uUrR]\=\%("""\|''''''\).*\S' +let s:docstring_end_regex = '\%("""\|''''''\)\s*$' " This one is needed for the while loop to count for opening and closing " docstrings. -let s:doc_general_regex = '\%("""\|''''''\)' -let s:doc_line_regex = '^\s*[uUrR]\=\("""\|''''''\).\+\1\s*$' +let s:docstring_general_regex = '\%("""\|''''''\)' let s:symbol = matchstr(&fillchars, 'fold:\zs.') " handles multibyte characters if s:symbol == '' let s:symbol = ' ' @@ -24,10 +23,10 @@ endif fun! pymode#folding#text() " {{{ let fs = v:foldstart - while getline(fs) !~ s:def_regex && getline(fs) !~ s:doc_begin_regex + while getline(fs) !~ s:def_regex && getline(fs) !~ s:docstring_begin_regex let fs = nextnonblank(fs + 1) endwhile - if getline(fs) =~ s:doc_end_regex && getline(fs) =~ s:doc_begin_regex + if getline(fs) =~ s:docstring_end_regex && getline(fs) =~ s:docstring_begin_regex let fs = nextnonblank(fs + 1) endif let line = getline(fs) @@ -83,7 +82,11 @@ fun! pymode#folding#expr(lnum) "{{{ if decorated return '=' else + " The line below may improve folding. return ">".(indent / &shiftwidth + 1) + " This was the previous rule. It grouped classes definitions + " together (undesired). + " return indent / &shiftwidth + 1 endif endif "}}} @@ -95,80 +98,43 @@ fun! pymode#folding#expr(lnum) "{{{ " Notice that an effect of this is that other docstring matches will not " be one liners. - if line =~ s:doc_line_regex + if line =~ s:docstring_line_regex return "=" endif - if line =~ s:doc_begin_regex - " echom 'just entering' + if line =~ s:docstring_begin_regex if s:Is_opening_folding(a:lnum) - " echom 'entering at line ' . a:lnum return ">".(indent / &shiftwidth + 1) endif endif - if line =~ s:doc_end_regex + if line =~ s:docstring_end_regex if !s:Is_opening_folding(a:lnum) - " echom 'leaving at line ' . a:lnum return "<".(indent / &shiftwidth + 1) endif endif "}}} - " Nested Definitions {{{ - " Handle nested defs but only for files shorter than - " g:pymode_folding_nest_limit lines due to performance concerns - if line('$') < g:pymode_folding_nest_limit && indent(prevnonblank(a:lnum)) - let curpos = getpos('.') - try - let last_block = s:BlockStart(a:lnum) - let last_block_indent = indent(last_block) - - " Check if last class/def is not indented and therefore can't be - " nested. - if last_block_indent - call cursor(a:lnum, 0) - let next_def = searchpos(s:def_regex, 'nW')[0] - let next_def_indent = next_def ? indent(next_def) : -1 - let last_block_end = s:BlockEnd(last_block) - - " If the next def has greater indent than the previous def, it - " is nested one level deeper and will have its own fold. If - " the class/def containing the current line is on the first - " line it can't be nested, and if this block ends on the last - " line, it contains no trailing code that should not be - " folded. Finally, if the next non-blank line after the end of - " the previous def is less indented than the previous def, it - " is not part of the same fold as that def. Otherwise, we know - " the current line is at the end of a nested def. - if next_def_indent <= last_block_indent && last_block > 1 && last_block_end < line('$') - \ && indent(nextnonblank(last_block_end)) >= last_block_indent - - " Include up to one blank line in the fold - if getline(last_block_end) =~ s:blank_regex - let fold_end = min([prevnonblank(last_block_end - 1), last_block_end]) + 1 - else - let fold_end = last_block_end - endif - if a:lnum == fold_end - return 's1' - else - return '=' - endif - endif - endif - finally - call setpos('.', curpos) - endtry - endif " }}} + " Blocks. {{{ + let save_cursor = getcurpos() + if line !~ s:blank_regex + let line_block_start = s:BlockStart(a:lnum) + let prev_line_block_start = s:BlockStart(a:lnum - 1) + call setpos('.', save_cursor) + if line_block_start == prev_line_block_start || a:lnum - line_block_start == 1 + return '=' + elseif indent < indent(prevnonblank(a:lnum - 1)) + return indent(line_block_start) / &shiftwidth + 1 + else + endif + endif + " endif " }}} " Blank Line {{{ if line =~ s:blank_regex if prev_line =~ s:blank_regex - if indent(a:lnum + 1) == 0 && next_line !~ s:blank_regex && next_line !~ s:doc_general_regex + if indent(a:lnum + 1) == 0 && next_line !~ s:blank_regex && next_line !~ s:docstring_general_regex if s:Is_opening_folding(a:lnum) - " echom a:lnum return "=" else - " echom "not " . a:lnum return 0 endif endif @@ -182,15 +148,25 @@ fun! pymode#folding#expr(lnum) "{{{ endfunction "}}} -fun! s:BlockStart(lnum) "{{{ +fun! s:BlockStart(line_number) "{{{ + " Returns the definition statement which encloses the current line. + " Note: Make sure to reset cursor position after using this function. - call cursor(a:lnum, 0) + call cursor(a:line_number, 0) " In case the end of the block is indented to a higher level than the def " statement plus one shiftwidth, we need to find the indent level at the " bottom of that if/for/try/while/etc. block. - let last_def = searchpos(s:def_regex, 'bcnW')[0] + let previous_definition = searchpos(s:def_regex, 'bcnW') + if previous_definition != [0, 0] + while previous_definition != [0, 0] && indent(previous_definition[0]) >= indent(a:line_number) + let previous_definition = searchpos(s:def_regex, 'bncW') + call cursor(previous_definition[0] - 1, 0) + endwhile + endif + let last_def = previous_definition[0] if last_def + call cursor(last_def, 0) let last_def_indent = indent(last_def) call cursor(last_def, 0) let next_stmt_at_def_indent = searchpos('\v^\s{'.last_def_indent.'}[^[:space:]#]', 'nW')[0] @@ -200,19 +176,33 @@ fun! s:BlockStart(lnum) "{{{ " Now find the class/def one shiftwidth lower than the start of the " aforementioned indent block. - if next_stmt_at_def_indent && next_stmt_at_def_indent < a:lnum + if next_stmt_at_def_indent && next_stmt_at_def_indent < a:line_number let max_indent = max([indent(next_stmt_at_def_indent) - &shiftwidth, 0]) else - let max_indent = max([indent(prevnonblank(a:lnum)) - &shiftwidth, 0]) + let max_indent = max([indent(prevnonblank(a:line_number)) - &shiftwidth, 0]) endif + + " " Debug: + return searchpos('\v^\s{,'.max_indent.'}(def |class )\w', 'bcnW')[0] + endfunction "}}} +function! Blockstart(x) + let save_cursor = getcurpos() + return s:BlockStart(a:x) + call setpos('.', save_cursor) +endfunction fun! s:BlockEnd(lnum) "{{{ " Note: Make sure to reset cursor position after using this function. call cursor(a:lnum, 0) return searchpos('\v^\s{,'.indent('.').'}\S', 'nW')[0] - 1 endfunction "}}} +function! Blockend(lnum) + let save_cursor = getcurpos() + return s:BlockEnd(a:lnum) + call setpos('.', save_cursor) +endfunction function! s:Is_opening_folding(lnum) "{{{ " Helper function to see if docstring is opening or closing @@ -238,13 +228,11 @@ function! s:Is_opening_folding(lnum) "{{{ let i_line = getline(i) - if i_line =~ s:doc_line_regex - " echom "case 00 on line " . i + if i_line =~ s:docstring_line_regex continue endif - if i_line =~ s:doc_begin_regex && ! has_open_docstring - " echom "case 01 on line " . i + if i_line =~ s:docstring_begin_regex && ! has_open_docstring " This causes the loop to continue if there is a triple quote which " is not a docstring. if extra_docstrings > 0 @@ -255,15 +243,13 @@ function! s:Is_opening_folding(lnum) "{{{ let number_of_folding = number_of_folding + 1 endif " If it is an end doc and has an open docstring. - elseif i_line =~ s:doc_end_regex && has_open_docstring - " echom "case 02 on line " . i + elseif i_line =~ s:docstring_end_regex && has_open_docstring let has_open_docstring = 0 let number_of_folding = number_of_folding + 1 - elseif i_line =~ s:doc_general_regex - " echom "extra docstrings on line " . i + elseif i_line =~ s:docstring_general_regex let extra_docstrings = extra_docstrings + 1 - endif + endif endfor call add(b:fold_cache, number_of_folding % 2) diff --git a/autoload/pymode/lint.vim b/autoload/pymode/lint.vim index e7dba8b5..f6d27bf7 100644 --- a/autoload/pymode/lint.vim +++ b/autoload/pymode/lint.vim @@ -5,7 +5,7 @@ call pymode#tools#loclist#init() fun! pymode#lint#auto() "{{{ - if !pymode#save() + if ! pymode#save() return 0 endif PymodePython from pymode import auto @@ -42,7 +42,7 @@ fun! pymode#lint#toggle() "{{{ call pymode#wide_message("Code checking is enabled.") else call pymode#wide_message("Code checking is disabled.") - end + endif endfunction "}}} diff --git a/autoload/pymode/motion.vim b/autoload/pymode/motion.vim index 67e99e6b..17377c96 100644 --- a/autoload/pymode/motion.vim +++ b/autoload/pymode/motion.vim @@ -21,7 +21,7 @@ fun! pymode#motion#vmove(pattern, flags) range "{{{ call cursor(a:firstline, 0) normal! v call cursor(end) -endfunction "}}} +endfunction "}}} fun! pymode#motion#pos_le(pos1, pos2) "{{{ diff --git a/autoload/pymode/rope.vim b/autoload/pymode/rope.vim index a82a46d9..ab330f0a 100644 --- a/autoload/pymode/rope.vim +++ b/autoload/pymode/rope.vim @@ -1,5 +1,9 @@ " Python-mode Rope support -" + +if ! g:pymode_rope + finish +endif + PymodePython from pymode import rope call pymode#tools#loclist#init() @@ -12,23 +16,23 @@ endfunction fun! pymode#rope#complete(dot) if pumvisible() return "\" - end + endif if a:dot PymodePython rope.complete(True) else PymodePython rope.complete() - end + endif return pumvisible() ? "\\" : "" endfunction fun! pymode#rope#complete_on_dot() "{{{ if !exists("*synstack") return "" - end + endif for group in map(synstack(line('.'), col('.') - 1), 'synIDattr(v:val, "name")') for name in ['pythonString', 'pythonComment', 'pythonNumber', 'pythonDocstring'] if group == name - return "" + return "" endif endfor endfor @@ -73,7 +77,7 @@ fun! pymode#rope#show_doc() setlocal nomodified setlocal filetype=rst wincmd p - end + endif endfunction diff --git a/autoload/pymode/tools/loclist.vim b/autoload/pymode/tools/loclist.vim index 18b6d294..0b883bbb 100644 --- a/autoload/pymode/tools/loclist.vim +++ b/autoload/pymode/tools/loclist.vim @@ -77,5 +77,5 @@ fun! g:PymodeLocList.show() "{{{ call setwinvar(winnr(), 'quickfix_title', self._title . ' <' . self._name . '>') exe num . "wincmd w" endif - end + endif endfunction "}}} diff --git a/autoload/pymode/troubleshooting.vim b/autoload/pymode/troubleshooting.vim index 915a5c5e..09955c92 100644 --- a/autoload/pymode/troubleshooting.vim +++ b/autoload/pymode/troubleshooting.vim @@ -18,7 +18,7 @@ fun! pymode#troubleshooting#test() "{{{ call append('0', ['Pymode diagnostic', \ '===================', - \ 'VIM:' . v:version . ', OS: ' . os .', multi_byte:' . has('multi_byte') . ', pymode: ' . g:pymode_version . ', pymode-python: ' . g:pymode_python, + \ 'VIM:' . v:version . ', OS: ' . os .', multi_byte:' . has('multi_byte') . ', pymode: ' . g:pymode_version . ', pymode-python: ' . g:pymode_python, \ '']) if !exists('#filetypeplugin') @@ -85,5 +85,5 @@ EOF call append('$', 'let pymode_virtualenv = ' . string(g:pymode_virtualenv)) call append('$', 'let pymode_virtualenv_enabled = ' . string(g:pymode_virtualenv_enabled)) call append('$', 'let pymode_virtualenv_path = ' . string(g:pymode_virtualenv_path)) - + endfunction "}}} diff --git a/doc/pymode.txt b/doc/pymode.txt index 1551f119..f466508b 100644 --- a/doc/pymode.txt +++ b/doc/pymode.txt @@ -6,7 +6,7 @@ (__) (__) (__) (_) (_)(_____)(_)\_) (_/\/\_)(_____)(____/(____) ~ - Version: 0.9.2 + Version: 0.9.4 ============================================================================== CONTENTS *pymode-contents* @@ -86,7 +86,7 @@ Turn off plugin's warnings *'g:pymode_warnings'* let g:pymode_warnings = 1 Add paths to `sys.path` *'g:pymode_paths'* -Value is list of path's strings. +Value is list of path's strings. > let g:pymode_paths = [] @@ -130,10 +130,10 @@ Setup pymode |quickfix| window 2.1. Python version ~ *pymode-python-version* -By default pymode looks for current python version supported in your Vim. +By default pymode looks for current python version supported in your Vim. You could choose prefer version, but value will be tested on loading. - *'g:pymode_python'* + *'g:pymode_python'* > let g:pymode_python = 'python' @@ -196,7 +196,7 @@ Enable pymode-motion *'g:pymode_motion'* Pymode could show documentation for current word by `pydoc`. Commands: -*:PymodeDoc* — show documentation +*:PymodeDoc* — show documentation Turns on the documentation script *'g:pymode_doc'* > @@ -498,7 +498,7 @@ Offer to unresolved import object after completion. *pymode-rope-findit* By default when you press *g* on any object in your code you will be moved -to definition. +to definition. Leave empty for disable key binding. *'g:pymode_rope_goto_definition_bind'* > let g:pymode_rope_goto_definition_bind = 'g' @@ -597,7 +597,7 @@ Change function signature ~ ------------------------------------------------------------------------------ 4.4 Undo/Redo changes ~ - *pymode-rope-undo* + *pymode-rope-undo* *pymode-rope-redo* Commands: @@ -670,7 +670,7 @@ Highlight builtin types (str, list, ...) *'g:pymode_syntax_builtin_types'* > let g:pymode_syntax_builtin_types = g:pymode_syntax_all -Highlight exceptions (TypeError, ValueError, ...) +Highlight exceptions (TypeError, ValueError, ...) *'g:pymode_syntax_highlight_exceptions'* > let g:pymode_syntax_highlight_exceptions = g:pymode_syntax_all diff --git a/ftplugin/python/pymode.vim b/ftplugin/python/pymode.vim index 97daecca..79842616 100644 --- a/ftplugin/python/pymode.vim +++ b/ftplugin/python/pymode.vim @@ -110,7 +110,7 @@ if g:pymode_lint " let &l:updatetime = g:pymode_lint_async_updatetime " au! BufEnter call pymode#lint#start() " au! BufLeave call pymode#lint#stop() - end + endif endif @@ -124,7 +124,7 @@ if g:pymode_doc exe "nnoremap " g:pymode_doc_bind ":call pymode#doc#find()" exe "vnoremap " g:pymode_doc_bind ":call pymode#doc#show(@*)" -end +endif " Rope support if g:pymode_rope @@ -134,69 +134,69 @@ if g:pymode_rope endif if g:pymode_rope_show_doc_bind != "" exe "noremap " . g:pymode_rope_show_doc_bind . " :call pymode#rope#show_doc()" - end + endif if g:pymode_rope_find_it_bind != "" exe "noremap " . g:pymode_rope_find_it_bind . " :call pymode#rope#find_it()" - end + endif if g:pymode_rope_organize_imports_bind != "" exe "noremap " . g:pymode_rope_organize_imports_bind . " :call pymode#rope#organize_imports()" - end + endif if g:pymode_rope_rename_bind != "" exe "noremap " . g:pymode_rope_rename_bind . " :call pymode#rope#rename()" - end + endif if g:pymode_rope_rename_module_bind != "" exe "noremap " . g:pymode_rope_rename_module_bind . " :call pymode#rope#rename_module()" - end + endif if g:pymode_rope_extract_method_bind != "" exe "vnoremap " . g:pymode_rope_extract_method_bind . " :call pymode#rope#extract_method()" - end + endif if g:pymode_rope_extract_variable_bind != "" exe "vnoremap " . g:pymode_rope_extract_variable_bind . " :call pymode#rope#extract_variable()" - end + endif if g:pymode_rope_inline_bind != "" exe "noremap " . g:pymode_rope_inline_bind . " :call pymode#rope#inline()" - end + endif if g:pymode_rope_move_bind != "" exe "noremap " . g:pymode_rope_move_bind . " :call pymode#rope#move()" - end + endif if g:pymode_rope_change_signature_bind != "" exe "noremap " . g:pymode_rope_change_signature_bind . " :call pymode#rope#signature()" - end + endif if g:pymode_rope_use_function_bind != "" exe "noremap " . g:pymode_rope_use_function_bind . " :call pymode#rope#use_function()" - end + endif if g:pymode_rope_generate_function_bind != "" exe "noremap " . g:pymode_rope_generate_function_bind . " :call pymode#rope#generate_function()" - end + endif if g:pymode_rope_generate_package_bind != "" exe "noremap " . g:pymode_rope_generate_package_bind . " :call pymode#rope#generate_package()" - end + endif if g:pymode_rope_generate_class_bind != "" exe "noremap " . g:pymode_rope_generate_class_bind . " :call pymode#rope#generate_class()" - end + endif if g:pymode_rope_module_to_package_bind != "" exe "noremap " . g:pymode_rope_module_to_package_bind . " :call pymode#rope#module_to_package()" - end + endif if g:pymode_rope_autoimport_bind != "" exe "noremap " . g:pymode_rope_autoimport_bind . " :PymodeRopeAutoImport" - end + endif if g:pymode_rope_completion && g:pymode_rope_complete_on_dot inoremap . .=pymode#rope#complete_on_dot() - end + endif command! -buffer -nargs=? PymodeRopeNewProject call pymode#rope#new() command! -buffer PymodeRopeUndo call pymode#rope#undo() @@ -207,6 +207,6 @@ if g:pymode_rope if g:pymode_rope_autoimport command! -buffer PymodeRopeAutoImport call pymode#rope#autoimport(expand('')) - end + endif -end +endif diff --git a/plugin/pymode.vim b/plugin/pymode.vim index 30078ce6..83127829 100644 --- a/plugin/pymode.vim +++ b/plugin/pymode.vim @@ -1,5 +1,5 @@ " vi: fdl=1 -let g:pymode_version = "0.9.2" +let g:pymode_version = "0.9.4" com! PymodeVersion echomsg "Current python-mode version: " . g:pymode_version com! PymodeTroubleshooting call pymode#troubleshooting#test() @@ -9,7 +9,10 @@ call pymode#default('g:pymode', 1) call pymode#default('g:pymode_debug', 0) " DESC: Disable script loading -if !g:pymode || &cp +if !g:pymode || &cp || &diff + " Update pymode status to prevent loading in other files and adding this + " condition to all of them. + let g:pymode = v:false finish endif @@ -49,7 +52,7 @@ call pymode#default("g:pymode_trim_whitespaces", 1) " Set recomended python options call pymode#default("g:pymode_options", 1) -call pymode#default("g:pymode_options_max_line_length", 80) +call pymode#default("g:pymode_options_max_line_length", 79) call pymode#default("g:pymode_options_colorcolumn", 1) " Enable/disable vertical display of python documentation @@ -135,7 +138,8 @@ call pymode#default("g:pymode_lint_info_symbol", "II") call pymode#default("g:pymode_lint_pyflakes_symbol", "FF") " Code checkers options -call pymode#default("g:pymode_lint_options_pycodestyle", +" TODO: check if most adequate name name is pep8 or pycodestyle. +call pymode#default("g:pymode_lint_options_pep8", \ {'max_line_length': g:pymode_options_max_line_length}) call pymode#default("g:pymode_lint_options_pylint", @@ -167,96 +171,98 @@ call pymode#default('g:pymode_breakpoint_cmd', '') " ROPE (refactoring, codeassist) {{{ " " Rope support -call pymode#default('g:pymode_rope', 1) +call pymode#default('g:pymode_rope', v:false) " System plugin variable -call pymode#default('g:pymode_rope_current', '') +if g:pymode_rope + call pymode#default('g:pymode_rope_current', '') -" Configurable rope project root -call pymode#default('g:pymode_rope_project_root', '') + " Configurable rope project root + call pymode#default('g:pymode_rope_project_root', '') -" Configurable rope project folder (always relative to project root) -call pymode#default('g:pymode_rope_ropefolder', '.ropeproject') + " Configurable rope project folder (always relative to project root) + call pymode#default('g:pymode_rope_ropefolder', '.ropeproject') -" If project hasnt been finded in current working directory, look at parents directory -call pymode#default('g:pymode_rope_lookup_project', 0) + " If project hasnt been finded in current working directory, look at parents directory + call pymode#default('g:pymode_rope_lookup_project', 0) -" Enable Rope completion -call pymode#default('g:pymode_rope_completion', 1) + " Enable Rope completion + call pymode#default('g:pymode_rope_completion', 1) -" Complete keywords from not imported modules (could make completion slower) -" Enable autoimport used modules -call pymode#default('g:pymode_rope_autoimport', 0) + " Complete keywords from not imported modules (could make completion slower) + " Enable autoimport used modules + call pymode#default('g:pymode_rope_autoimport', 0) -" Offer to import object after complete (if that not be imported before) -call pymode#default('g:pymode_rope_autoimport_import_after_complete', 0) + " Offer to import object after complete (if that not be imported before) + call pymode#default('g:pymode_rope_autoimport_import_after_complete', 0) -" Autoimported modules -call pymode#default('g:pymode_rope_autoimport_modules', ['os', 'shutil', 'datetime']) + " Autoimported modules + call pymode#default('g:pymode_rope_autoimport_modules', ['os', 'shutil', 'datetime']) -" Bind keys to autoimport module for object under cursor -call pymode#default('g:pymode_rope_autoimport_bind', 'ra') + " Bind keys to autoimport module for object under cursor + call pymode#default('g:pymode_rope_autoimport_bind', 'ra') -" Automatic completion on dot -call pymode#default('g:pymode_rope_complete_on_dot', 1) + " Automatic completion on dot + call pymode#default('g:pymode_rope_complete_on_dot', 1) -" Bind keys for autocomplete (leave empty for disable) -call pymode#default('g:pymode_rope_completion_bind', '') + " Bind keys for autocomplete (leave empty for disable) + call pymode#default('g:pymode_rope_completion_bind', '') -" Bind keys for goto definition (leave empty for disable) -call pymode#default('g:pymode_rope_goto_definition_bind', 'g') + " Bind keys for goto definition (leave empty for disable) + call pymode#default('g:pymode_rope_goto_definition_bind', 'g') -" set command for open definition (e, new, vnew) -call pymode#default('g:pymode_rope_goto_definition_cmd', 'new') + " set command for open definition (e, new, vnew) + call pymode#default('g:pymode_rope_goto_definition_cmd', 'new') -" Bind keys for show documentation (leave empty for disable) -call pymode#default('g:pymode_rope_show_doc_bind', 'd') + " Bind keys for show documentation (leave empty for disable) + call pymode#default('g:pymode_rope_show_doc_bind', 'd') -" Bind keys for find occurencies (leave empty for disable) -call pymode#default('g:pymode_rope_find_it_bind', 'f') + " Bind keys for find occurencies (leave empty for disable) + call pymode#default('g:pymode_rope_find_it_bind', 'f') -" Bind keys for organize imports (leave empty for disable) -call pymode#default('g:pymode_rope_organize_imports_bind', 'ro') + " Bind keys for organize imports (leave empty for disable) + call pymode#default('g:pymode_rope_organize_imports_bind', 'ro') -" Bind keys for rename variable/method/class in the project (leave empty for disable) -call pymode#default('g:pymode_rope_rename_bind', 'rr') + " Bind keys for rename variable/method/class in the project (leave empty for disable) + call pymode#default('g:pymode_rope_rename_bind', 'rr') -" Bind keys for rename module -call pymode#default('g:pymode_rope_rename_module_bind', 'r1r') + " Bind keys for rename module + call pymode#default('g:pymode_rope_rename_module_bind', 'r1r') -" Bind keys for convert module to package -call pymode#default('g:pymode_rope_module_to_package_bind', 'r1p') + " Bind keys for convert module to package + call pymode#default('g:pymode_rope_module_to_package_bind', 'r1p') -" Creates a new function or method (depending on the context) from the selected lines -call pymode#default('g:pymode_rope_extract_method_bind', 'rm') + " Creates a new function or method (depending on the context) from the selected lines + call pymode#default('g:pymode_rope_extract_method_bind', 'rm') -" Creates a variable from the selected lines -call pymode#default('g:pymode_rope_extract_variable_bind', 'rl') + " Creates a variable from the selected lines + call pymode#default('g:pymode_rope_extract_variable_bind', 'rl') -" Inline refactoring -call pymode#default('g:pymode_rope_inline_bind', 'ri') + " Inline refactoring + call pymode#default('g:pymode_rope_inline_bind', 'ri') -" Move refactoring -call pymode#default('g:pymode_rope_move_bind', 'rv') + " Move refactoring + call pymode#default('g:pymode_rope_move_bind', 'rv') -" Generate function -call pymode#default('g:pymode_rope_generate_function_bind', 'rnf') + " Generate function + call pymode#default('g:pymode_rope_generate_function_bind', 'rnf') -" Generate class -call pymode#default('g:pymode_rope_generate_class_bind', 'rnc') + " Generate class + call pymode#default('g:pymode_rope_generate_class_bind', 'rnc') -" Generate package -call pymode#default('g:pymode_rope_generate_package_bind', 'rnp') + " Generate package + call pymode#default('g:pymode_rope_generate_package_bind', 'rnp') -" Change signature -call pymode#default('g:pymode_rope_change_signature_bind', 'rs') + " Change signature + call pymode#default('g:pymode_rope_change_signature_bind', 'rs') -" Tries to find the places in which a function can be used and changes the -" code to call it instead -call pymode#default('g:pymode_rope_use_function_bind', 'ru') + " Tries to find the places in which a function can be used and changes the + " code to call it instead + call pymode#default('g:pymode_rope_use_function_bind', 'ru') -" Regenerate project cache on every save -call pymode#default('g:pymode_rope_regenerate_on_write', 1) + " Regenerate project cache on every save + call pymode#default('g:pymode_rope_regenerate_on_write', 1) +endif " }}} @@ -299,12 +305,12 @@ elseif g:pymode_python == 'python3' else - let g:pymode_doc = 0 - let g:pymode_lint = 0 - let g:pymode_path = 0 - let g:pymode_rope = 0 - let g:pymode_run = 0 - let g:pymode_virtualenv = 0 + let g:pymode_doc = v:false + let g:pymode_lint = v:false + let g:pymode_path = v:false + let g:pymode_rope = v:false + let g:pymode_run = v:false + let g:pymode_virtualenv = v:false command! -nargs=1 PymodePython echo diff --git a/syntax/python.vim b/syntax/python.vim index 090e9be1..e94877ee 100644 --- a/syntax/python.vim +++ b/syntax/python.vim @@ -118,7 +118,7 @@ endif if g:pymode_syntax_highlight_stars_operator syn match pythonExtraOperator "\%(\*\|\*\*\)" endif - + if g:pymode_syntax_highlight_self syn keyword pythonSelf self cls endif @@ -271,8 +271,8 @@ endif syn keyword pythonBuiltinObj True False Ellipsis None NotImplemented syn keyword pythonBuiltinObj __debug__ __doc__ __file__ __name__ __package__ endif - - if g:pymode_syntax_builtin_types + + if g:pymode_syntax_builtin_types syn keyword pythonBuiltinType type object syn keyword pythonBuiltinType str basestring unicode buffer bytearray bytes chr unichr syn keyword pythonBuiltinType dict int long bool float complex set frozenset list tuple From c9f1c3e6e58fcded7660526ced72f340087e1f85 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Tue, 7 Nov 2017 23:04:49 -0200 Subject: [PATCH 004/206] updated files in root folder according to 2082d0b8fed7fff10b3f335cefc6a51dd25ee0b2 (various improvements) --- .bumpversion.cfg | 2 +- .gitignore | 2 ++ Changelog.rst | 57 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 3b087e6f..e29f1ee9 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,6 +1,6 @@ [bumpversion] commit = True -current_version = 0.9.2 +current_version = 0.9.5 files = plugin/pymode.vim tag = True tag_name = {new_version} diff --git a/.gitignore b/.gitignore index f5674a78..40ca63ba 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ test.py todo.txt vendor vim.py +vim_session_*.vim +__*/ diff --git a/Changelog.rst b/Changelog.rst index e396eb69..af249a25 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -1,6 +1,48 @@ Changelog ========= + +## TODO +------- +* Move changelog rst syntax to markdown +* pymode_rope: check disables +* When loading a file without a history, substituting a word (eg 'cw') moves + the cursor to position 0 (equivalent to 'cw' then '0l') + * Fixed on `917e484` +* Inspect why files starting with: +~~~~~~ +def main(): + pass + + +if __name__ == '__main__': + main() +~~~~~~ +do not get loaded. + + +## 2017-07-xxx 0.9.5 +-------------------- +* pylama: migrated to submodule + + +## 2017-07-11 0.9.4 +-------------------- +* pylama: fixed erratic behavior of `skip` option causing unintended skipping + of lint checkers +* PEP257 requires `snowbalstemmer`: added as submodule +* Fixed handling of `g:pymode_lint_ignore` and `g:pymode_lint_select`: from + strings to list +* Migrated modules from `pymode/libs` to `submodules/ `__ + * Rationale: no need to single handedly update each module; removes burden + from developers +* Improved folding accuracy + * Improved nested definitions folding + * Improved block delimiting + + +## (changelog poorly maintained) 0.8.2 +-------------------------------------- * Pylama updated to version 5.0.5 * Rope libs updated * Add wdb to debugger list in breakpoint cmd @@ -140,7 +182,7 @@ Changelog -------------------- * Dont raise an exception when Logger has no message handler (c) nixon * Improve performance of white space removal (c) Dave Smith -* Improve ropemode support (c) s0undt3ch +* Improve ropemode support (c) s0undt3ch * Add `g:pymode_updatetime` option * Update autopep8 to version 0.8.1 @@ -151,7 +193,7 @@ Changelog ## 2012-09-06 0.6.8 ------------------- -* Add PEP8 indentation ":help 'pymode_indent'" +* Add PEP8 indentation ":help 'pymode_indent'" ## 2012-08-15 0.6.7 ------------------- @@ -165,7 +207,7 @@ Changelog * Fixed virtualenv support for windows users * Added pymode modeline ':help PythonModeModeline' * Added diagnostic tool ':call pymode#troubleshooting#Test()' -* Added `PyLintAuto` command ':help PyLintAuto' +* Added `PyLintAuto` command ':help PyLintAuto' * Code checking is async operation now * More, more fast the pymode folding * Repaired execution of python code @@ -191,12 +233,12 @@ Changelog ## 2012-03-13 0.6.0 ------------------- -* Add 'pymode_lint_hold' option +* Add 'pymode_lint_hold' option * Improve pymode loading speed * Add pep8, mccabe lint checkers * Now g:pymode_lint_checker can have many values Ex. "pep8,pyflakes,mccabe" -* Add 'pymode_lint_ignore' and 'pymode_lint_select' options +* Add 'pymode_lint_ignore' and 'pymode_lint_select' options * Fix rope keys * Fix python motion in visual mode * Add folding 'pymode_folding' @@ -258,7 +300,10 @@ Changelog ------------------- * Enable all syntax highlighting For old settings set in your vimrc: - let g:pymode_syntax_builtin_objs = 0 + + :: + +2082d0b8fed7fff10b3f335cefc6a51dd25ee0b2 let g:pymode_syntax_builtin_objs = 2 let g:pymode_syntax_builtin_funcs = 0 * Change namespace of syntax variables From b848f6294ca5858fd17eaf14783fa2042e8142b7 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Tue, 7 Nov 2017 23:12:02 -0200 Subject: [PATCH 005/206] updated pymode/pyfiles files according to 2082d0b8fed7fff10b3f335cefc6a51dd25ee0b2 (various improvements) --- pymode/__init__.py | 14 +++++++++----- pymode/lint.py | 44 +++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/pymode/__init__.py b/pymode/__init__.py index d5e63ba3..6fbdd9e0 100644 --- a/pymode/__init__.py +++ b/pymode/__init__.py @@ -1,4 +1,4 @@ -""" Pymode support functions. """ +"""Pymode support functions.""" from __future__ import absolute_import @@ -7,14 +7,18 @@ def auto(): - """ Fix PEP8 erorrs in current buffer. """ + """Fix PEP8 erorrs in current buffer. + + pymode: uses it in command PymodeLintAuto with pymode#lint#auto() + + """ from .autopep8 import fix_file class Options(object): - aggressive = 2 + aggressive = 1 diff = False experimental = True - ignore = vim.eval('g:pymode_lint_ignore') + ignore = vim.eval('g:pymode_lint_ignore').split(',') in_place = True indent_size = int(vim.eval('&tabstop')) line_range = None @@ -28,7 +32,7 @@ class Options(object): def get_documentation(): - """ Search documentation and append to current buffer. """ + """Search documentation and append to current buffer.""" from ._compat import StringIO sys.stdout, _ = StringIO(), sys.stdout diff --git a/pymode/lint.py b/pymode/lint.py index b0f85655..25f2414c 100644 --- a/pymode/lint.py +++ b/pymode/lint.py @@ -15,7 +15,7 @@ pass -def code_check(): # noqa +def code_check(): """Run pylama and check current file. :return bool: @@ -24,32 +24,38 @@ def code_check(): # noqa with silence_stderr(): from pylama.core import run - from pylama.main import parse_options - from pylama.config import _override_options + from pylama.config import parse_options if not env.curbuf.name: return env.stop() + linters = env.var('g:pymode_lint_checkers') + env.debug(linters) + + # Fixed in v0.9.3: these two parameters may be passed as strings. + # DEPRECATE: v:0.10.0: need to be set as lists. + if isinstance(env.var('g:pymode_lint_ignore'), str): + ignore = env.var('g:pymode_lint_ignore').split(',') + else: + ignore = env.var('g:pymode_lint_ignore') + if isinstance(env.var('g:pymode_lint_select'), str): + select = env.var('g:pymode_lint_select').split(',') + else: + select = env.var('g:pymode_lint_select') options = parse_options( - force=1, - ignore=env.var('g:pymode_lint_ignore'), - select=env.var('g:pymode_lint_select'), + linters=linters, force=1, + ignore=ignore, + select=select, ) - - linters = env.var('g:pymode_lint_checkers', default=[]) - if linters: - _override_options(options, linters=",".join(linters)) - - for linter in dict(options.linters): - opts = env.var('g:pymode_lint_options_%s' % linter, silence=True) - if opts: - options.linters_params[linter] = options.linters_params.get(linter, {}) - options.linters_params[linter].update(opts) - - if 'pylint' in options.linters_params: - options.linters_params['pylint']['clear_cache'] = True env.debug(options) + for linter in linters: + opts = env.var('g:pymode_lint_options_%s' % linter, silence=True) + if opts: + options.linters_params[linter] = options.linters_params.get( + linter, {}) + options.linters_params[linter].update(opts) + path = os.path.relpath(env.curbuf.name, env.curdir) env.debug("Start code check: ", path) From 43c052e88f901acabd658d37aa6322e22e1c762a Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Mon, 13 Nov 2017 23:11:03 -0200 Subject: [PATCH 006/206] reverted v:false to 0 due to vim7 incompatibility --- plugin/pymode.vim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugin/pymode.vim b/plugin/pymode.vim index 83127829..a9b195fc 100644 --- a/plugin/pymode.vim +++ b/plugin/pymode.vim @@ -12,7 +12,7 @@ call pymode#default('g:pymode_debug', 0) if !g:pymode || &cp || &diff " Update pymode status to prevent loading in other files and adding this " condition to all of them. - let g:pymode = v:false + let g:pymode = 0 finish endif @@ -171,7 +171,7 @@ call pymode#default('g:pymode_breakpoint_cmd', '') " ROPE (refactoring, codeassist) {{{ " " Rope support -call pymode#default('g:pymode_rope', v:false) +call pymode#default('g:pymode_rope', 0) " System plugin variable if g:pymode_rope @@ -305,12 +305,12 @@ elseif g:pymode_python == 'python3' else - let g:pymode_doc = v:false - let g:pymode_lint = v:false - let g:pymode_path = v:false - let g:pymode_rope = v:false - let g:pymode_run = v:false - let g:pymode_virtualenv = v:false + let g:pymode_doc = 0 + let g:pymode_lint = 0 + let g:pymode_path = 0 + let g:pymode_rope = 0 + let g:pymode_run = 0 + let g:pymode_virtualenv = 0 command! -nargs=1 PymodePython echo From cc11bc3073a0ad3b37f36c90caf3ac47397550d6 Mon Sep 17 00:00:00 2001 From: alphaCTzo7G Date: Mon, 13 Nov 2017 17:28:51 -0800 Subject: [PATCH 007/206] Slack now has tonnes of unanswered question Better to redirect to Stackoverflow as very few people log into the slack channel to reply. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0706f0c6..3596967d 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,7 @@ *The project needs contributors* -** Python-mode Slack Channel is here: https://python-mode.herokuapp.com/ ** +** Please use Python-mode tag on Stackoverflow to ask questions: https://stackoverflow.com/questions/tagged/python-mode ** ----- From a2ecfc33c0de075fcde1fd5c778a1be4f85f16e0 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Wed, 15 Nov 2017 20:31:39 -0200 Subject: [PATCH 008/206] changed readme.rst to readme.md according to issues #805 and #813 --- README.rst | 367 ----------------------------------------------------- readme.md | 172 +++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 367 deletions(-) delete mode 100644 README.rst create mode 100644 readme.md diff --git a/README.rst b/README.rst deleted file mode 100644 index 3596967d..00000000 --- a/README.rst +++ /dev/null @@ -1,367 +0,0 @@ -|logo| Python-mode, Python in VIM -################################# - -.. image:: https://travis-ci.org/python-mode/python-mode.png?branch=develop - :target: https://travis-ci.org/python-mode/python-mode - ------ - -*The project needs contributors* - -** Please use Python-mode tag on Stackoverflow to ask questions: https://stackoverflow.com/questions/tagged/python-mode ** - ------ - -| -| Src: https://github.com/python-mode/python-mode -| Homepage: https://klen.github.io/python-mode/ -| Docs: https://github.com/python-mode/python-mode/blob/develop/doc/pymode.txt -| - -Python-mode is a vim plugin that helps you to create python code very quickly -by utilizing libraries including -`pylint`_, `rope`_, pydoc_, `pyflakes`_, `pep8`_, `autopep8`_, -`pep257`_ and `mccabe`_ -for features like static analysis, refactoring, folding, completion, -documentation, and more. - -The plugin contains all you need to develop python applications in Vim. - -There is no need to install `pylint`_, `rope`_ -or any other `Python Libraries`_ on your system. - -- Support Python version 2.6+ and 3.2+ -- Syntax highlighting -- Virtualenv support -- Run python code (``r``) -- Add/remove breakpoints (``b``) -- Improved Python indentation -- Python folding -- Python motions and operators (``]]``, ``3[[``, ``]]M``, ``vaC``, ``viM``, - ``daC``, ``ciM``, ...) -- Code checking (pylint_, pyflakes_, pylama_, ...) that can be run - simultaneously (``:PymodeLint``) -- Autofix PEP8 errors (``:PymodeLintAuto``) -- Search in python documentation (``K``) -- Code refactoring (rope_) -- Strong code completion (rope_) -- Go to definition (``g`` for `:RopeGotoDefinition`) -- And more, more ... - -See (very old) screencast here: http://www.youtube.com/watch?v=67OZNp9Z0CQ -(sorry for quality, this is my first screencast) Another old presentation here: -http://www.youtube.com/watch?v=YhqsjUUHj6g - -**To read python-mode documentation in Vim, see** ``:help pymode`` - - -.. contents:: - - -Requirements -============ - -- VIM >= 7.3 (mostly features needed `+python` or `+python3` support) - (also ``--with-features=big`` if you want ``g:pymode_lint_signs``) - - -How to install -============== - -Using pathogen (recommended) ----------------------------- -:: - - % cd ~/.vim - % mkdir -p bundle && cd bundle - % git clone https://github.com/python-mode/python-mode.git - -- Enable `pathogen `_ - in your ``~/.vimrc``: :: - - " Pathogen load - filetype off - - call pathogen#infect() - call pathogen#helptags() - - filetype plugin indent on - syntax on - - -Manually --------- -:: - - % git clone https://github.com/python-mode/python-mode.git - % cd python-mode - % cp -R * ~/.vim - -Then rebuild **helptags** in vim:: - - :helptags ~/.vim/doc/ - - -.. note:: **filetype-plugin** (``:help filetype-plugin-on``) and - **filetype-indent** (``:help filetype-indent-on``) - must be enabled to use python-mode. - - -Debian packages ---------------- -|Repository URL: https://klen.github.io/python-mode/deb/ - -Install with commands: - -:: - - add-apt-repository https://klen.github.io/python-mode/deb main - apt-get update - apt-get install vim-python-mode - -If you are getting the message: "The following signatures couldn't be verified because the public key is not available": :: - - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys B5DF65307000E266 - -`vim-python-mode` using `vim-addons`, so after installation just enable -`python-mode` with command: :: - - vim-addons install python-mode - - -Troubleshooting -=============== - -If your python-mode doesn't work: - -1. Load Vim with only python-mode enabled (use `debug.vim` from pymode): :: - - vim -u /debug.vim - -And try to repeat your case. If no error occurs, seems like problem isn't in the -plugin. - -2. Type `:PymodeTroubleshooting` - -And fix any warnings or copy the output and send it to me. (For example, by -creating a `new github issue `_ -if one does not already exist for the problem). - - -Customization -============= - -You can override the default key bindings by redefining them in your `.vimrc`, for example: :: - - " Override go-to.definition key shortcut to Ctrl-] - let g:pymode_rope_goto_definition_bind = "" - - " Override run current python file key shortcut to Ctrl-Shift-e - let g:pymode_run_bind = "" - - " Override view python doc key shortcut to Ctrl-Shift-d - let g:pymode_doc_bind = "" - - -Frequent Problems -================= - -Read this section before opening an issue on the tracker. - -Python 3 Syntax ---------------- - -By default python-mode uses python 2 syntax checking. To enable python 3 -syntax checking (e.g. for async) add:: - - let g:pymode_python = 'python3' - -To your vimrc or exrc file - - -Documentation -============= - -Documentation is available in your vim ``:help pymode`` - - -Bugtracker -=========== - -If you have any suggestions, bug reports or -annoyances please report them to the issue tracker -at https://github.com/python-mode/python-mode/issues - - -Contributing -============ - -* Kirill Klenov (horneds@gmail.com) -* Bryce Guinta (https://github.com/brycepg) - -Also see the `AUTHORS` file. - -Development of python-mode happens at github: -https://github.com/python-mode/python-mode - -Please make a pull request to `development` branch and add yourself to -`AUTHORS`. - -Source Links -=================== -- `doc/pymode.txt - `__ - -- ``:help pymode`` -- `plugin/pymode.vim - `__ - -- python-mode VIM plugin -- `syntax/python.vim - `__ - -- python-mode ``python.vim`` VIM syntax -- `syntax/pyrex.vim - `__ - -- ``pyrex.vim`` VIM syntax (pyrex, Cython) -- `t/ - `__ - -- ``*.vim`` more python-mode VIM configuration -- `pymode/ - `__ - -- ``*.py`` -- python-mode Python module -- `pymode/libs/ - `__ - -- ``*.py`` -- `Python Libraries <#python-libraries>`__ - - -Python Libraries ------------------- -Vendored Python modules are located -mostly in -`pymode/libs/ `__. - - -====== -rope -====== -| PyPI: https://pypi.python.org/pypi/rope -| Src: https://github.com/python-rope/rope -| Docs: https://github.com/python-rope/rope/blob/master/docs/overview.rst -| Docs: https://github.com/python-rope/rope/blob/master/docs/library.rst - -======================== -ropemode -======================== -| PyPI: https://pypi.python.org/pypi/ropemode -| Src: https://github.com/python-rope/ropemode - -========= -ropevim -========= -| PyPI: https://pypi.python.org/pypi/ropevim -| Src: https://github.com/python-rope/ropevim -| Docs: https://github.com/python-rope/ropevim/blob/master/doc/ropevim.txt - -======= -pylama -======= -| PyPI: https://pypi.python.org/pypi/pylama -| Src: https://github.com/klen/pylama - -======== -pylint -======== -| PyPI: https://pypi.python.org/pypi/pylint -| Src: https://bitbucket.org/logilab/pylint -| Homepage: http://www.pylint.org/ -| Docs: http://docs.pylint.org/ -| Docs: http://docs.pylint.org/message-control.html -| Docs: http://docs.pylint.org/faq.html#message-control -| ErrCodes: http://pylint-messages.wikidot.com/all-codes -| ErrCodes: http://pylint-messages.wikidot.com/all-messages - -========== -pyflakes -========== -| PyPI: https://pypi.python.org/pypi/pyflakes -| Src: https://github.com/pyflakes/pyflakes -| ErrCodes: https://flake8.readthedocs.org/en/latest/warnings.html - -====== -pep8 -====== -| PyPI: https://pypi.python.org/pypi/pep8 -| Src: http://github.com/jcrocholl/pep8 -| PEP 8: http://www.python.org/dev/peps/pep-0008/ -| PEP 8: http://legacy.python.org/dev/peps/pep-0008/ -| Docs: https://pep8.readthedocs.org/en/latest/ -| Docs: https://pep8.readthedocs.org/en/latest/intro.html#configuration -| ErrCodes: https://pep8.readthedocs.org/en/latest/intro.html#error-codes - -========= -autopep8 -========= -| PyPI: https://pypi.python.org/pypi/autopep8 -| Src: https://github.com/hhatto/autopep8 - -======= -pep257 -======= -| PyPI: https://pypi.python.org/pypi/pep257 -| Src: http://github.com/GreenSteam/pep257 -| Docs: https://pep257.readthedocs.org/en/latest/ -| PEP 257: http://www.python.org/dev/peps/pep-0257/ -| ErrCodes: https://pep257.readthedocs.org/en/latest/error_codes.html - -======= -mccabe -======= -| PyPI: https://pypi.python.org/pypi/mccabe -| Src: https://github.com/flintwork/mccabe -| Docs: https://en.wikipedia.org/wiki/Cyclomatic_complexity - - -Vim Libraries ---------------- -Vendored Vim modules are located mostly in ``t/``. - -====================== -Python syntax for vim -====================== -| Src: http://www.hlabs.spb.ru/vim/python.vim - - -===================== -PEP8 VIM indentation -===================== -| Src: http://github.com/hynek/vim-python-pep8-indent - - - -Copyright -========= - -Copyright © 2013-2015 Kirill Klenov (klen_) - -License -======= - -Licensed under a `GNU lesser general public license`_. - -If you like this plugin, I would very appreciated if you kindly send me a postcard :) -My address is here: "Russia, 143500, MO, Istra, pos. Severny 8-3" to "Kirill Klenov". -**Thanks for support!** - -.. _GNU lesser general public license: http://www.gnu.org/copyleft/lesser.html -.. _klen: https://klen.github.com/ -.. _pydoc: http://docs.python.org/library/pydoc.html -.. _pathogen: https://github.com/tpope/vim-pathogen -.. _rope_: https://pypi.python.org/pypi/rope -.. _pylama_: https://github.com/klen/pylama -.. _pylint_: https://bitbucket.org/logilab/pylint -.. _pyflakes_: https://pypi.python.org/pypi/pyflakes -.. _autopep8_: https://github.com/hhatto/autopep8 -.. _pep257_: http://github.com/GreenSteam/pep257 -.. _mccabe_: https://github.com/flintwork/mccabe -.. _pythonvim: http://www.hlabs.spb.ru/vim/python.vim -.. _pep8_: http://github.com/jcrocholl/pep8 -.. _pep8indent: http://github.com/hynek/vim-python-pep8-indent -.. |logo| image:: https://raw.github.com/python-mode/python-mode/develop/logo.png diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..4798a99c --- /dev/null +++ b/readme.md @@ -0,0 +1,172 @@ +![](https://raw.github.com/python-mode/python-mode/develop/logo.png) +# Python-mode, a Python IDE for Vim + +------------------------------------------------------------------------------- + +*This project needs contributors.* + +**Please use python-mode tag on Stackoverflow to ask questions:** + + +------------------------------------------------------------------------------- + +Python-mode is a Vim plugin that magically converts Vim into a Python IDE. + +Why Python-mode? + +1. **Be more productive**: Pymode saves time by bring all tools necessary for + professional developers so that you can focus on bigger things. It has been + finely tuned based on decades of experience working with Vim and is + constantly kept uptodate. +2. **Get smart assistance**: Pymode knows all about your code. We use the + best-in-class intellisense code completion, on-the-fly error checking and + quick-fixes; easy project navigation and much more. +3. **Use the full power and capabilities of Vim**: Unlike traditional IDEs + which can only provide a small subset of Vim functionalities, you can do + everything and anything that you can in Vim. +4. **Modular structure**: We attempt to be create Python-mode in the same + principles of python: i.e. have a modular structure, so that as and when + better libraries evolve, we can provide you the best experience, while + abstracting the details so that you can get back to what you do best. +5. **Written mostly in Python**: 96.1% written in Python. Well we love Python + :) + +The plugin contains all you need to develop python applications in Vim. + +* Support Python version 2.6+ and 3.2+ +* Syntax highlighting +* Virtualenv support +* Run python code (`r`) +* Add/remove breakpoints (`b`) +* Improved Python indentation +* Python motions and operators (`]]`, `3[[`, `]]M`, `vaC`, `viM`, + `daC`, `ciM`, ...) +* Improved Python folding +* Run multiple code checkers simultaneously (`:PymodeLint`) +* Autofix PEP8 errors (`:PymodeLintAuto`) +* Search in python documentation (`K`) +* Code refactoring +* Intellisense code-completion +* Go to definition (`g`) +* And more, more ... + +See a screencast here: +Another old presentation here: + +**To read python-mode documentation in Vim, use** `:help pymode`. + +# Requirements + +Vim >= 7.3 (most features needed +python or +python3 support) (also +`--with-features=big` if you want `g:pymode_lint_signs`). + +# How to install + +## Manually (according to vim's package structure) + +As of vim8 there is an officially supported way of adding plugins. See `:tab +help packages` in vim for details. + + cd ~/.vim/pack/foo/start + git clone https://github.com/python-mode/python-mode.git + cd python-mode + git submodule update --init --recursive + + +## Using pathogen + + % cd ~/.vim + % mkdir -p bundle && cd bundle + % git clone https://github.com/python-mode/python-mode.git + +Enable [pathogen](https://github.com/tpope/vim-pathogen) in your `~/.vimrc`: + + " Pathogen load + filetype off + + call pathogen#infect() + call pathogen#helptags() + + filetype plugin indent on + syntax on + +## Manually + + % git clone https://github.com/python-mode/python-mode.git + % cd python-mode + % cp -R * ~/.vim + +Then rebuild **helptags** in vim: + + :helptags ~/.vim/doc/ + +**filetype-plugin** (`:help filetype-plugin-on`) and **filetype-indent** +(`:help filetype-indent-on`) must be enabled to use python-mode. + +# Troubleshooting + +If your python-mode doesn't work: + +1. Load Vim with only python-mode enabled (use debug.vim from pymode): + + vim -u /debug.vim + + And try to repeat your case. If no error occurs, seems like problem isn't in + the plugin. + +2. Type `:PymodeTroubleshooting` and fix any warnings or copy the output and + send it to me. (For example, by creating a [new github issue]( + https://github.com/python-mode/python-mode/issues/new) if one does + not already exist for the problem). + +# Frequent problems + +Read this section before opening an issue on the tracker. + +## Python 3 syntax + +By default python-mode uses python 2 syntax checking. To enable python 3 syntax +checking (e.g. for async) add: + + let g:pymode_python = 'python3' + +To your vimrc or exrc file. + +# Documentation + +Documentation is available in your vim `:help pymode`. + +# Bugtracker + +If you have any suggestions, bug reports or annoyances please report them to +the issue tracker at: + + +# Contributing + +* Kirill Klenov () +* Felipe Vieira () + +Also see the AUTHORS file. + +Development of python-mode happens at github: + + +Please make a pull request to development branch and add yourself to AUTHORS. + +### Python libraries + +Vendored Python modules are located mostly in +[pymode/libs/](https://github.com/python-mode/python-mode/tree/develop/pymode/libs). + +# Copyright + +Copyright © 2013-2015 Kirill Klenov (). + +# License + +Licensed under a [GNU lesser general public license](). + +If you like this plugin, I would very appreciated if you kindly send me +a postcard :) My address is here: "Russia, 143500, MO, Istra, pos. Severny 8-3" +to "Kirill Klenov". **Thanks for support!** From 5a2919217e5bfcd29123cca42b70d0df420c3a19 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Wed, 15 Nov 2017 20:59:17 -0200 Subject: [PATCH 009/206] updated authors --- AUTHORS | 7 +++++-- Changelog.rst | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index cc3de277..a917a124 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,8 +1,10 @@ -Maintainers: +Author: * Kirill Klenov -* Bryce Guinta (https://github.com/brycepg) +Maintainers: + +* Felipe M. Vieira (https://github.com/fmv1992) Contributors: @@ -15,6 +17,7 @@ Contributors: * Boris Filippov (http://github.com/frenzykryger); * Brad Mease (http://github.com/bmease) * Brendan Maguire (https://github.com/brendanmaguire) +* Bryce Guinta (https://github.com/brycepg) * Daniel Hahler (http://github.com/blueyed) * David Vogt (http://github.com/winged); * Denis Kasak (http://github.com/dkasak); diff --git a/Changelog.rst b/Changelog.rst index af249a25..158c4db5 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -303,7 +303,7 @@ do not get loaded. :: -2082d0b8fed7fff10b3f335cefc6a51dd25ee0b2 let g:pymode_syntax_builtin_objs = 2 + let g:pymode_syntax_builtin_objs = 0 let g:pymode_syntax_builtin_funcs = 0 * Change namespace of syntax variables From 6d497a405a66096ef5c0b51fd7ce260236ea5fda Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 19:57:23 -0200 Subject: [PATCH 010/206] changed troubleshooting mechanism and updated documentation on development guidelines --- autoload/pymode.vim | 21 +- autoload/pymode/debug.vim | 57 +++++ autoload/pymode/folding.vim | 3 - autoload/pymode/troubleshooting.vim | 89 ------- debug.vim | 13 - debugvimrc.vim | 21 ++ doc/pymode.txt | 376 +++++++++++++++------------- ftplugin/python/pymode.vim | 37 +++ plugin/pymode.vim | 1 - readme.md | 18 +- syntax/python.vim | 6 - 11 files changed, 339 insertions(+), 303 deletions(-) create mode 100644 autoload/pymode/debug.vim delete mode 100644 autoload/pymode/troubleshooting.vim delete mode 100644 debug.vim create mode 100644 debugvimrc.vim diff --git a/autoload/pymode.vim b/autoload/pymode.vim index 3127431d..6beb89a8 100644 --- a/autoload/pymode.vim +++ b/autoload/pymode.vim @@ -76,7 +76,6 @@ fun! pymode#trim_whitespaces() "{{{ endif endfunction "}}} - fun! pymode#save() "{{{ if &modifiable && &modified try @@ -120,9 +119,25 @@ fun! pymode#buffer_post_write() "{{{ endfunction "}}} fun! pymode#debug(msg) "{{{ + " Pymode's debug function. + " Should be called by other pymode's functions to report outputs. See + " the function PymodeDebugFolding for example. + " TODO: why echom here creates a problem? + " echom '' . a:msg + '|||||||||||' + + let l:info_separator = repeat('-', 79) + if g:pymode_debug - let g:pymode_debug += 1 - echom string(g:pymode_debug) . ': ' . string(a:msg) + if ! exists('g:pymode_debug_counter') + let g:pymode_debug_counter = 0 + endif + let g:pymode_debug_counter += 1 + " NOTE: Print a separator for every message except folding ones (since + " they could be many). + if a:msg !~ 'has folding:' + echom l:info_separator + endif + echom '' . 'pymode debug msg ' . g:pymode_debug_counter . ': ' . a:msg endif endfunction "}}} diff --git a/autoload/pymode/debug.vim b/autoload/pymode/debug.vim new file mode 100644 index 00000000..c24a5ee4 --- /dev/null +++ b/autoload/pymode/debug.vim @@ -0,0 +1,57 @@ +" Set debugging functions. + +" DESC: Get debug information about pymode problem. +fun! pymode#debug#sysinfo() "{{{ + " OS info. {{{ + let l:os_name = "Unknown" + if has('win16') || has('win32') || has('win64') + let l:os_name = "Windows" + else + let l:os_name = substitute(system('uname'), "\n", "", "") + endif + call pymode#debug("Operating system: " . l:os_name) + " }}} + " Loaded scripts info. {{{ + call pymode#debug("Scriptnames:") + let l:scriptnames_var = execute('scriptnames') + " }}} + " Variables info. {{{ + " Drop verbose file temporarily to prevent the 'let' from showing up. + let l:tmp = &verbosefile + set verbosefile= + let l:all_variables = filter( + \ split(execute('let', 'silent!'), '\n'), + \ 'v:val =~ "^pymode"') + let &verbosefile = l:tmp + " NOTE: echom does not display multiline messages. Thus a for loop is + " needed. + call pymode#debug("Pymode variables:") + for pymodevar in sort(l:all_variables) + echom pymodevar + endfor + " }}} + " Github commit info. {{{ + " Find in the scriptnames the first occurence of 'python-mode'. Then parse + " the result outputting its path. This is in turn fed into the git command. + call pymode#debug("Git commit: ") + let l:pymode_folder = substitute( + \ filter( + \ split(l:scriptnames_var, '\n'), + \ 'v:val =~ "/python-mode/"')[0], + \ '\(^\s\+[0-9]\+:\s\+\)\([/~].*python-mode\/\)\(.*\)', + \ '\2', + \ '') + let l:git_head_sha1 = system('git -C ' . expand(l:pymode_folder). ' rev-parse HEAD ' ) + echom join(filter(split(l:git_head_sha1, '\zs'), 'v:val =~? "[0-9A-Fa-f]"'), '') + " }}} + call pymode#debug("End of pymode#debug#sysinfo") +endfunction "}}} + +" DESC: Define debug folding function. +function! pymode#debug#foldingexpr(lnum) "{{{ + let l:get_folding_result = pymode#folding#expr(a:lnum) + " NOTE: the 'has folding:' expression is special in the pymode#debug. + call pymode#debug('line ' . a:lnum . ' has folding:' . l:get_folding_result) + return pymode#folding#expr(a:lnum) +endfunction +" }}} diff --git a/autoload/pymode/folding.vim b/autoload/pymode/folding.vim index 24f6b530..ca98b5c9 100644 --- a/autoload/pymode/folding.vim +++ b/autoload/pymode/folding.vim @@ -20,7 +20,6 @@ if s:symbol == '' endif " '''''''' - fun! pymode#folding#text() " {{{ let fs = v:foldstart while getline(fs) !~ s:def_regex && getline(fs) !~ s:docstring_begin_regex @@ -182,8 +181,6 @@ fun! s:BlockStart(line_number) "{{{ let max_indent = max([indent(prevnonblank(a:line_number)) - &shiftwidth, 0]) endif - " " Debug: - return searchpos('\v^\s{,'.max_indent.'}(def |class )\w', 'bcnW')[0] endfunction "}}} diff --git a/autoload/pymode/troubleshooting.vim b/autoload/pymode/troubleshooting.vim deleted file mode 100644 index 09955c92..00000000 --- a/autoload/pymode/troubleshooting.vim +++ /dev/null @@ -1,89 +0,0 @@ -" DESC: Get debug information about pymode problem -fun! pymode#troubleshooting#test() "{{{ - new - setlocal buftype=nofile bufhidden=delete noswapfile nowrap - - let os = "Unknown" - if has('win16') || has('win32') || has('win64') - let os = "Windows" - else - let os = substitute(system('uname'), "\n", "", "") - endif - - if !pymode#default('g:pymode_init', 1) - call pymode#init(expand(':p:h'), g:pymode_paths) - call pymode#virtualenv#init() - call pymode#breakpoint#init() - endif - - call append('0', ['Pymode diagnostic', - \ '===================', - \ 'VIM:' . v:version . ', OS: ' . os .', multi_byte:' . has('multi_byte') . ', pymode: ' . g:pymode_version . ', pymode-python: ' . g:pymode_python, - \ '']) - - if !exists('#filetypeplugin') - call append('$', ['WARNING: ', 'Python-mode required :filetype plugin indent on', '']) - endif - - call append('$', ['+python: ' . has('python')]) - call append('$', ['+python3: ' . has('python3'), '']) - - if g:pymode_python == 'disable' - - if !has('python') && !has('python3') - - call append('$', ['WARNING: Python-mode required vim compiled with +python or +python3.', - \ '"lint, rope, run, doc, virtualenv" features disabled.', '']) - - else - - call append('$', ['WARNING: Python is disabled by `pymode_python` option.', - \ '"lint, rope, run, doc, virtualenv" features disabled.', '']) - - endif - - else - - call append('$', 'VIM python paths:') - call append('$', '-----------------') - PymodePython << EOF -import vim -vim.command('let l:output = %s' % repr(sys.path)) -EOF - call append('$', output) - call append('$', '') - - endif - - call append('$', 'Pymode variables:') - call append('$', '-------------------') - call append('$', 'let pymode = ' . string(g:pymode)) - call append('$', 'let pymode_breakpoint = ' . string(g:pymode_breakpoint)) - call append('$', 'let pymode_breakpoint_bind = ' . string(g:pymode_breakpoint_bind)) - call append('$', 'let pymode_doc = ' . string(g:pymode_doc)) - call append('$', 'let pymode_doc_bind = ' . string(g:pymode_doc_bind)) - call append('$', 'let pymode_folding = ' . string(g:pymode_folding)) - call append('$', 'let pymode_indent = ' . string(g:pymode_indent)) - call append('$', 'let pymode_lint = ' . string(g:pymode_lint)) - call append('$', 'let pymode_lint_checkers = ' . string(g:pymode_lint_checkers)) - call append('$', 'let pymode_lint_cwindow = ' . string(g:pymode_lint_cwindow)) - call append('$', 'let pymode_lint_ignore = ' . string(g:pymode_lint_ignore)) - call append('$', 'let pymode_lint_message = ' . string(g:pymode_lint_message)) - call append('$', 'let pymode_lint_on_fly = ' . string(g:pymode_lint_on_fly)) - call append('$', 'let pymode_lint_on_write = ' . string(g:pymode_lint_on_write)) - call append('$', 'let pymode_lint_select = ' . string(g:pymode_lint_select)) - call append('$', 'let pymode_lint_signs = ' . string(g:pymode_lint_signs)) - call append('$', 'let pymode_motion = ' . string(g:pymode_motion)) - call append('$', 'let pymode_options = ' . string(g:pymode_options)) - call append('$', 'let pymode_paths = ' . string(g:pymode_paths)) - call append('$', 'let pymode_quickfix_maxheight = ' . string(g:pymode_quickfix_maxheight)) - call append('$', 'let pymode_quickfix_minheight = ' . string(g:pymode_quickfix_minheight)) - call append('$', 'let pymode_rope = ' . string(g:pymode_rope)) - call append('$', 'let pymode_run = ' . string(g:pymode_run)) - call append('$', 'let pymode_run_bind = ' . string(g:pymode_run_bind)) - call append('$', 'let pymode_trim_whitespaces = ' . string(g:pymode_trim_whitespaces)) - call append('$', 'let pymode_virtualenv = ' . string(g:pymode_virtualenv)) - call append('$', 'let pymode_virtualenv_enabled = ' . string(g:pymode_virtualenv_enabled)) - call append('$', 'let pymode_virtualenv_path = ' . string(g:pymode_virtualenv_path)) - -endfunction "}}} diff --git a/debug.vim b/debug.vim deleted file mode 100644 index c7d32661..00000000 --- a/debug.vim +++ /dev/null @@ -1,13 +0,0 @@ -" Use this settings for testing the plugin. -" Run vim with command -" -" $ vim -u debug.py -" -" Only python-mode will be loaded. - - -execute('set rtp+='. expand(':p:h')) -set rtp -=$HOME/.vim -set rtp -=$HOME/.vim/after -set nocp -syntax enable diff --git a/debugvimrc.vim b/debugvimrc.vim new file mode 100644 index 00000000..750062b6 --- /dev/null +++ b/debugvimrc.vim @@ -0,0 +1,21 @@ +" Use this settings for testing the plugin. +" +" Run vim with command: +" +" $ vim -u ./debug.vim /my/py/file.py +" +" Only python-mode will be loaded. + +" Modify vimrc configuration. +execute('set rtp+='. expand(':p:h')) +set rtp -=$HOME/.vim +set rtp -=$HOME/.vim/after +set nocompatible + +" Activate debugging. +let g:pymode_debug = 1 + +" Define a common shell for non Windows systems. +if ! (has('win16') || has('win32') || has('win64')) + set shell=/bin/bash +endif diff --git a/doc/pymode.txt b/doc/pymode.txt index f466508b..4a29d6ce 100644 --- a/doc/pymode.txt +++ b/doc/pymode.txt @@ -1,4 +1,4 @@ -*pymode.txt* *python-mode.txt* *pymode* *python-mode* +*pymode.txt* For Vim Version 8.0 Last change: 2017 November 11 ____ _ _ ____ _ _ _____ _ _ __ __ _____ ____ ____ ~ ( _ \( \/ )(_ _)( )_( )( _ )( \( )___( \/ )( _ )( _ \( ___) ~ @@ -8,34 +8,39 @@ Version: 0.9.4 -============================================================================== -CONTENTS *pymode-contents* - - 1.Intro.......................................................|pymode-intro| - 2.Common functionality.......................................|pymode-common| - 2.1 Python version...............................|pymode-python-version| - 2.2 Python indentation...................................|pymode-indent| - 2.3 Python folding......................................|pymode-folding| - 2.4 Vim motion...........................................|pymode-motion| - 2.5 Show documentation............................|pymode-documentation| - 2.6 Support virtualenv...............................|pymode-virtualenv| - 2.7 Run code................................................|pymode-run| - 2.8 Breakpoints.....................................|pymode-breakpoints| - 3. Code checking...............................................|pymode-lint| - 3.1 Code checkers options..........................|pymode-lint-options| - 4. Rope support................................................|pymode-rope| - 4.1 Code completion..................................|pymode-completion| - 4.2 Find definition.................................|pymode-rope-findit| - 4.3 Refactoring................................|pymode-rope-refactoring| - 4.4 Undo/Redo changes.................................|pymode-rope-undo| - 5. Syntax....................................................|pymode-syntax| - 6.FAQ...........................................................|pymode-faq| - 7.Credits...................................................|pymode-credits| - 8.License...................................................|pymode-license| - -============================================================================== +=============================================================================== +CONTENTS *pymode-contents* + +1. Intro...........................................................|pymode-intro| +2. Common functionality...........................................|pymode-common| + 2.1 Python version....................................|pymode-python-version| + 2.2 Python indentation........................................|pymode-indent| + 2.3 Python folding...........................................|pymode-folding| + 2.4 Vim motion................................................|pymode-motion| + 2.5 Show documentation.................................|pymode-documentation| + 2.6 Support virtualenv....................................|pymode-virtualenv| + 2.7 Run code.....................................................|pymode-run| + 2.8 Breakpoints..........................................|pymode-breakpoints| +3. Code checking....................................................|pymode-lint| + 3.1 Code checkers options...............................|pymode-lint-options| +4. Rope support.....................................................|pymode-rope| + 4.1 Code completion.......................................|pymode-completion| + 4.2 Find definition......................................|pymode-rope-findit| + 4.3 Refactoring.....................................|pymode-rope-refactoring| + 4.4 Undo/Redo changes......................................|pymode-rope-undo| +5. Syntax.........................................................|pymode-syntax| +6. FAQ...............................................................|pymode-faq| +7. Development...............................................|pymode-development| +8. Credits.......................................................|pymode-credits| +9. License.......................................................|pymode-license| + +=============================================================================== 1. Intro ~ - *pymode-intro* + *pymode-intro* + +XXX IMPORTANT: As of 2017-11-18 python-mode is going through a major redesign. +Thus some of its functionality may not work as expected. Please be patient and +do report bugs or inconsistencies in its documentation. Python-mode is a vim plugin that allows you to use the pylint, rope, and pydoc libraries in vim to provide features like python code bug checking, @@ -46,7 +51,7 @@ need to install the pylint or rope libraries on your system. Python-mode contains all you need to develop python applications in Vim. -Features: *pymode-features* +Features: *pymode-features* - Support Python version 2.6+ and 3.2+ - Syntax highlighting @@ -67,34 +72,34 @@ Features: *pymode-features* - And more, more ... -============================================================================== +=============================================================================== 2. Common functionality ~ - *pymode-common* + *pymode-common* This script provides the following options that can customizes the behavior of -PythonMode. These options should be set in your |vimrc|. +python-mode. These options should be set in your |vimrc|. - Below shows the default values. +Find below the default values: -Turn on the whole plugin *'g:pymode'* +Turn on the whole plugin. *'g:pymode'* > let g:pymode = 1 -Turn off plugin's warnings *'g:pymode_warnings'* +Turn off plugin's warnings. *'g:pymode_warnings'* > let g:pymode_warnings = 1 -Add paths to `sys.path` *'g:pymode_paths'* +Add paths to `sys.path` *'g:pymode_paths'* Value is list of path's strings. > let g:pymode_paths = [] -Trim unused white spaces on save *'g:pymode_trim_whitespaces'* +Trim unused white spaces on save. *'g:pymode_trim_whitespaces'* > let g:pymode_trim_whitespaces = 1 -Setup default python options *'g:pymode_options'* +Setup default python options. *'g:pymode_options'* > let g:pymode_options = 1 @@ -111,29 +116,29 @@ python buffers: > setlocal commentstring=#%s setlocal define=^\s*\\(def\\\\|class\\) -Setup max line length *'g:pymode_options_max_line_length'* +Setup max line length *'g:pymode_options_max_line_length'* > let g:pymode_options_max_line_length = 79 -Enable colorcolumn display at max_line_length *'g:pymode_options_colorcolumn'* +Enable colorcolumn display at max_line_length. *'g:pymode_options_colorcolumn'* > let g:pymode_options_colorcolumn = 1 -Setup pymode |quickfix| window +Setup pymode |quickfix| window. - *'g:pymode_quickfix_maxheight'* *'g:pymode_quickfix_minheight'* + *'g:pymode_quickfix_maxheight'* *'g:pymode_quickfix_minheight'* > let g:pymode_quickfix_minheight = 3 let g:pymode_quickfix_maxheight = 6 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.1. Python version ~ - *pymode-python-version* + *pymode-python-version* By default pymode looks for current python version supported in your Vim. You could choose prefer version, but value will be tested on loading. - *'g:pymode_python'* + *'g:pymode_python'* > let g:pymode_python = 'python' @@ -143,73 +148,73 @@ python-features of **pymode** will be disabled. Set value to `python3` if you are working with python3 projects. You could use |exrc| ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.2 Python indentation ~ - *pymode-indent* + *pymode-indent* Pymode supports PEP8-compatible python indent. -Enable pymode indentation *'g:pymode_indent'* +Enable pymode indentation *'g:pymode_indent'* > let g:pymode_indent = 1 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.3 Python folding ~ - *pymode-folding* + *pymode-folding* Fast and usual python folding in Vim. -Enable pymode folding *'g:pymode_folding'* +Enable pymode folding *'g:pymode_folding'* > let g:pymode_folding = 1 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.4 Vim motion ~ - *pymode-motion* + *pymode-motion* Support Vim motion (See |operator|) for python objects (such as functions, class and methods). `C` — means class `M` — means method or function - *pymode-motion-keys* - -================ ============================ -Key Command -================ ============================ -[[ Jump to previous class or function (normal, visual, operator modes) -]] Jump to next class or function (normal, visual, operator modes) -[M Jump to previous class or method (normal, visual, operator modes) -]M Jump to next class or method (normal, visual, operator modes) -aC Select a class. Ex: vaC, daC, yaC, caC (normal, operator modes) -iC Select inner class. Ex: viC, diC, yiC, ciC (normal, operator modes) -aM Select a function or method. Ex: vaM, daM, yaM, caM (normal, operator modes) -iM Select inner function or method. Ex: viM, diM, yiM, ciM (normal, operator modes) -================ ============================ - -Enable pymode-motion *'g:pymode_motion'* + *pymode-motion-keys* + +==== ============================ +Key Command +==== ============================ +[[ Jump to previous class or function (normal, visual, operator modes) +]] Jump to next class or function (normal, visual, operator modes) +[M Jump to previous class or method (normal, visual, operator modes) +]M Jump to next class or method (normal, visual, operator modes) +aC Select a class. Ex: vaC, daC, yaC, caC (normal, operator modes) +iC Select inner class. Ex: viC, diC, yiC, ciC (normal, operator modes) +aM Select a function or method. Ex: vaM, daM, yaM, caM (normal, operator modes) +iM Select inner function or method. Ex: viM, diM, yiM, ciM (normal, operator modes) +==== ============================ + +Enable pymode-motion *'g:pymode_motion'* > let g:pymode_motion = 1 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.5 Show documentation ~ - *pymode-documentation* + *pymode-documentation* Pymode could show documentation for current word by `pydoc`. Commands: *:PymodeDoc* — show documentation -Turns on the documentation script *'g:pymode_doc'* +Turns on the documentation script *'g:pymode_doc'* > let g:pymode_doc = 1 Bind keys to show documentation for current word (selection) - *'g:pymode_doc_bind'* + *'g:pymode_doc_bind'* > let g:pymode_doc_bind = 'K' ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.6 Support virtualenv ~ - *pymode-virtualenv* + *pymode-virtualenv* Commands: *:PymodeVirtualenv* -- Activate virtualenv (path can be absolute or @@ -219,33 +224,33 @@ Enable automatic virtualenv detection *'g:pymode_virtualenv' > let g:pymode_virtualenv = 1 -Set path to virtualenv manually *'g:pymode_virtualenv_path'* +Set path to virtualenv manually *'g:pymode_virtualenv_path'* > let g:pymode_virtualenv_path = $VIRTUAL_ENV ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.7 Run code ~ - *pymode-run* + *pymode-run* Commands: *:PymodeRun* -- Run current buffer or selection -Turn on the run code script *'g:pymode_run'* +Turn on the run code script *'g:pymode_run'* > let g:pymode_run = 1 -Binds keys to run python code *'g:pymode_run_bind'* +Binds keys to run python code *'g:pymode_run_bind'* > let g:pymode_run_bind = 'r' ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 2.8 Breakpoints ~ - *pymode-breakpoints* + *pymode-breakpoints* Pymode automatically detects available debugger (like pdb, ipdb, pudb) and user can set/unset breakpoint with one key and without code checking and etc. -Enable functionality *'g:pymode_breakpoint'* +Enable functionality *'g:pymode_breakpoint'* > let g:pymode_breakpoint = 1 @@ -258,9 +263,9 @@ Manually set breakpoint command (leave empty for automatic detection) let g:pymode_breakpoint_cmd = '' -============================================================================== +=============================================================================== 3. Code checking ~ - *pymode-lint* + *pymode-lint* Pymode supports `pylint`, `pep257`, `pep8`, `pyflakes`, `mccabe` code checkers. You could run several similar checkers. @@ -277,44 +282,45 @@ Commands: *:PymodeLintToggle* -- Toggle code checking *:PymodeLintAuto* -- Fix PEP8 errors in current buffer automatically -Turn on code checking *'g:pymode_lint'* +Turn on code checking *'g:pymode_lint'* > let g:pymode_lint = 1 -Check code on every save (if file has been modified) *'g:pymode_lint_on_write'* +Check code on every save (if file has been modified) *'g:pymode_lint_on_write'* > let g:pymode_lint_on_write = 1 -Check code on every save (every) *'g:pymode_lint_unmodified'* +Check code on every save (every) *'g:pymode_lint_unmodified'* > let g:pymode_lint_unmodified = 0 -Check code when editing (on the fly) *'g:pymode_lint_on_fly'* +Check code when editing (on the fly) *'g:pymode_lint_on_fly'* > let g:pymode_lint_on_fly = 0 -Show error message if cursor placed at the error line *'g:pymode_lint_message'* +Show error message if cursor placed at the error line *'g:pymode_lint_message'* > let g:pymode_lint_message = 1 -Default code checkers (you could set several) *'g:pymode_lint_checkers'* +Default code checkers (you could set several) *'g:pymode_lint_checkers'* > let g:pymode_lint_checkers = ['pyflakes', 'pep8', 'mccabe'] Values may be chosen from: `pylint`, `pep8`, `mccabe`, `pep257`, `pyflakes`. -Skip errors and warnings *'g:pymode_lint_ignore'* -E.g. "E501,W002", "E2,W" (Skip all Warnings and Errors that starts with E2) and etc +Skip errors and warnings *'g:pymode_lint_ignore'* +E.g. "E501,W002", "E2,W" (Skip all Warnings and Errors that starts with E2) and +etc > let g:pymode_lint_ignore = "E501,W" -Select some error or warnings. *'g:pymode_lint_select'* +Select some error or warnings. *'g:pymode_lint_select'* By example you disable all warnings starting from 'W', but want to see warning 'W0011' and warning 'W430' > let g:pymode_lint_select = "E501,W0011,W430" -Sort errors by relevance *'g:pymode_lint_sort'* +Sort errors by relevance *'g:pymode_lint_sort'* If not empty, errors will be sort by defined relevance E.g. let g:pymode_lint_sort = ['E', 'C', 'I'] " Errors first 'E', after them 'C' and ... @@ -322,11 +328,11 @@ after them 'C' and ... let g:pymode_lint_sort = [] Auto open cwindow (quickfix) if any errors have been found - *'g:pymode_lint_cwindow'* + *'g:pymode_lint_cwindow'* > let g:pymode_lint_cwindow = 1 -Place error |signs| *'g:pymode_signs'* +Place error |signs| *'g:pymode_signs'* > let g:pymode_lint_signs = 1 @@ -339,13 +345,13 @@ Definitions for |signs| let g:pymode_lint_info_symbol = 'II' let g:pymode_lint_pyflakes_symbol = 'FF' ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 3.1 Set code checkers options ~ - *pymode-lint-options* + *pymode-lint-options* Pymode has the ability to set code checkers options from pymode variables: -Set PEP8 options *'g:pymode_lint_options_pep8'* +Set PEP8 options *'g:pymode_lint_options_pep8'* > let g:pymode_lint_options_pep8 = \ {'max_line_length': g:pymode_options_max_line_length}) @@ -353,19 +359,19 @@ Set PEP8 options *'g:pymode_lint_options_pep8'* See https://pep8.readthedocs.org/en/1.4.6/intro.html#configuration for more info. -Set Pyflakes options *'g:pymode_lint_options_pyflakes'* +Set Pyflakes options *'g:pymode_lint_options_pyflakes'* > let g:pymode_lint_options_pyflakes = { 'builtins': '_' } -Set mccabe options *'g:pymode_lint_options_mccabe'* +Set mccabe options *'g:pymode_lint_options_mccabe'* > let g:pymode_lint_options_mccabe = { 'complexity': 12 } -Set pep257 options *'g:pymode_lint_options_pep257'* +Set pep257 options *'g:pymode_lint_options_pep257'* > let g:pymode_lint_options_pep257 = {} -Set pylint options *'g:pymode_lint_options_pylint'* +Set pylint options *'g:pymode_lint_options_pylint'* > let g:pymode_lint_options_pylint = \ {'max-line-length': g:pymode_options_max_line_length}) @@ -373,10 +379,9 @@ Set pylint options *'g:pymode_lint_options_pylint'* See http://docs.pylint.org/features.html#options for more info. - -============================================================================== -3. Rope support ~ - *pymode-rope* +=============================================================================== +4. Rope support ~ + *pymode-rope* Pymode supports Rope refactoring operations, code completion and code assists. @@ -390,12 +395,12 @@ Commands: |:PymodeRopeUndo| -- Undo changes from last refactoring -Turn on the rope script *'g:pymode_rope'* +Turn on the rope script *'g:pymode_rope'* > let g:pymode_rope = 1 .ropeproject Folder ~ - *.ropeproject* + *.ropeproject* *:PymodeRopeNewProject* [] -- Open new Rope project in the given path *:PymodeRopeRegenerate* -- Regenerate the project cache @@ -422,13 +427,13 @@ all its child directories, which may slow scanning down (because of many, possibly unrelated, files) Enable searching for |.ropeproject| in parent directories - *'g:pymode_rope_lookup_project'* + *'g:pymode_rope_lookup_project'* > let g:pymode_rope_lookup_project = 0 You can also manually set the rope project directory. If not specified rope will use the current directory. - *'g:pymode_rope_project_root'* + *'g:pymode_rope_project_root'* > let g:pymode_rope_project_root = "" @@ -438,15 +443,14 @@ keep it outside of your project root. The rope library treats this folder as a project resource, so the path will always be relative to your project root (a leading '/' will be ignored). You may use `'..'` path segments to place the folder outside of your project root. - *'g:pymode_rope_ropefolder'* + *'g:pymode_rope_ropefolder'* > let g:pymode_rope_ropefolder='.ropeproject' - Show documentation for element under cursor ~ -Show documentation for object under cursor. *'g:pymode_rope_show_doc_bind'* +Show documentation for object under cursor. *'g:pymode_rope_show_doc_bind'* Leave empty to disable the key binding. > let g:pymode_rope_show_doc_bind = 'd' @@ -455,9 +459,9 @@ Regenerate project cache on every save (if file has been modified) > let g:pymode_rope_regenerate_on_write = 1 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 4.1 Completion ~ - *pymode-completion* + *pymode-completion* By default you can use for autocompletion. The first entry will be automatically selected and you can press to insert the entry in @@ -466,25 +470,25 @@ your code. and / works too. Autocompletion is also called by typing a period in |Insert| mode by default. -Turn on code completion support in the plugin *'g:pymode_rope_completion'* +Turn on code completion support in the plugin *'g:pymode_rope_completion'* > let g:pymode_rope_completion = 1 Turn on autocompletion when typing a period - *'g:pymode_rope_complete_on_dot'* + *'g:pymode_rope_complete_on_dot'* > let g:pymode_rope_complete_on_dot = 1 -Keymap for autocomplete *'g:pymode_rope_completion_bind'* +Keymap for autocomplete *'g:pymode_rope_completion_bind'* > let g:pymode_rope_completion_bind = '' Extended autocompletion (rope could complete objects which have not been -imported) from project *'g:pymode_rope_autoimport'* +imported) from project *'g:pymode_rope_autoimport'* > let g:pymode_rope_autoimport = 0 -Load modules to autoimport by default *'g:pymode_rope_autoimport_modules'* +Load modules to autoimport by default *'g:pymode_rope_autoimport_modules'* > let g:pymode_rope_autoimport_modules = ['os', 'shutil', 'datetime'] @@ -493,24 +497,24 @@ Offer to unresolved import object after completion. let g:pymode_rope_autoimport_import_after_complete = 0 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 4.2 Find definition ~ - *pymode-rope-findit* + *pymode-rope-findit* By default when you press *g* on any object in your code you will be moved to definition. -Leave empty for disable key binding. *'g:pymode_rope_goto_definition_bind'* +Leave empty for disable key binding. *'g:pymode_rope_goto_definition_bind'* > let g:pymode_rope_goto_definition_bind = 'g' Command for open window when definition has been found -Values are (`e`, `new`, `vnew`) *'g:pymode_rope_goto_definition_cmd'* +Values are (`e`, `new`, `vnew`) *'g:pymode_rope_goto_definition_cmd'* > let g:pymode_rope_goto_definition_cmd = 'new' ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 4.3 Refactoring ~ - *pymode-rope-refactoring* + *pymode-rope-refactoring* Rename method/function/class/variable in the project ~ @@ -518,7 +522,7 @@ Pymode can rename everything: classes, functions, modules, packages, methods, variables and keyword arguments. Keymap for rename method/function/class/variables under cursor - *'g:pymode_rope_rename_bind'* + *'g:pymode_rope_rename_bind'* > let g:pymode_rope_rename_bind = 'rr' @@ -527,7 +531,7 @@ Rename a current module/package ~ *:PymodeRopeRenameModule* -- Rename current module -Keymap for rename current module *'g:pymode_rope_rename_module_bind'* +Keymap for rename current module *'g:pymode_rope_rename_module_bind'* > let g:pymode_rope_rename_module_bind = 'r1r' @@ -538,18 +542,18 @@ Imports ~ Organize imports sorts imports, too. It does that according to PEP8. Unused imports will be dropped. -Keymap *'g:pymode_rope_organize_imports_bind'* +Keymap *'g:pymode_rope_organize_imports_bind'* > let g:pymode_rope_organize_imports_bind = 'ro' -Insert import for current word under cursor *'g:pymode_rope_autoimport_bind'* +Insert import for current word under cursor *'g:pymode_rope_autoimport_bind'* Should be enabled |'g:pymode_rope_autoimport'| > let g:pymode_rope_autoimport_bind = 'ra' Convert module to package ~ - *'g:pymode_rope_module_to_package_bind'* + *'g:pymode_rope_module_to_package_bind'* *:PymodeRopeModuleToPackage* -- convert current module to package @@ -559,19 +563,19 @@ Keybinding: Extract method/variable ~ - *pymode-rope-extract* + *pymode-rope-extract* Extract method/variable from selected lines. - *'g:pymode_rope_extract_method_bind'* - *'g:pymode_rope_extract_variable_bind'* + *'g:pymode_rope_extract_method_bind'* + *'g:pymode_rope_extract_variable_bind'* > let g:pymode_rope_extract_method_bind = 'rm' let g:pymode_rope_extract_variable_bind = 'rl' Use function ~ - *pymode-rope-use* + *pymode-rope-use* It tries to find the places in which a function can be used and changes the code to call it instead. @@ -580,7 +584,7 @@ code to call it instead. Move method/fields ~ - *pymode-rope-move* + *pymode-rope-move* It happens when you perform move refactoring on a method of a class. In this refactoring, a method of a class is moved to the class of one of its @@ -595,10 +599,10 @@ Change function signature ~ let g:pymode_rope_change_signature_bind = 'rs' ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 4.4 Undo/Redo changes ~ - *pymode-rope-undo* - *pymode-rope-redo* + *pymode-rope-undo* + *pymode-rope-redo* Commands: @@ -606,90 +610,95 @@ Commands: *:PymodeRopeRedo* -- Redo last changes in the project -============================================================================== +=============================================================================== 5. Syntax ~ - *pymode-syntax* + *pymode-syntax* -Turn on pymode syntax *'g:pymode_syntax'* +Turn on pymode syntax *'g:pymode_syntax'* > let g:pymode_syntax = 1 Slower syntax synchronization that is better at handling code blocks in docstrings. Consider disabling this on slower hardware. - *'g:pymode_syntax_slow_sync'* + *'g:pymode_syntax_slow_sync'* > let g:pymode_syntax_slow_sync = 1 -Enable all python highlights *'g:pymode_syntax_all'* +Enable all python highlights *'g:pymode_syntax_all'* > let g:pymode_syntax_all = 1 -Highlight "print" as a function *'g:pymode_syntax_print_as_function'* +Highlight "print" as a function *'g:pymode_syntax_print_as_function'* > let g:pymode_syntax_print_as_function = 0 -Highlight "async/await" keywords *'g:pymode_syntax_highlight_async_await'* +Highlight "async/await" keywords *'g:pymode_syntax_highlight_async_await'* > let g:pymode_syntax_highlight_async_await = g:pymode_syntax_all -Highlight '=' operator *'g:pymode_syntax_highlight_equal_operator'* +Highlight '=' operator *'g:pymode_syntax_highlight_equal_operator'* > let g:pymode_syntax_highlight_equal_operator = g:pymode_syntax_all -Highlight '*' operator *'g:pymode_syntax_highlight_stars_operator'* +Highlight '*' operator *'g:pymode_syntax_highlight_stars_operator'* > let g:pymode_syntax_highlight_stars_operator = g:pymode_syntax_all -Highlight 'self' keyword *'g:pymode_syntax_highlight_self'* +Highlight 'self' keyword *'g:pymode_syntax_highlight_self'* > let g:pymode_syntax_highlight_self = g:pymode_syntax_all -Highlight indent's errors *'g:pymode_syntax_indent_errors'* +Highlight indent's errors *'g:pymode_syntax_indent_errors'* > let g:pymode_syntax_indent_errors = g:pymode_syntax_all -Highlight space's errors *'g:pymode_syntax_space_errors'* +Highlight space's errors *'g:pymode_syntax_space_errors'* > let g:pymode_syntax_space_errors = g:pymode_syntax_all Highlight string formatting *'g:pymode_syntax_string_formatting'* - *'g:pymode_syntax_string_format'* - *'g:pymode_syntax_string_templates'* - *'g:pymode_syntax_doctests'* + *'g:pymode_syntax_string_format'* + *'g:pymode_syntax_string_templates'* + *'g:pymode_syntax_doctests'* > let g:pymode_syntax_string_formatting = g:pymode_syntax_all let g:pymode_syntax_string_format = g:pymode_syntax_all let g:pymode_syntax_string_templates = g:pymode_syntax_all let g:pymode_syntax_doctests = g:pymode_syntax_all -Highlight builtin objects (True, False, ...) *'g:pymode_syntax_builtin_objs'* +Highlight builtin objects (True, False, ...) *'g:pymode_syntax_builtin_objs'* > let g:pymode_syntax_builtin_objs = g:pymode_syntax_all -Highlight builtin types (str, list, ...) *'g:pymode_syntax_builtin_types'* +Highlight builtin types (str, list, ...) *'g:pymode_syntax_builtin_types'* > let g:pymode_syntax_builtin_types = g:pymode_syntax_all Highlight exceptions (TypeError, ValueError, ...) - *'g:pymode_syntax_highlight_exceptions'* + *'g:pymode_syntax_highlight_exceptions'* > let g:pymode_syntax_highlight_exceptions = g:pymode_syntax_all Highlight docstrings as pythonDocstring (otherwise as pythonString) - *'g:pymode_syntax_docstrings'* + *'g:pymode_syntax_docstrings'* > let g:pymode_syntax_docstrings = g:pymode_syntax_all -============================================================================== +=============================================================================== 6. FAQ ~ - *pymode-faq* + *pymode-faq* Python-mode doesn't work ------------------------ -Open any python file and run ":call pymode#troubleshooting#test()", -fix the warning or send me the output. +Start python mode with: +`vim -u /debugvimrc.vim` +Reproduce the error and submit your python mode debug file. You check its +location with `:messages` for something like: +`pymode debug msg 1: Starting debug on: 2017-11-18 16:44:13 with file /tmp/pymode_debug_file.txt` +Please submit the entire content of the file along with a reasoning of why the +plugin seems broken. Rope completion is very slow *pymode-rope-slow* @@ -715,7 +724,6 @@ You may also set |'g:pymode_rope_project_root'| to manually specify the project root path. - Pylint check is very slow ------------------------- @@ -726,7 +734,6 @@ modules if possible. Try using another code checker: see You may set |exrc| and |secure| in your |vimrc| to auto-set custom settings from `.vimrc` from your projects directories. - OSX cannot import urandom ------------------------- @@ -742,9 +749,23 @@ The sequence of commands that fixed this: brew link python < -============================================================================== -7. Credits ~ - *pymode-credits* +=============================================================================== +7. Development~ + *pymode-development* + +This section briefly defines development guidelines for python-mode. + +1. This help file uses vim's conventions defined at |help-writing|. +2. The name of the plugin shall be referred to as 'python-mode' throughout +documentation (except as a first word in a sentence in which case is +'Python-mode'). +3. All defined functions should use vim's conventions and start with 'Pymode'. +4. Special marks for project development are `XXX` and `TODO`. They provide a +easy way for developers to check pending issues. + +=============================================================================== +8. Credits ~ + *pymode-credits* Kirill Klenov http://klen.github.com/ http://github.com/klen/ @@ -778,19 +799,20 @@ The sequence of commands that fixed this: http://github.com/hynek/vim-python-pep8-indent -============================================================================== -8. License ~ - *pymode-license* +=============================================================================== +9. License ~ + *pymode-license* Python-mode is released under the GNU lesser general public license. See: http://www.gnu.org/copyleft/lesser.html -If you like this plugin, I would very appreciated if you kindly send me a postcard :) +If you like this plugin, I would very appreciated if you kindly send me a +postcard :) -My address is: "Russia, 143500, MO, Istra, pos. Severny 8-3" to "Kirill Klenov". -Thanks for your support! +My address is: "Russia, 143500, MO, Istra, pos. Severny 8-3" to "Kirill +Klenov". Thanks for your support! ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- - vim:tw=78:ts=8:ft=help:norl: + vim:tw=79:ts=8:ft=help:norl: diff --git a/ftplugin/python/pymode.vim b/ftplugin/python/pymode.vim index 79842616..11dba3c4 100644 --- a/ftplugin/python/pymode.vim +++ b/ftplugin/python/pymode.vim @@ -210,3 +210,40 @@ if g:pymode_rope endif endif + + +if g:pymode_debug + " Redefine functions to be debugged here functions here. + + " NOTE: The redraw seems to be necessary to force messages to get echoed to + " the screen. See: + " https://groups.google.com/forum/#!topic/vim_use/EfcXOjq_rKE + " for details. + " silent! redraw! + " TODO: when loading with 'vim -u ./debug.vim' the messages shown in vim + " are unduly cleared. Need a fix. + + " Start debbuging environment. {{{ + if ! &verbosefile + " Get a system independent temporary filename. The 'marker' variable is + " used to get rid of a null character getting inserted at position. + " substitute() was not able to remove it. + let g:pymode_debug_tempfile=matchstr( + \ execute( + \ g:pymode_python + \ . " import os;import tempfile; marker='|';" + \ . " print(marker, tempfile.gettempdir(), os.sep, " + \ . "'pymode_debug_file.txt', marker, sep='', end='')"), + \ '|\zs.*\ze|') + execute "set verbosefile=" . g:pymode_debug_tempfile + endif + call pymode#debug('Starting debug on: ' + \ . strftime("\%Y-\%m-\%d \%H:\%M:\%S") + \ . ' with file ' . &verbosefile) + " }}} + if g:pymode_folding + setlocal foldexpr=pymode#debug#foldingexpr(v:lnum) + endif + call pymode#debug#sysinfo() + +endif diff --git a/plugin/pymode.vim b/plugin/pymode.vim index a9b195fc..ea96ed19 100644 --- a/plugin/pymode.vim +++ b/plugin/pymode.vim @@ -2,7 +2,6 @@ let g:pymode_version = "0.9.4" com! PymodeVersion echomsg "Current python-mode version: " . g:pymode_version -com! PymodeTroubleshooting call pymode#troubleshooting#test() " Enable pymode by default :) call pymode#default('g:pymode', 1) diff --git a/readme.md b/readme.md index 4798a99c..8e2b450b 100644 --- a/readme.md +++ b/readme.md @@ -107,17 +107,13 @@ Then rebuild **helptags** in vim: If your python-mode doesn't work: -1. Load Vim with only python-mode enabled (use debug.vim from pymode): - - vim -u /debug.vim - - And try to repeat your case. If no error occurs, seems like problem isn't in - the plugin. - -2. Type `:PymodeTroubleshooting` and fix any warnings or copy the output and - send it to me. (For example, by creating a [new github issue]( - https://github.com/python-mode/python-mode/issues/new) if one does - not already exist for the problem). +1. **(From the FAQ)** Start python mode with: + `vim -u /debugvimrc.vim` + Reproduce the error and submit your python mode debug file. You check its + location with `:messages` for something like: + `pymode debug msg 1: Starting debug on: 2017-11-18 16:44:13 with file /tmp/pymode_debug_file.txt`. + Please submit the entire content of the file along with a reasoning of why + the plugin seems broken. # Frequent problems diff --git a/syntax/python.vim b/syntax/python.vim index e94877ee..89f6d929 100644 --- a/syntax/python.vim +++ b/syntax/python.vim @@ -62,7 +62,6 @@ call pymode#default('g:pymode_syntax_slow_sync', 1) " }}} - " For version 5.x: Clear all syntax items if version < 600 syntax clear @@ -125,7 +124,6 @@ endif " }}} - " Decorators {{{ " ============== @@ -135,7 +133,6 @@ endif " }}} - " Comments {{{ " ============ @@ -146,7 +143,6 @@ endif " }}} - " Errors {{{ " ========== @@ -167,7 +163,6 @@ endif " }}} - " Strings {{{ " =========== @@ -321,7 +316,6 @@ endif " }}} - if g:pymode_syntax_slow_sync syn sync minlines=2000 else From fe9c27061d6da83b58d453661bc4b0a66b444fb3 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 21:23:40 -0200 Subject: [PATCH 011/206] improved debugging function with history output --- debugvimrc.vim | 11 +++++++++++ doc/pymode.txt | 7 +++++-- ftplugin/python/pymode.vim | 10 +++++++++- readme.md | 17 +++++++++-------- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/debugvimrc.vim b/debugvimrc.vim index 750062b6..a8b3f188 100644 --- a/debugvimrc.vim +++ b/debugvimrc.vim @@ -6,6 +6,14 @@ " " Only python-mode will be loaded. +" Disable all persistence between sessions. +let skip_defaults_vim=1 +" TODO XXX: this nevertheless keeps viminfo enabled. As a workaround the flag +" '-i NONE' should be added to vim's loading. +set viminfo= +set nobackup +set noswapfile + " Modify vimrc configuration. execute('set rtp+='. expand(':p:h')) set rtp -=$HOME/.vim @@ -19,3 +27,6 @@ let g:pymode_debug = 1 if ! (has('win16') || has('win32') || has('win64')) set shell=/bin/bash endif + +" IMPORTANT: Do note that the history of this session is saved on the log file. +" See the augroup in ./ftplugin/python/pymode.vim file. diff --git a/doc/pymode.txt b/doc/pymode.txt index 4a29d6ce..8568397c 100644 --- a/doc/pymode.txt +++ b/doc/pymode.txt @@ -693,13 +693,16 @@ Python-mode doesn't work ------------------------ Start python mode with: -`vim -u /debugvimrc.vim` -Reproduce the error and submit your python mode debug file. You check its +`vim -i NONE -u /debugvimrc.vim` +Reproduce the error and submit your python mode debug file. You can check its location with `:messages` for something like: `pymode debug msg 1: Starting debug on: 2017-11-18 16:44:13 with file /tmp/pymode_debug_file.txt` Please submit the entire content of the file along with a reasoning of why the plugin seems broken. + *Underlined do check for sensitive information in the file before + *Underlined submitting! + Rope completion is very slow *pymode-rope-slow* ---------------------------- diff --git a/ftplugin/python/pymode.vim b/ftplugin/python/pymode.vim index 11dba3c4..2f8e661f 100644 --- a/ftplugin/python/pymode.vim +++ b/ftplugin/python/pymode.vim @@ -241,9 +241,17 @@ if g:pymode_debug \ . strftime("\%Y-\%m-\%d \%H:\%M:\%S") \ . ' with file ' . &verbosefile) " }}} + " Redefine folding expression. {{{ if g:pymode_folding setlocal foldexpr=pymode#debug#foldingexpr(v:lnum) endif call pymode#debug#sysinfo() + " }}} + " Define auto commands for vim. {{{ + augroup augroup_save_issue_commands + autocmd! + autocmd VimLeave *.py | call pymode#debug('Session history:') | silent! history + augroup END + " }}} -endif + endif diff --git a/readme.md b/readme.md index 8e2b450b..9369139e 100644 --- a/readme.md +++ b/readme.md @@ -103,17 +103,18 @@ Then rebuild **helptags** in vim: **filetype-plugin** (`:help filetype-plugin-on`) and **filetype-indent** (`:help filetype-indent-on`) must be enabled to use python-mode. -# Troubleshooting +# Troubleshooting/Debugging If your python-mode doesn't work: -1. **(From the FAQ)** Start python mode with: - `vim -u /debugvimrc.vim` - Reproduce the error and submit your python mode debug file. You check its - location with `:messages` for something like: - `pymode debug msg 1: Starting debug on: 2017-11-18 16:44:13 with file /tmp/pymode_debug_file.txt`. - Please submit the entire content of the file along with a reasoning of why - the plugin seems broken. +**(From the FAQ)** Start python mode with: +`vim -i NONE -u /debugvimrc.vim` +Reproduce the error and submit your python mode debug file. You can check its +location with `:messages` for something like: +`pymode debug msg 1: Starting debug on: 2017-11-18 16:44:13 with file /tmp/pymode_debug_file.txt`. +Please submit the entire content of the file along with a reasoning of why the +plugin seems broken. +***Do check for sensitive information in the file before submitting.*** # Frequent problems From 65c68eae06ae127741652da666425454a811b118 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 22:14:56 -0200 Subject: [PATCH 012/206] fixed breakpoint_cmd being improperly reset (gh issue 795) --- autoload/pymode/breakpoint.vim | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/autoload/pymode/breakpoint.vim b/autoload/pymode/breakpoint.vim index c3189aad..b9e09fb2 100644 --- a/autoload/pymode/breakpoint.vim +++ b/autoload/pymode/breakpoint.vim @@ -1,17 +1,11 @@ fun! pymode#breakpoint#init() "{{{ - if !g:pymode_breakpoint + " If breakpoints are either disabled or already defined do nothing. + if ! g:pymode_breakpoint || g:pymode_breakpoint_cmd != '' return - endif - - if g:pymode_breakpoint_cmd == '' - let g:pymode_breakpoint_cmd = 'import pdb; pdb.set_trace() # XXX BREAKPOINT' - - if g:pymode_python == 'disable' - return - endif - endif + " Else go for a 'smart scan' of the defaults. + else PymodePython << EOF @@ -26,6 +20,7 @@ for module in ('wdb', 'pudb', 'ipdb'): continue EOF + endif endfunction "}}} From 76c582b9df2c3895cc34ef7b238ff0ddfabeea1e Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 22:34:04 -0200 Subject: [PATCH 013/206] enforced list data type for pymode_lint_ignore (gh issue 786) --- doc/pymode.txt | 5 ++--- pymode/lint.py | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/pymode.txt b/doc/pymode.txt index 8568397c..ac3a0fa9 100644 --- a/doc/pymode.txt +++ b/doc/pymode.txt @@ -309,10 +309,9 @@ Default code checkers (you could set several) *'g:pymode_lint_checkers' Values may be chosen from: `pylint`, `pep8`, `mccabe`, `pep257`, `pyflakes`. Skip errors and warnings *'g:pymode_lint_ignore'* -E.g. "E501,W002", "E2,W" (Skip all Warnings and Errors that starts with E2) and -etc +E.g. ["W", "E2"] (Skip all Warnings and the Errors starting with E2) etc. > - let g:pymode_lint_ignore = "E501,W" + let g:pymode_lint_ignore = ["E501", "W",] Select some error or warnings. *'g:pymode_lint_select'* By example you disable all warnings starting from 'W', but want to see warning diff --git a/pymode/lint.py b/pymode/lint.py index 25f2414c..01b0b527 100644 --- a/pymode/lint.py +++ b/pymode/lint.py @@ -35,10 +35,12 @@ def code_check(): # Fixed in v0.9.3: these two parameters may be passed as strings. # DEPRECATE: v:0.10.0: need to be set as lists. if isinstance(env.var('g:pymode_lint_ignore'), str): + raise ValueError ('g:pymode_lint_ignore should have a list type') ignore = env.var('g:pymode_lint_ignore').split(',') else: ignore = env.var('g:pymode_lint_ignore') if isinstance(env.var('g:pymode_lint_select'), str): + raise ValueError ('g:pymode_lint_ignore should have a list type') select = env.var('g:pymode_lint_select').split(',') else: select = env.var('g:pymode_lint_select') From c7e6baa189d6da94941276cdcf84d1b83f7a2406 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 23:03:01 -0200 Subject: [PATCH 014/206] fixed folding issue when definition was on first line (gh issue 808) --- autoload/pymode/folding.vim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/autoload/pymode/folding.vim b/autoload/pymode/folding.vim index ca98b5c9..12825da5 100644 --- a/autoload/pymode/folding.vim +++ b/autoload/pymode/folding.vim @@ -1,4 +1,4 @@ -" Python-mode folding functions +k" Python-mode folding function2 " Notice that folding is based on single line so complex regular expressions " that take previous line into consideration are not fit for the job. @@ -156,10 +156,14 @@ fun! s:BlockStart(line_number) "{{{ " In case the end of the block is indented to a higher level than the def " statement plus one shiftwidth, we need to find the indent level at the " bottom of that if/for/try/while/etc. block. - let previous_definition = searchpos(s:def_regex, 'bcnW') + " Flags from searchpos() (same as search()): + " b: search Backward instead of forward + " n: do Not move the cursor + " W: don't Wrap around the end of the file + let previous_definition = searchpos(s:def_regex, 'bnW') if previous_definition != [0, 0] while previous_definition != [0, 0] && indent(previous_definition[0]) >= indent(a:line_number) - let previous_definition = searchpos(s:def_regex, 'bncW') + let previous_definition = searchpos(s:def_regex, 'bnW') call cursor(previous_definition[0] - 1, 0) endwhile endif From 7d376f1d57bbc5be11b61bd6cefb5f6def616350 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 23:21:27 -0200 Subject: [PATCH 015/206] adapted readme.md to development guidelines --- readme.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 9369139e..9905c8a4 100644 --- a/readme.md +++ b/readme.md @@ -114,6 +114,7 @@ location with `:messages` for something like: `pymode debug msg 1: Starting debug on: 2017-11-18 16:44:13 with file /tmp/pymode_debug_file.txt`. Please submit the entire content of the file along with a reasoning of why the plugin seems broken. + ***Do check for sensitive information in the file before submitting.*** # Frequent problems @@ -141,8 +142,11 @@ the issue tracker at: # Contributing -* Kirill Klenov () -* Felipe Vieira () +The contributing guidelines for this plugin are outlined at +`:help pymode-development`. + +* Author: Kirill Klenov () +* Maintainer: Felipe Vieira () Also see the AUTHORS file. From 97351299bbd66393a28f33d2dd21549a6ac01786 Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sat, 18 Nov 2017 23:42:02 -0200 Subject: [PATCH 016/206] removed travis test as they were abandoned long ago; the testing issue still persists --- .ruby-gemset | 1 - .ruby-version | 1 - .travis.yml | 8 +- Gemfile | 3 - Makefile | 98 ----------------- Rakefile | 11 -- python-mode.yaml | 268 ----------------------------------------------- 7 files changed, 2 insertions(+), 388 deletions(-) delete mode 100644 .ruby-gemset delete mode 100644 .ruby-version delete mode 100644 Gemfile delete mode 100644 Makefile delete mode 100644 Rakefile delete mode 100644 python-mode.yaml diff --git a/.ruby-gemset b/.ruby-gemset deleted file mode 100644 index 5ded393e..00000000 --- a/.ruby-gemset +++ /dev/null @@ -1 +0,0 @@ -vim-flavor diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 67b8bc0d..00000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -ruby-1.9.3 diff --git a/.travis.yml b/.travis.yml index e10ed9f1..af733524 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,2 @@ -language: ruby -python: "2.7" -rvm: - - 1.9.3 -script: - - make travis +# Deactivated. +# This plugin needs a robust test suite. diff --git a/Gemfile b/Gemfile deleted file mode 100644 index a87f4e1a..00000000 --- a/Gemfile +++ /dev/null @@ -1,3 +0,0 @@ -source 'https://rubygems.org' - -gem 'vim-flavor', '~> 1.1' diff --git a/Makefile b/Makefile deleted file mode 100644 index 5e5a0990..00000000 --- a/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -PYMODE = $(CURDIR)/pymode -LIBS = $(PYMODE)/libs -PYLAMA = $(LIBS)/pylama - -.PHONY: clean -clean: - find $(CURDIR) -name "*.pyc" -delete - rm -rf $(CURDIR)/build - rm -rf *.deb - -VERSION?=minor -# target: release - Bump version -release: - git fetch origin - git checkout master - git rebase - git merge develop - bumpversion $(VERSION) - git checkout develop - git rebase - git merge master - git push origin develop master - git push --tags - -.PHONY: minor -minor: release - -.PHONY: patch -patch: - make release VERSION=patch - -.PHONY: major -major: - make release VERSION=major - -# Temporary disable rope tests on Travis -.PHONY: travis -travis: - rake test - -.PHONY: test t -test: - bundle install - rm -rf $(CURDIR)/.ropeproject - rake test -t: test - -.PHONY: pylama -pylama: - rm -rf $(PYLAMA) - make $(PYLAMA) - make $(PYLAMA)/lint/pylama_pylint - @pip install --upgrade --force-reinstall --target=$(LIBS) pydocstyle - @pip install --upgrade --force-reinstall --target=$(LIBS) pycodestyle - @pip install --upgrade --force-reinstall --target=$(LIBS) pyflakes - @pip install --upgrade --force-reinstall --target=$(LIBS) mccabe - @pip install --upgrade --force-reinstall --target=$(LIBS) pylint - @find $(LIBS) -name *.dist-info -type d | xargs rm -rf - @find $(LIBS) -name *.egg-info -type d | xargs rm -rf - @find $(LIBS) -name test* -type d | xargs rm -rf - -.PHONY: rope -rope: - @git clone https://github.com/python-rope/rope.git $(CURDIR)/_/rope - @rm -rf $(CURDIR)/pymode/libs/rope - @cp -r $(CURDIR)/_/rope/rope $(CURDIR)/pymode/libs/. - -$(PYLAMA): - cp -r $$PRJDIR/pylama/pylama $(PYLAMA) - -$(PYLAMA)/lint/pylama_pylint: - cp -r $$PRJDIR/pylama/plugins/pylama_pylint/pylama_pylint/ $(PYLAMA)/lint/pylama_pylint - -$(CURDIR)/build: - mkdir -p $(CURDIR)/build/usr/share/vim/addons - mkdir -p $(CURDIR)/build/usr/share/vim/registry - cp -r after autoload doc ftplugin plugin pymode syntax $(CURDIR)/build/usr/share/vim/addons/. - cp -r python-mode.yaml $(CURDIR)/build/usr/share/vim/registry/. - -PACKAGE_VERSION?=$(shell git describe --tags `git rev-list master --tags --max-count=1`) -PACKAGE_NAME="vim-python-mode" -PACKAGE_MAINTAINER="Kirill Klenov " -PACKAGE_URL=http://github.com/klen/python-mode -deb: clean $(CURDIR)/build - @fpm -s dir -t deb -a all \ - -n $(PACKAGE_NAME) \ - -v $(PACKAGE_VERSION) \ - -m $(PACKAGE_MAINTAINER) \ - --url $(PACKAGE_URL) \ - --license "GNU lesser general public license" \ - --description "Vim-Swissknife for python" \ - --deb-user root \ - --deb-group root \ - -C $(CURDIR)/build \ - -d "python2.7" \ - -d "vim-addon-manager" \ - usr - @mv *.deb ~/Dropbox/projects/deb/load diff --git a/Rakefile b/Rakefile deleted file mode 100644 index 63a3a361..00000000 --- a/Rakefile +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env rake - -task :ci => [:dump, :test] - -task :dump do - sh 'vim --version' -end - -task :test do - sh 'bundle exec vim-flavor test' -end diff --git a/python-mode.yaml b/python-mode.yaml deleted file mode 100644 index b5635e68..00000000 --- a/python-mode.yaml +++ /dev/null @@ -1,268 +0,0 @@ -addon: python-mode -description: "swissknife for python" -files: - - after/ftplugin/pyrex.vim - - after/ftplugin/python.vim - - after/indent/pyrex.vim - - after/indent/python.vim - - autoload/pymode/breakpoint.vim - - autoload/pymode/doc.vim - - autoload/pymode/folding.vim - - autoload/pymode/indent.vim - - autoload/pymode/lint.vim - - autoload/pymode/motion.vim - - autoload/pymode/rope.vim - - autoload/pymode/run.vim - - autoload/pymode/tools/loclist.vim - - autoload/pymode/tools/signs.vim - - autoload/pymode/troubleshooting.vim - - autoload/pymode/virtualenv.vim - - autoload/pymode.vim - - ftplugin/pyrex.vim - - ftplugin/python/pymode.vim - - plugin/pymode.vim - - syntax/pyrex.vim - - syntax/python.vim - - pymode/__init__.py - - pymode/async.py - - pymode/autopep8.py - - pymode/environment.py - - pymode/libs/pylama/__init__.py - - pymode/libs/pylama/config.py - - pymode/libs/pylama/core.py - - pymode/libs/pylama/hook.py - - pymode/libs/pylama/libs/__init__.py - - pymode/libs/pylama/libs/importlib.py - - pymode/libs/pylama/libs/inirama.py - - pymode/libs/pylama/lint/__init__.py - - pymode/libs/pylama/lint/extensions.py - - pymode/libs/pylama/lint/pylama_mccabe/__init__.py - - pymode/libs/pylama/lint/pylama_mccabe/mccabe.py - - pymode/libs/pylama/lint/pylama_pep257/__init__.py - - pymode/libs/pylama/lint/pylama_pep257/pep257.py - - pymode/libs/pylama/lint/pylama_pep8/__init__.py - - pymode/libs/pylama/lint/pylama_pep8/pep8.py - - pymode/libs/pylama/lint/pylama_pyflakes/__init__.py - - pymode/libs/pylama/lint/pylama_pyflakes/pyflakes/__init__.py - - pymode/libs/pylama/lint/pylama_pyflakes/pyflakes/checker.py - - pymode/libs/pylama/lint/pylama_pyflakes/pyflakes/messages.py - - pymode/libs/pylama/lint/pylama_pylint/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/main.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/__pkginfo__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/__pkginfo__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/as_string.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/bases.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/builder.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/exceptions.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/inference.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/manager.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/mixins.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/node_classes.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/nodes.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/protocols.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/raw_building.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/rebuilder.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/scoped_nodes.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/astroid/utils.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/base.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/classes.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/design_analysis.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/exceptions.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/format.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/imports.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/logging.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/misc.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/newstyle.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/raw_metrics.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/similar.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/stdlib.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/strings.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/typecheck.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/utils.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/variables.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/config.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/interfaces.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/lint.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/__pkginfo__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/changelog.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/compat.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/configuration.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/decorators.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/deprecation.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/graph.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/interface.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/modutils.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/optik_ext.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/textutils.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/tree.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/ureports/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/ureports/docbook_writer.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/ureports/html_writer.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/ureports/nodes.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/ureports/text_writer.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/logilab/common/visitor.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/reporters/__init__.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/reporters/guireporter.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/reporters/html.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/reporters/text.py - - pymode/libs/pylama/lint/pylama_pylint/pylint/utils.py - - pymode/libs/pylama/main.py - - pymode/libs/pylama/tasks.py - - pymode/libs/pylama/utils.py - - pymode/libs2/rope/__init__.py - - pymode/libs2/rope/base/__init__.py - - pymode/libs2/rope/base/arguments.py - - pymode/libs2/rope/base/ast.py - - pymode/libs2/rope/base/astutils.py - - pymode/libs2/rope/base/builtins.py - - pymode/libs2/rope/base/change.py - - pymode/libs2/rope/base/codeanalyze.py - - pymode/libs2/rope/base/default_config.py - - pymode/libs2/rope/base/evaluate.py - - pymode/libs2/rope/base/exceptions.py - - pymode/libs2/rope/base/fscommands.py - - pymode/libs2/rope/base/history.py - - pymode/libs2/rope/base/libutils.py - - pymode/libs2/rope/base/oi/__init__.py - - pymode/libs2/rope/base/oi/doa.py - - pymode/libs2/rope/base/oi/memorydb.py - - pymode/libs2/rope/base/oi/objectdb.py - - pymode/libs2/rope/base/oi/objectinfo.py - - pymode/libs2/rope/base/oi/runmod.py - - pymode/libs2/rope/base/oi/soa.py - - pymode/libs2/rope/base/oi/soi.py - - pymode/libs2/rope/base/oi/transform.py - - pymode/libs2/rope/base/prefs.py - - pymode/libs2/rope/base/project.py - - pymode/libs2/rope/base/pycore.py - - pymode/libs2/rope/base/pynames.py - - pymode/libs2/rope/base/pynamesdef.py - - pymode/libs2/rope/base/pyobjects.py - - pymode/libs2/rope/base/pyobjectsdef.py - - pymode/libs2/rope/base/pyscopes.py - - pymode/libs2/rope/base/resourceobserver.py - - pymode/libs2/rope/base/resources.py - - pymode/libs2/rope/base/simplify.py - - pymode/libs2/rope/base/stdmods.py - - pymode/libs2/rope/base/taskhandle.py - - pymode/libs2/rope/base/utils.py - - pymode/libs2/rope/base/worder.py - - pymode/libs2/rope/contrib/__init__.py - - pymode/libs2/rope/contrib/autoimport.py - - pymode/libs2/rope/contrib/changestack.py - - pymode/libs2/rope/contrib/codeassist.py - - pymode/libs2/rope/contrib/finderrors.py - - pymode/libs2/rope/contrib/findit.py - - pymode/libs2/rope/contrib/fixmodnames.py - - pymode/libs2/rope/contrib/fixsyntax.py - - pymode/libs2/rope/contrib/generate.py - - pymode/libs2/rope/refactor/__init__.py - - pymode/libs2/rope/refactor/change_signature.py - - pymode/libs2/rope/refactor/encapsulate_field.py - - pymode/libs2/rope/refactor/extract.py - - pymode/libs2/rope/refactor/functionutils.py - - pymode/libs2/rope/refactor/importutils/__init__.py - - pymode/libs2/rope/refactor/importutils/actions.py - - pymode/libs2/rope/refactor/importutils/importinfo.py - - pymode/libs2/rope/refactor/importutils/module_imports.py - - pymode/libs2/rope/refactor/inline.py - - pymode/libs2/rope/refactor/introduce_factory.py - - pymode/libs2/rope/refactor/introduce_parameter.py - - pymode/libs2/rope/refactor/localtofield.py - - pymode/libs2/rope/refactor/method_object.py - - pymode/libs2/rope/refactor/move.py - - pymode/libs2/rope/refactor/multiproject.py - - pymode/libs2/rope/refactor/occurrences.py - - pymode/libs2/rope/refactor/patchedast.py - - pymode/libs2/rope/refactor/rename.py - - pymode/libs2/rope/refactor/restructure.py - - pymode/libs2/rope/refactor/similarfinder.py - - pymode/libs2/rope/refactor/sourceutils.py - - pymode/libs2/rope/refactor/suites.py - - pymode/libs2/rope/refactor/topackage.py - - pymode/libs2/rope/refactor/usefunction.py - - pymode/libs2/rope/refactor/wildcards.py - - pymode/libs3/rope/__init__.py - - pymode/libs3/rope/base/__init__.py - - pymode/libs3/rope/base/arguments.py - - pymode/libs3/rope/base/ast.py - - pymode/libs3/rope/base/astutils.py - - pymode/libs3/rope/base/builtins.py - - pymode/libs3/rope/base/change.py - - pymode/libs3/rope/base/codeanalyze.py - - pymode/libs3/rope/base/default_config.py - - pymode/libs3/rope/base/evaluate.py - - pymode/libs3/rope/base/exceptions.py - - pymode/libs3/rope/base/fscommands.py - - pymode/libs3/rope/base/history.py - - pymode/libs3/rope/base/libutils.py - - pymode/libs3/rope/base/oi/__init__.py - - pymode/libs3/rope/base/oi/doa.py - - pymode/libs3/rope/base/oi/memorydb.py - - pymode/libs3/rope/base/oi/objectdb.py - - pymode/libs3/rope/base/oi/objectinfo.py - - pymode/libs3/rope/base/oi/runmod.py - - pymode/libs3/rope/base/oi/soa.py - - pymode/libs3/rope/base/oi/soi.py - - pymode/libs3/rope/base/oi/transform.py - - pymode/libs3/rope/base/prefs.py - - pymode/libs3/rope/base/project.py - - pymode/libs3/rope/base/pycore.py - - pymode/libs3/rope/base/pynames.py - - pymode/libs3/rope/base/pynamesdef.py - - pymode/libs3/rope/base/pyobjects.py - - pymode/libs3/rope/base/pyobjectsdef.py - - pymode/libs3/rope/base/pyscopes.py - - pymode/libs3/rope/base/resourceobserver.py - - pymode/libs3/rope/base/resources.py - - pymode/libs3/rope/base/simplify.py - - pymode/libs3/rope/base/stdmods.py - - pymode/libs3/rope/base/taskhandle.py - - pymode/libs3/rope/base/utils.py - - pymode/libs3/rope/base/worder.py - - pymode/libs3/rope/contrib/__init__.py - - pymode/libs3/rope/contrib/autoimport.py - - pymode/libs3/rope/contrib/changestack.py - - pymode/libs3/rope/contrib/codeassist.py - - pymode/libs3/rope/contrib/finderrors.py - - pymode/libs3/rope/contrib/findit.py - - pymode/libs3/rope/contrib/fixmodnames.py - - pymode/libs3/rope/contrib/fixsyntax.py - - pymode/libs3/rope/contrib/generate.py - - pymode/libs3/rope/refactor/__init__.py - - pymode/libs3/rope/refactor/change_signature.py - - pymode/libs3/rope/refactor/encapsulate_field.py - - pymode/libs3/rope/refactor/extract.py - - pymode/libs3/rope/refactor/functionutils.py - - pymode/libs3/rope/refactor/importutils/__init__.py - - pymode/libs3/rope/refactor/importutils/actions.py - - pymode/libs3/rope/refactor/importutils/importinfo.py - - pymode/libs3/rope/refactor/importutils/module_imports.py - - pymode/libs3/rope/refactor/inline.py - - pymode/libs3/rope/refactor/introduce_factory.py - - pymode/libs3/rope/refactor/introduce_parameter.py - - pymode/libs3/rope/refactor/localtofield.py - - pymode/libs3/rope/refactor/method_object.py - - pymode/libs3/rope/refactor/move.py - - pymode/libs3/rope/refactor/multiproject.py - - pymode/libs3/rope/refactor/occurrences.py - - pymode/libs3/rope/refactor/patchedast.py - - pymode/libs3/rope/refactor/rename.py - - pymode/libs3/rope/refactor/restructure.py - - pymode/libs3/rope/refactor/similarfinder.py - - pymode/libs3/rope/refactor/sourceutils.py - - pymode/libs3/rope/refactor/suites.py - - pymode/libs3/rope/refactor/topackage.py - - pymode/libs3/rope/refactor/usefunction.py - - pymode/libs3/rope/refactor/wildcards.py - - pymode/lint.py - - pymode/rope.py - - pymode/run.py - - pymode/utils.py - - pymode/virtualenv.py - - pymode/libs/pylama/lint/pylama_pylint/pylint.rc From c224a04237c4ebfc986d4166ed46bf48971cce1d Mon Sep 17 00:00:00 2001 From: "Felipe M. Vieira" Date: Sun, 19 Nov 2017 00:46:33 -0200 Subject: [PATCH 017/206] changed modules from pymode/libs to submodules --- .gitmodules | 28 + pymode/autopep8.py | 3886 +---------------- pymode/libs/_markerlib/__init__.py | 16 + pymode/libs/_markerlib/markers.py | 119 + ...ts.functools_lru_cache-1.3-py3.5-nspkg.pth | 1 - .../libs/backports/configparser/__init__.py | 1390 ------ pymode/libs/backports/configparser/helpers.py | 171 - pymode/libs/backports/functools_lru_cache.py | 184 - .../libs/configparser-3.5.0-py2.7-nspkg.pth | 1 - pymode/libs/configparser.py | 52 - pymode/libs/easy_install.py | 5 + pymode/libs/isort/__init__.py | 28 - pymode/libs/isort/__main__.py | 3 - pymode/libs/isort/hooks.py | 82 - pymode/libs/isort/isort.py | 969 ---- pymode/libs/isort/main.py | 296 -- pymode/libs/isort/natural.py | 47 - pymode/libs/isort/pie_slice.py | 594 --- pymode/libs/isort/pylama_isort.py | 29 - pymode/libs/isort/settings.py | 256 -- pymode/libs/lazy_object_proxy/__init__.py | 20 - pymode/libs/lazy_object_proxy/cext.c | 1421 ------ pymode/libs/lazy_object_proxy/compat.py | 9 - pymode/libs/lazy_object_proxy/simple.py | 246 -- pymode/libs/lazy_object_proxy/slots.py | 414 -- pymode/libs/lazy_object_proxy/utils.py | 13 - pymode/libs/logilab/__init__.py | 1 + pymode/libs/logilab/common/__init__.py | 184 + pymode/libs/logilab/common/cache.py | 114 + pymode/libs/logilab/common/changelog.py | 238 + pymode/libs/logilab/common/clcommands.py | 334 ++ pymode/libs/logilab/common/compat.py | 78 + pymode/libs/logilab/common/configuration.py | 1105 +++++ pymode/libs/logilab/common/daemon.py | 101 + pymode/libs/logilab/common/date.py | 335 ++ pymode/libs/logilab/common/debugger.py | 214 + pymode/libs/logilab/common/decorators.py | 281 ++ pymode/libs/logilab/common/deprecation.py | 189 + pymode/libs/logilab/common/fileutils.py | 404 ++ pymode/libs/logilab/common/graph.py | 282 ++ pymode/libs/logilab/common/interface.py | 71 + pymode/libs/logilab/common/logging_ext.py | 195 + pymode/libs/logilab/common/modutils.py | 713 +++ pymode/libs/logilab/common/optik_ext.py | 392 ++ pymode/libs/logilab/common/optparser.py | 92 + pymode/libs/logilab/common/proc.py | 277 ++ pymode/libs/logilab/common/pytest.py | 1202 +++++ pymode/libs/logilab/common/registry.py | 1125 +++++ pymode/libs/logilab/common/shellutils.py | 462 ++ pymode/libs/logilab/common/sphinx_ext.py | 87 + pymode/libs/logilab/common/sphinxutils.py | 122 + pymode/libs/logilab/common/table.py | 929 ++++ pymode/libs/logilab/common/tasksqueue.py | 101 + pymode/libs/logilab/common/testlib.py | 1338 ++++++ pymode/libs/logilab/common/textutils.py | 537 +++ pymode/libs/logilab/common/tree.py | 369 ++ pymode/libs/logilab/common/umessage.py | 194 + .../libs/logilab/common/ureports/__init__.py | 172 + .../logilab/common/ureports/docbook_writer.py | 140 + .../logilab/common/ureports/html_writer.py | 133 + pymode/libs/logilab/common/ureports/nodes.py | 203 + .../logilab/common/ureports/text_writer.py | 145 + pymode/libs/logilab/common/urllib2ext.py | 89 + pymode/libs/logilab/common/vcgutils.py | 216 + pymode/libs/logilab/common/visitor.py | 109 + pymode/libs/logilab/common/xmlutils.py | 61 + .../libs/logilab_common-1.0.2-py2.7-nspkg.pth | 1 + .../DESCRIPTION.rst | 153 + .../logilab_common-1.0.2.dist-info/METADATA | 169 + .../logilab_common-1.0.2.dist-info/RECORD | 87 + .../libs/logilab_common-1.0.2.dist-info/WHEEL | 5 + .../metadata.json | 1 + .../namespace_packages.txt | 1 + .../top_level.txt | 1 + pymode/libs/mccabe.py | 348 +- pymode/libs/pkg_resources/__init__.py | 3113 +++++++++++++ .../_vendor}/__init__.py | 0 .../_vendor/packaging/__about__.py | 31 + .../_vendor/packaging/__init__.py | 24 + .../_vendor/packaging/_compat.py | 40 + .../_vendor/packaging/_structures.py | 78 + .../_vendor/packaging/specifiers.py | 784 ++++ .../_vendor/packaging/version.py | 403 ++ pymode/libs/pycodestyle.py | 2328 +--------- pymode/libs/pydocstyle | 1 + pymode/libs/pydocstyle/__init__.py | 7 - pymode/libs/pydocstyle/__main__.py | 19 - pymode/libs/pydocstyle/checker.py | 711 --- pymode/libs/pydocstyle/cli.py | 94 - pymode/libs/pydocstyle/config.py | 614 --- pymode/libs/pydocstyle/data/imperatives.txt | 232 - .../pydocstyle/data/imperatives_blacklist.txt | 100 - pymode/libs/pydocstyle/parser.py | 594 --- pymode/libs/pydocstyle/utils.py | 27 - pymode/libs/pydocstyle/violations.py | 246 -- pymode/libs/pydocstyle/wordlists.py | 39 - pymode/libs/pyflakes | 1 + pymode/libs/pyflakes/__init__.py | 1 - pymode/libs/pyflakes/__main__.py | 5 - pymode/libs/pyflakes/api.py | 187 - pymode/libs/pyflakes/checker.py | 1355 ------ pymode/libs/pyflakes/messages.py | 233 - pymode/libs/pyflakes/reporter.py | 81 - pymode/libs/pyflakes/scripts/pyflakes.py | 8 - pymode/libs/pylama | 1 + pymode/libs/pylama/__init__.py | 10 - pymode/libs/pylama/__main__.py | 6 - pymode/libs/pylama/async.py | 75 - pymode/libs/pylama/config.py | 265 -- pymode/libs/pylama/core.py | 207 - pymode/libs/pylama/errors.py | 113 - pymode/libs/pylama/hook.py | 110 - pymode/libs/pylama/libs/__init__.py | 1 - pymode/libs/pylama/libs/importlib.py | 38 - pymode/libs/pylama/libs/inirama.py | 405 -- pymode/libs/pylama/lint/__init__.py | 19 - pymode/libs/pylama/lint/extensions.py | 47 - pymode/libs/pylama/lint/pylama_mccabe.py | 26 - pymode/libs/pylama/lint/pylama_pycodestyle.py | 66 - pymode/libs/pylama/lint/pylama_pydocstyle.py | 33 - pymode/libs/pylama/lint/pylama_pyflakes.py | 51 - .../pylama/lint/pylama_pylint/__init__.py | 12 - pymode/libs/pylama/lint/pylama_pylint/main.py | 110 - .../libs/pylama/lint/pylama_pylint/pylint.rc | 23 - pymode/libs/pylama/lint/pylama_radon.py | 31 - pymode/libs/pylama/main.py | 105 - pymode/libs/pylama/pytest.py | 87 - pymode/libs/six.py | 74 +- pymode/libs/snowballstemmer | 1 + pymode/libs/snowballstemmer/__init__.py | 57 - pymode/libs/snowballstemmer/among.py | 15 - pymode/libs/snowballstemmer/basestemmer.py | 351 -- pymode/libs/snowballstemmer/danish_stemmer.py | 364 -- pymode/libs/snowballstemmer/dutch_stemmer.py | 699 --- .../libs/snowballstemmer/english_stemmer.py | 1115 ----- .../libs/snowballstemmer/finnish_stemmer.py | 853 ---- pymode/libs/snowballstemmer/french_stemmer.py | 1307 ------ pymode/libs/snowballstemmer/german_stemmer.py | 619 --- .../libs/snowballstemmer/hungarian_stemmer.py | 1061 ----- .../libs/snowballstemmer/italian_stemmer.py | 1033 ----- .../libs/snowballstemmer/norwegian_stemmer.py | 308 -- pymode/libs/snowballstemmer/porter_stemmer.py | 789 ---- .../snowballstemmer/portuguese_stemmer.py | 965 ---- .../libs/snowballstemmer/romanian_stemmer.py | 900 ---- .../libs/snowballstemmer/russian_stemmer.py | 636 --- .../libs/snowballstemmer/spanish_stemmer.py | 1032 ----- .../libs/snowballstemmer/swedish_stemmer.py | 304 -- .../libs/snowballstemmer/turkish_stemmer.py | 2601 ----------- pymode/libs/wrapt/__init__.py | 19 - pymode/libs/wrapt/arguments.py | 96 - pymode/libs/wrapt/decorators.py | 512 --- pymode/libs/wrapt/importer.py | 228 - pymode/libs/wrapt/wrappers.py | 899 ---- submodules/autopep8 | 1 + submodules/mccabe | 1 + submodules/pycodestyle | 1 + submodules/pydocstyle | 1 + submodules/pyflakes | 1 + submodules/pylama | 1 + submodules/snowball_py | 1 + 160 files changed, 18429 insertions(+), 35993 deletions(-) create mode 100644 .gitmodules mode change 100644 => 120000 pymode/autopep8.py create mode 100644 pymode/libs/_markerlib/__init__.py create mode 100644 pymode/libs/_markerlib/markers.py delete mode 100644 pymode/libs/backports.functools_lru_cache-1.3-py3.5-nspkg.pth delete mode 100644 pymode/libs/backports/configparser/__init__.py delete mode 100644 pymode/libs/backports/configparser/helpers.py delete mode 100644 pymode/libs/backports/functools_lru_cache.py delete mode 100644 pymode/libs/configparser-3.5.0-py2.7-nspkg.pth delete mode 100644 pymode/libs/configparser.py create mode 100644 pymode/libs/easy_install.py delete mode 100644 pymode/libs/isort/__init__.py delete mode 100644 pymode/libs/isort/__main__.py delete mode 100644 pymode/libs/isort/hooks.py delete mode 100644 pymode/libs/isort/isort.py delete mode 100644 pymode/libs/isort/main.py delete mode 100644 pymode/libs/isort/natural.py delete mode 100644 pymode/libs/isort/pie_slice.py delete mode 100644 pymode/libs/isort/pylama_isort.py delete mode 100644 pymode/libs/isort/settings.py delete mode 100644 pymode/libs/lazy_object_proxy/__init__.py delete mode 100644 pymode/libs/lazy_object_proxy/cext.c delete mode 100644 pymode/libs/lazy_object_proxy/compat.py delete mode 100644 pymode/libs/lazy_object_proxy/simple.py delete mode 100644 pymode/libs/lazy_object_proxy/slots.py delete mode 100644 pymode/libs/lazy_object_proxy/utils.py create mode 100644 pymode/libs/logilab/__init__.py create mode 100644 pymode/libs/logilab/common/__init__.py create mode 100644 pymode/libs/logilab/common/cache.py create mode 100644 pymode/libs/logilab/common/changelog.py create mode 100644 pymode/libs/logilab/common/clcommands.py create mode 100644 pymode/libs/logilab/common/compat.py create mode 100644 pymode/libs/logilab/common/configuration.py create mode 100644 pymode/libs/logilab/common/daemon.py create mode 100644 pymode/libs/logilab/common/date.py create mode 100644 pymode/libs/logilab/common/debugger.py create mode 100644 pymode/libs/logilab/common/decorators.py create mode 100644 pymode/libs/logilab/common/deprecation.py create mode 100644 pymode/libs/logilab/common/fileutils.py create mode 100644 pymode/libs/logilab/common/graph.py create mode 100644 pymode/libs/logilab/common/interface.py create mode 100644 pymode/libs/logilab/common/logging_ext.py create mode 100644 pymode/libs/logilab/common/modutils.py create mode 100644 pymode/libs/logilab/common/optik_ext.py create mode 100644 pymode/libs/logilab/common/optparser.py create mode 100644 pymode/libs/logilab/common/proc.py create mode 100644 pymode/libs/logilab/common/pytest.py create mode 100644 pymode/libs/logilab/common/registry.py create mode 100644 pymode/libs/logilab/common/shellutils.py create mode 100644 pymode/libs/logilab/common/sphinx_ext.py create mode 100644 pymode/libs/logilab/common/sphinxutils.py create mode 100644 pymode/libs/logilab/common/table.py create mode 100644 pymode/libs/logilab/common/tasksqueue.py create mode 100644 pymode/libs/logilab/common/testlib.py create mode 100644 pymode/libs/logilab/common/textutils.py create mode 100644 pymode/libs/logilab/common/tree.py create mode 100644 pymode/libs/logilab/common/umessage.py create mode 100644 pymode/libs/logilab/common/ureports/__init__.py create mode 100644 pymode/libs/logilab/common/ureports/docbook_writer.py create mode 100644 pymode/libs/logilab/common/ureports/html_writer.py create mode 100644 pymode/libs/logilab/common/ureports/nodes.py create mode 100644 pymode/libs/logilab/common/ureports/text_writer.py create mode 100644 pymode/libs/logilab/common/urllib2ext.py create mode 100644 pymode/libs/logilab/common/vcgutils.py create mode 100644 pymode/libs/logilab/common/visitor.py create mode 100644 pymode/libs/logilab/common/xmlutils.py create mode 100644 pymode/libs/logilab_common-1.0.2-py2.7-nspkg.pth create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/DESCRIPTION.rst create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/METADATA create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/RECORD create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/WHEEL create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/metadata.json create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/namespace_packages.txt create mode 100644 pymode/libs/logilab_common-1.0.2.dist-info/top_level.txt mode change 100644 => 120000 pymode/libs/mccabe.py create mode 100644 pymode/libs/pkg_resources/__init__.py rename pymode/libs/{pyflakes/scripts => pkg_resources/_vendor}/__init__.py (100%) create mode 100644 pymode/libs/pkg_resources/_vendor/packaging/__about__.py create mode 100644 pymode/libs/pkg_resources/_vendor/packaging/__init__.py create mode 100644 pymode/libs/pkg_resources/_vendor/packaging/_compat.py create mode 100644 pymode/libs/pkg_resources/_vendor/packaging/_structures.py create mode 100644 pymode/libs/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 pymode/libs/pkg_resources/_vendor/packaging/version.py mode change 100644 => 120000 pymode/libs/pycodestyle.py create mode 120000 pymode/libs/pydocstyle delete mode 100644 pymode/libs/pydocstyle/__init__.py delete mode 100644 pymode/libs/pydocstyle/__main__.py delete mode 100644 pymode/libs/pydocstyle/checker.py delete mode 100644 pymode/libs/pydocstyle/cli.py delete mode 100644 pymode/libs/pydocstyle/config.py delete mode 100644 pymode/libs/pydocstyle/data/imperatives.txt delete mode 100644 pymode/libs/pydocstyle/data/imperatives_blacklist.txt delete mode 100644 pymode/libs/pydocstyle/parser.py delete mode 100644 pymode/libs/pydocstyle/utils.py delete mode 100644 pymode/libs/pydocstyle/violations.py delete mode 100644 pymode/libs/pydocstyle/wordlists.py create mode 120000 pymode/libs/pyflakes delete mode 100644 pymode/libs/pyflakes/__init__.py delete mode 100644 pymode/libs/pyflakes/__main__.py delete mode 100644 pymode/libs/pyflakes/api.py delete mode 100644 pymode/libs/pyflakes/checker.py delete mode 100644 pymode/libs/pyflakes/messages.py delete mode 100644 pymode/libs/pyflakes/reporter.py delete mode 100644 pymode/libs/pyflakes/scripts/pyflakes.py create mode 120000 pymode/libs/pylama delete mode 100644 pymode/libs/pylama/__init__.py delete mode 100644 pymode/libs/pylama/__main__.py delete mode 100644 pymode/libs/pylama/async.py delete mode 100644 pymode/libs/pylama/config.py delete mode 100644 pymode/libs/pylama/core.py delete mode 100644 pymode/libs/pylama/errors.py delete mode 100644 pymode/libs/pylama/hook.py delete mode 100644 pymode/libs/pylama/libs/__init__.py delete mode 100644 pymode/libs/pylama/libs/importlib.py delete mode 100644 pymode/libs/pylama/libs/inirama.py delete mode 100644 pymode/libs/pylama/lint/__init__.py delete mode 100644 pymode/libs/pylama/lint/extensions.py delete mode 100644 pymode/libs/pylama/lint/pylama_mccabe.py delete mode 100644 pymode/libs/pylama/lint/pylama_pycodestyle.py delete mode 100644 pymode/libs/pylama/lint/pylama_pydocstyle.py delete mode 100644 pymode/libs/pylama/lint/pylama_pyflakes.py delete mode 100644 pymode/libs/pylama/lint/pylama_pylint/__init__.py delete mode 100644 pymode/libs/pylama/lint/pylama_pylint/main.py delete mode 100644 pymode/libs/pylama/lint/pylama_pylint/pylint.rc delete mode 100644 pymode/libs/pylama/lint/pylama_radon.py delete mode 100644 pymode/libs/pylama/main.py delete mode 100644 pymode/libs/pylama/pytest.py create mode 120000 pymode/libs/snowballstemmer delete mode 100644 pymode/libs/snowballstemmer/__init__.py delete mode 100644 pymode/libs/snowballstemmer/among.py delete mode 100644 pymode/libs/snowballstemmer/basestemmer.py delete mode 100644 pymode/libs/snowballstemmer/danish_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/dutch_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/english_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/finnish_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/french_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/german_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/hungarian_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/italian_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/norwegian_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/porter_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/portuguese_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/romanian_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/russian_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/spanish_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/swedish_stemmer.py delete mode 100644 pymode/libs/snowballstemmer/turkish_stemmer.py delete mode 100644 pymode/libs/wrapt/__init__.py delete mode 100644 pymode/libs/wrapt/arguments.py delete mode 100644 pymode/libs/wrapt/decorators.py delete mode 100644 pymode/libs/wrapt/importer.py delete mode 100644 pymode/libs/wrapt/wrappers.py create mode 160000 submodules/autopep8 create mode 160000 submodules/mccabe create mode 160000 submodules/pycodestyle create mode 160000 submodules/pydocstyle create mode 160000 submodules/pyflakes create mode 160000 submodules/pylama create mode 160000 submodules/snowball_py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..a40c4d6c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,28 @@ +[submodule "submodules/autopep8"] + path = submodules/autopep8 + url = https://github.com/hhatto/autopep8 + ignore = dirty +[submodule "submodules/pycodestyle"] + path = submodules/pycodestyle + url = https://github.com/PyCQA/pycodestyle + ignore = dirty +[submodule "submodules/pydocstyle"] + path = submodules/pydocstyle + url = https://github.com/PyCQA/pydocstyle/ + ignore = dirty +[submodule "submodules/mccabe"] + path = submodules/mccabe + url = https://github.com/PyCQA/mccabe + ignore = dirty +[submodule "submodules/pyflakes"] + path = submodules/pyflakes + url = https://github.com/PyCQA/pyflakes + ignore = dirty +[submodule "submodules/snowball_py"] + path = submodules/snowball_py + url = https://github.com/shibukawa/snowball_py + ignore = dirty +[submodule "submodules/pylama"] + path = submodules/pylama + url = https://github.com/fmv1992/pylama + ignore = dirty diff --git a/pymode/autopep8.py b/pymode/autopep8.py deleted file mode 100644 index 62e5832f..00000000 --- a/pymode/autopep8.py +++ /dev/null @@ -1,3885 +0,0 @@ -#!/usr/bin/env python - -# Copyright (C) 2010-2011 Hideo Hattori -# Copyright (C) 2011-2013 Hideo Hattori, Steven Myint -# Copyright (C) 2013-2016 Hideo Hattori, Steven Myint, Bill Wendling -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -"""Automatically formats Python code to conform to the PEP 8 style guide. - -Fixes that only need be done once can be added by adding a function of the form -"fix_(source)" to this module. They should return the fixed source code. -These fixes are picked up by apply_global_fixes(). - -Fixes that depend on pycodestyle should be added as methods to FixPEP8. See the -class documentation for more information. - -""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -import codecs -import collections -import copy -import difflib -import fnmatch -import inspect -import io -import keyword -import locale -import os -import re -import signal -import sys -import textwrap -import token -import tokenize - -import pycodestyle - - -try: - unicode -except NameError: - unicode = str - - -__version__ = '1.3.2' - - -CR = '\r' -LF = '\n' -CRLF = '\r\n' - - -PYTHON_SHEBANG_REGEX = re.compile(r'^#!.*\bpython[23]?\b\s*$') -LAMBDA_REGEX = re.compile(r'([\w.]+)\s=\slambda\s*([\(\)\w,\s.]*):') -COMPARE_NEGATIVE_REGEX = re.compile(r'\b(not)\s+([^][)(}{]+)\s+(in|is)\s') -BARE_EXCEPT_REGEX = re.compile(r'except\s*:') -STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\s.*\):') - - -# For generating line shortening candidates. -SHORTEN_OPERATOR_GROUPS = frozenset([ - frozenset([',']), - frozenset(['%']), - frozenset([',', '(', '[', '{']), - frozenset(['%', '(', '[', '{']), - frozenset([',', '(', '[', '{', '%', '+', '-', '*', '/', '//']), - frozenset(['%', '+', '-', '*', '/', '//']), -]) - - -DEFAULT_IGNORE = 'E24,W503' -DEFAULT_INDENT_SIZE = 4 - - -# W602 is handled separately due to the need to avoid "with_traceback". -CODE_TO_2TO3 = { - 'E231': ['ws_comma'], - 'E721': ['idioms'], - 'W601': ['has_key'], - 'W603': ['ne'], - 'W604': ['repr'], - 'W690': ['apply', - 'except', - 'exitfunc', - 'numliterals', - 'operator', - 'paren', - 'reduce', - 'renames', - 'standarderror', - 'sys_exc', - 'throw', - 'tuple_params', - 'xreadlines']} - - -if sys.platform == 'win32': # pragma: no cover - DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8') -else: - DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or - os.path.expanduser('~/.config'), 'pep8') -PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8') - - -MAX_PYTHON_FILE_DETECTION_BYTES = 1024 - - -def open_with_encoding(filename, - encoding=None, mode='r', limit_byte_check=-1): - """Return opened file with a specific encoding.""" - if not encoding: - encoding = detect_encoding(filename, limit_byte_check=limit_byte_check) - - return io.open(filename, mode=mode, encoding=encoding, - newline='') # Preserve line endings - - -def detect_encoding(filename, limit_byte_check=-1): - """Return file encoding.""" - try: - with open(filename, 'rb') as input_file: - from lib2to3.pgen2 import tokenize as lib2to3_tokenize - encoding = lib2to3_tokenize.detect_encoding(input_file.readline)[0] - - with open_with_encoding(filename, encoding) as test_file: - test_file.read(limit_byte_check) - - return encoding - except (LookupError, SyntaxError, UnicodeDecodeError): - return 'latin-1' - - -def readlines_from_file(filename): - """Return contents of file.""" - with open_with_encoding(filename) as input_file: - return input_file.readlines() - - -def extended_blank_lines(logical_line, - blank_lines, - blank_before, - indent_level, - previous_logical): - """Check for missing blank lines after class declaration.""" - if previous_logical.startswith('def '): - if blank_lines and pycodestyle.DOCSTRING_REGEX.match(logical_line): - yield (0, 'E303 too many blank lines ({0})'.format(blank_lines)) - elif pycodestyle.DOCSTRING_REGEX.match(previous_logical): - # Missing blank line between class docstring and method declaration. - if ( - indent_level and - not blank_lines and - not blank_before and - logical_line.startswith(('def ')) and - '(self' in logical_line - ): - yield (0, 'E301 expected 1 blank line, found 0') - - -pycodestyle.register_check(extended_blank_lines) - - -def continued_indentation(logical_line, tokens, indent_level, indent_char, - noqa): - """Override pycodestyle's function to provide indentation information.""" - first_row = tokens[0][2][0] - nrows = 1 + tokens[-1][2][0] - first_row - if noqa or nrows == 1: - return - - # indent_next tells us whether the next block is indented. Assuming - # that it is indented by 4 spaces, then we should not allow 4-space - # indents on the final continuation line. In turn, some other - # indents are allowed to have an extra 4 spaces. - indent_next = logical_line.endswith(':') - - row = depth = 0 - valid_hangs = ( - (DEFAULT_INDENT_SIZE,) - if indent_char != '\t' else (DEFAULT_INDENT_SIZE, - 2 * DEFAULT_INDENT_SIZE) - ) - - # Remember how many brackets were opened on each line. - parens = [0] * nrows - - # Relative indents of physical lines. - rel_indent = [0] * nrows - - # For each depth, collect a list of opening rows. - open_rows = [[0]] - # For each depth, memorize the hanging indentation. - hangs = [None] - - # Visual indents. - indent_chances = {} - last_indent = tokens[0][2] - indent = [last_indent[1]] - - last_token_multiline = None - line = None - last_line = '' - last_line_begins_with_multiline = False - for token_type, text, start, end, line in tokens: - - newline = row < start[0] - first_row - if newline: - row = start[0] - first_row - newline = (not last_token_multiline and - token_type not in (tokenize.NL, tokenize.NEWLINE)) - last_line_begins_with_multiline = last_token_multiline - - if newline: - # This is the beginning of a continuation line. - last_indent = start - - # Record the initial indent. - rel_indent[row] = pycodestyle.expand_indent(line) - indent_level - - # Identify closing bracket. - close_bracket = (token_type == tokenize.OP and text in ']})') - - # Is the indent relative to an opening bracket line? - for open_row in reversed(open_rows[depth]): - hang = rel_indent[row] - rel_indent[open_row] - hanging_indent = hang in valid_hangs - if hanging_indent: - break - if hangs[depth]: - hanging_indent = (hang == hangs[depth]) - - visual_indent = (not close_bracket and hang > 0 and - indent_chances.get(start[1])) - - if close_bracket and indent[depth]: - # Closing bracket for visual indent. - if start[1] != indent[depth]: - yield (start, 'E124 {0}'.format(indent[depth])) - elif close_bracket and not hang: - pass - elif indent[depth] and start[1] < indent[depth]: - # Visual indent is broken. - yield (start, 'E128 {0}'.format(indent[depth])) - elif (hanging_indent or - (indent_next and - rel_indent[row] == 2 * DEFAULT_INDENT_SIZE)): - # Hanging indent is verified. - if close_bracket: - yield (start, 'E123 {0}'.format(indent_level + - rel_indent[open_row])) - hangs[depth] = hang - elif visual_indent is True: - # Visual indent is verified. - indent[depth] = start[1] - elif visual_indent in (text, unicode): - # Ignore token lined up with matching one from a previous line. - pass - else: - one_indented = (indent_level + rel_indent[open_row] + - DEFAULT_INDENT_SIZE) - # Indent is broken. - if hang <= 0: - error = ('E122', one_indented) - elif indent[depth]: - error = ('E127', indent[depth]) - elif not close_bracket and hangs[depth]: - error = ('E131', one_indented) - elif hang > DEFAULT_INDENT_SIZE: - error = ('E126', one_indented) - else: - hangs[depth] = hang - error = ('E121', one_indented) - - yield (start, '{0} {1}'.format(*error)) - - # Look for visual indenting. - if ( - parens[row] and - token_type not in (tokenize.NL, tokenize.COMMENT) and - not indent[depth] - ): - indent[depth] = start[1] - indent_chances[start[1]] = True - # Deal with implicit string concatenation. - elif (token_type in (tokenize.STRING, tokenize.COMMENT) or - text in ('u', 'ur', 'b', 'br')): - indent_chances[start[1]] = unicode - # Special case for the "if" statement because len("if (") is equal to - # 4. - elif not indent_chances and not row and not depth and text == 'if': - indent_chances[end[1] + 1] = True - elif text == ':' and line[end[1]:].isspace(): - open_rows[depth].append(row) - - # Keep track of bracket depth. - if token_type == tokenize.OP: - if text in '([{': - depth += 1 - indent.append(0) - hangs.append(None) - if len(open_rows) == depth: - open_rows.append([]) - open_rows[depth].append(row) - parens[row] += 1 - elif text in ')]}' and depth > 0: - # Parent indents should not be more than this one. - prev_indent = indent.pop() or last_indent[1] - hangs.pop() - for d in range(depth): - if indent[d] > prev_indent: - indent[d] = 0 - for ind in list(indent_chances): - if ind >= prev_indent: - del indent_chances[ind] - del open_rows[depth + 1:] - depth -= 1 - if depth: - indent_chances[indent[depth]] = True - for idx in range(row, -1, -1): - if parens[idx]: - parens[idx] -= 1 - break - assert len(indent) == depth + 1 - if ( - start[1] not in indent_chances and - # This is for purposes of speeding up E121 (GitHub #90). - not last_line.rstrip().endswith(',') - ): - # Allow to line up tokens. - indent_chances[start[1]] = text - - last_token_multiline = (start[0] != end[0]) - if last_token_multiline: - rel_indent[end[0] - first_row] = rel_indent[row] - - last_line = line - - if ( - indent_next and - not last_line_begins_with_multiline and - pycodestyle.expand_indent(line) == indent_level + DEFAULT_INDENT_SIZE - ): - pos = (start[0], indent[0] + 4) - desired_indent = indent_level + 2 * DEFAULT_INDENT_SIZE - if visual_indent: - yield (pos, 'E129 {0}'.format(desired_indent)) - else: - yield (pos, 'E125 {0}'.format(desired_indent)) - - -del pycodestyle._checks['logical_line'][pycodestyle.continued_indentation] -pycodestyle.register_check(continued_indentation) - - -class FixPEP8(object): - - """Fix invalid code. - - Fixer methods are prefixed "fix_". The _fix_source() method looks for these - automatically. - - The fixer method can take either one or two arguments (in addition to - self). The first argument is "result", which is the error information from - pycodestyle. The second argument, "logical", is required only for - logical-line fixes. - - The fixer method can return the list of modified lines or None. An empty - list would mean that no changes were made. None would mean that only the - line reported in the pycodestyle error was modified. Note that the modified - line numbers that are returned are indexed at 1. This typically would - correspond with the line number reported in the pycodestyle error - information. - - [fixed method list] - - e111,e114,e115,e116 - - e121,e122,e123,e124,e125,e126,e127,e128,e129 - - e201,e202,e203 - - e211 - - e221,e222,e223,e224,e225 - - e231 - - e251 - - e261,e262 - - e271,e272,e273,e274 - - e301,e302,e303,e304,e306 - - e401 - - e502 - - e701,e702,e703,e704 - - e711,e712,e713,e714 - - e722 - - e731 - - w291 - - w503 - - """ - - def __init__(self, filename, - options, - contents=None, - long_line_ignore_cache=None): - self.filename = filename - if contents is None: - self.source = readlines_from_file(filename) - else: - sio = io.StringIO(contents) - self.source = sio.readlines() - self.options = options - self.indent_word = _get_indentword(''.join(self.source)) - - self.long_line_ignore_cache = ( - set() if long_line_ignore_cache is None - else long_line_ignore_cache) - - # Many fixers are the same even though pycodestyle categorizes them - # differently. - self.fix_e115 = self.fix_e112 - self.fix_e116 = self.fix_e113 - self.fix_e121 = self._fix_reindent - self.fix_e122 = self._fix_reindent - self.fix_e123 = self._fix_reindent - self.fix_e124 = self._fix_reindent - self.fix_e126 = self._fix_reindent - self.fix_e127 = self._fix_reindent - self.fix_e128 = self._fix_reindent - self.fix_e129 = self._fix_reindent - self.fix_e202 = self.fix_e201 - self.fix_e203 = self.fix_e201 - self.fix_e211 = self.fix_e201 - self.fix_e221 = self.fix_e271 - self.fix_e222 = self.fix_e271 - self.fix_e223 = self.fix_e271 - self.fix_e226 = self.fix_e225 - self.fix_e227 = self.fix_e225 - self.fix_e228 = self.fix_e225 - self.fix_e241 = self.fix_e271 - self.fix_e242 = self.fix_e224 - self.fix_e261 = self.fix_e262 - self.fix_e272 = self.fix_e271 - self.fix_e273 = self.fix_e271 - self.fix_e274 = self.fix_e271 - self.fix_e306 = self.fix_e301 - self.fix_e501 = ( - self.fix_long_line_logically if - options and (options.aggressive >= 2 or options.experimental) else - self.fix_long_line_physically) - self.fix_e703 = self.fix_e702 - self.fix_w293 = self.fix_w291 - - def _fix_source(self, results): - try: - (logical_start, logical_end) = _find_logical(self.source) - logical_support = True - except (SyntaxError, tokenize.TokenError): # pragma: no cover - logical_support = False - - completed_lines = set() - for result in sorted(results, key=_priority_key): - if result['line'] in completed_lines: - continue - - fixed_methodname = 'fix_' + result['id'].lower() - if hasattr(self, fixed_methodname): - fix = getattr(self, fixed_methodname) - - line_index = result['line'] - 1 - original_line = self.source[line_index] - - is_logical_fix = len(_get_parameters(fix)) > 2 - if is_logical_fix: - logical = None - if logical_support: - logical = _get_logical(self.source, - result, - logical_start, - logical_end) - if logical and set(range( - logical[0][0] + 1, - logical[1][0] + 1)).intersection( - completed_lines): - continue - - modified_lines = fix(result, logical) - else: - modified_lines = fix(result) - - if modified_lines is None: - # Force logical fixes to report what they modified. - assert not is_logical_fix - - if self.source[line_index] == original_line: - modified_lines = [] - - if modified_lines: - completed_lines.update(modified_lines) - elif modified_lines == []: # Empty list means no fix - if self.options.verbose >= 2: - print( - '---> Not fixing {error} on line {line}'.format( - error=result['id'], line=result['line']), - file=sys.stderr) - else: # We assume one-line fix when None. - completed_lines.add(result['line']) - else: - if self.options.verbose >= 3: - print( - "---> '{0}' is not defined.".format(fixed_methodname), - file=sys.stderr) - - info = result['info'].strip() - print('---> {0}:{1}:{2}:{3}'.format(self.filename, - result['line'], - result['column'], - info), - file=sys.stderr) - - def fix(self): - """Return a version of the source code with PEP 8 violations fixed.""" - pep8_options = { - 'ignore': self.options.ignore, - 'select': self.options.select, - 'max_line_length': self.options.max_line_length, - } - results = _execute_pep8(pep8_options, self.source) - - if self.options.verbose: - progress = {} - for r in results: - if r['id'] not in progress: - progress[r['id']] = set() - progress[r['id']].add(r['line']) - print('---> {n} issue(s) to fix {progress}'.format( - n=len(results), progress=progress), file=sys.stderr) - - if self.options.line_range: - start, end = self.options.line_range - results = [r for r in results - if start <= r['line'] <= end] - - self._fix_source(filter_results(source=''.join(self.source), - results=results, - aggressive=self.options.aggressive)) - - if self.options.line_range: - # If number of lines has changed then change line_range. - count = sum(sline.count('\n') - for sline in self.source[start - 1:end]) - self.options.line_range[1] = start + count - 1 - - return ''.join(self.source) - - def _fix_reindent(self, result): - """Fix a badly indented line. - - This is done by adding or removing from its initial indent only. - - """ - num_indent_spaces = int(result['info'].split()[1]) - line_index = result['line'] - 1 - target = self.source[line_index] - - self.source[line_index] = ' ' * num_indent_spaces + target.lstrip() - - def fix_e112(self, result): - """Fix under-indented comments.""" - line_index = result['line'] - 1 - target = self.source[line_index] - - if not target.lstrip().startswith('#'): - # Don't screw with invalid syntax. - return [] - - self.source[line_index] = self.indent_word + target - - def fix_e113(self, result): - """Fix over-indented comments.""" - line_index = result['line'] - 1 - target = self.source[line_index] - - indent = _get_indentation(target) - stripped = target.lstrip() - - if not stripped.startswith('#'): - # Don't screw with invalid syntax. - return [] - - self.source[line_index] = indent[1:] + stripped - - def fix_e125(self, result): - """Fix indentation undistinguish from the next logical line.""" - num_indent_spaces = int(result['info'].split()[1]) - line_index = result['line'] - 1 - target = self.source[line_index] - - spaces_to_add = num_indent_spaces - len(_get_indentation(target)) - indent = len(_get_indentation(target)) - modified_lines = [] - - while len(_get_indentation(self.source[line_index])) >= indent: - self.source[line_index] = (' ' * spaces_to_add + - self.source[line_index]) - modified_lines.append(1 + line_index) # Line indexed at 1. - line_index -= 1 - - return modified_lines - - def fix_e131(self, result): - """Fix indentation undistinguish from the next logical line.""" - num_indent_spaces = int(result['info'].split()[1]) - line_index = result['line'] - 1 - target = self.source[line_index] - - spaces_to_add = num_indent_spaces - len(_get_indentation(target)) - - if spaces_to_add >= 0: - self.source[line_index] = (' ' * spaces_to_add + - self.source[line_index]) - else: - offset = abs(spaces_to_add) - self.source[line_index] = self.source[line_index][offset:] - - def fix_e201(self, result): - """Remove extraneous whitespace.""" - line_index = result['line'] - 1 - target = self.source[line_index] - offset = result['column'] - 1 - - fixed = fix_whitespace(target, - offset=offset, - replacement='') - - self.source[line_index] = fixed - - def fix_e224(self, result): - """Remove extraneous whitespace around operator.""" - target = self.source[result['line'] - 1] - offset = result['column'] - 1 - fixed = target[:offset] + target[offset:].replace('\t', ' ') - self.source[result['line'] - 1] = fixed - - def fix_e225(self, result): - """Fix missing whitespace around operator.""" - target = self.source[result['line'] - 1] - offset = result['column'] - 1 - fixed = target[:offset] + ' ' + target[offset:] - - # Only proceed if non-whitespace characters match. - # And make sure we don't break the indentation. - if ( - fixed.replace(' ', '') == target.replace(' ', '') and - _get_indentation(fixed) == _get_indentation(target) - ): - self.source[result['line'] - 1] = fixed - error_code = result.get('id', 0) - try: - ts = generate_tokens(fixed) - except tokenize.TokenError: - return - if not check_syntax(fixed.lstrip()): - return - errors = list( - pycodestyle.missing_whitespace_around_operator(fixed, ts)) - for e in reversed(errors): - if error_code != e[1].split()[0]: - continue - offset = e[0][1] - fixed = fixed[:offset] + ' ' + fixed[offset:] - self.source[result['line'] - 1] = fixed - else: - return [] - - def fix_e231(self, result): - """Add missing whitespace.""" - line_index = result['line'] - 1 - target = self.source[line_index] - offset = result['column'] - fixed = target[:offset].rstrip() + ' ' + target[offset:].lstrip() - self.source[line_index] = fixed - - def fix_e251(self, result): - """Remove whitespace around parameter '=' sign.""" - line_index = result['line'] - 1 - target = self.source[line_index] - - # This is necessary since pycodestyle sometimes reports columns that - # goes past the end of the physical line. This happens in cases like, - # foo(bar\n=None) - c = min(result['column'] - 1, - len(target) - 1) - - if target[c].strip(): - fixed = target - else: - fixed = target[:c].rstrip() + target[c:].lstrip() - - # There could be an escaped newline - # - # def foo(a=\ - # 1) - if fixed.endswith(('=\\\n', '=\\\r\n', '=\\\r')): - self.source[line_index] = fixed.rstrip('\n\r \t\\') - self.source[line_index + 1] = self.source[line_index + 1].lstrip() - return [line_index + 1, line_index + 2] # Line indexed at 1 - - self.source[result['line'] - 1] = fixed - - def fix_e262(self, result): - """Fix spacing after comment hash.""" - target = self.source[result['line'] - 1] - offset = result['column'] - - code = target[:offset].rstrip(' \t#') - comment = target[offset:].lstrip(' \t#') - - fixed = code + (' # ' + comment if comment.strip() else '\n') - - self.source[result['line'] - 1] = fixed - - def fix_e271(self, result): - """Fix extraneous whitespace around keywords.""" - line_index = result['line'] - 1 - target = self.source[line_index] - offset = result['column'] - 1 - - fixed = fix_whitespace(target, - offset=offset, - replacement=' ') - - if fixed == target: - return [] - else: - self.source[line_index] = fixed - - def fix_e301(self, result): - """Add missing blank line.""" - cr = '\n' - self.source[result['line'] - 1] = cr + self.source[result['line'] - 1] - - def fix_e302(self, result): - """Add missing 2 blank lines.""" - add_linenum = 2 - int(result['info'].split()[-1]) - cr = '\n' * add_linenum - self.source[result['line'] - 1] = cr + self.source[result['line'] - 1] - - def fix_e303(self, result): - """Remove extra blank lines.""" - delete_linenum = int(result['info'].split('(')[1].split(')')[0]) - 2 - delete_linenum = max(1, delete_linenum) - - # We need to count because pycodestyle reports an offset line number if - # there are comments. - cnt = 0 - line = result['line'] - 2 - modified_lines = [] - while cnt < delete_linenum and line >= 0: - if not self.source[line].strip(): - self.source[line] = '' - modified_lines.append(1 + line) # Line indexed at 1 - cnt += 1 - line -= 1 - - return modified_lines - - def fix_e304(self, result): - """Remove blank line following function decorator.""" - line = result['line'] - 2 - if not self.source[line].strip(): - self.source[line] = '' - - def fix_e305(self, result): - """Add missing 2 blank lines after end of function or class.""" - cr = '\n' - # check comment line - offset = result['line'] - 2 - while True: - if offset < 0: - break - line = self.source[offset].lstrip() - if not line: - break - if line[0] != '#': - break - offset -= 1 - offset += 1 - self.source[offset] = cr + self.source[offset] - - def fix_e401(self, result): - """Put imports on separate lines.""" - line_index = result['line'] - 1 - target = self.source[line_index] - offset = result['column'] - 1 - - if not target.lstrip().startswith('import'): - return [] - - indentation = re.split(pattern=r'\bimport\b', - string=target, maxsplit=1)[0] - fixed = (target[:offset].rstrip('\t ,') + '\n' + - indentation + 'import ' + target[offset:].lstrip('\t ,')) - self.source[line_index] = fixed - - def fix_long_line_logically(self, result, logical): - """Try to make lines fit within --max-line-length characters.""" - if ( - not logical or - len(logical[2]) == 1 or - self.source[result['line'] - 1].lstrip().startswith('#') - ): - return self.fix_long_line_physically(result) - - start_line_index = logical[0][0] - end_line_index = logical[1][0] - logical_lines = logical[2] - - previous_line = get_item(self.source, start_line_index - 1, default='') - next_line = get_item(self.source, end_line_index + 1, default='') - - single_line = join_logical_line(''.join(logical_lines)) - - try: - fixed = self.fix_long_line( - target=single_line, - previous_line=previous_line, - next_line=next_line, - original=''.join(logical_lines)) - except (SyntaxError, tokenize.TokenError): - return self.fix_long_line_physically(result) - - if fixed: - for line_index in range(start_line_index, end_line_index + 1): - self.source[line_index] = '' - self.source[start_line_index] = fixed - return range(start_line_index + 1, end_line_index + 1) - - return [] - - def fix_long_line_physically(self, result): - """Try to make lines fit within --max-line-length characters.""" - line_index = result['line'] - 1 - target = self.source[line_index] - - previous_line = get_item(self.source, line_index - 1, default='') - next_line = get_item(self.source, line_index + 1, default='') - - try: - fixed = self.fix_long_line( - target=target, - previous_line=previous_line, - next_line=next_line, - original=target) - except (SyntaxError, tokenize.TokenError): - return [] - - if fixed: - self.source[line_index] = fixed - return [line_index + 1] - - return [] - - def fix_long_line(self, target, previous_line, - next_line, original): - cache_entry = (target, previous_line, next_line) - if cache_entry in self.long_line_ignore_cache: - return [] - - if target.lstrip().startswith('#'): - if self.options.aggressive: - # Wrap commented lines. - return shorten_comment( - line=target, - max_line_length=self.options.max_line_length, - last_comment=not next_line.lstrip().startswith('#')) - else: - return [] - - fixed = get_fixed_long_line( - target=target, - previous_line=previous_line, - original=original, - indent_word=self.indent_word, - max_line_length=self.options.max_line_length, - aggressive=self.options.aggressive, - experimental=self.options.experimental, - verbose=self.options.verbose) - - if fixed and not code_almost_equal(original, fixed): - return fixed - - self.long_line_ignore_cache.add(cache_entry) - return None - - def fix_e502(self, result): - """Remove extraneous escape of newline.""" - (line_index, _, target) = get_index_offset_contents(result, - self.source) - self.source[line_index] = target.rstrip('\n\r \t\\') + '\n' - - def fix_e701(self, result): - """Put colon-separated compound statement on separate lines.""" - line_index = result['line'] - 1 - target = self.source[line_index] - c = result['column'] - - fixed_source = (target[:c] + '\n' + - _get_indentation(target) + self.indent_word + - target[c:].lstrip('\n\r \t\\')) - self.source[result['line'] - 1] = fixed_source - return [result['line'], result['line'] + 1] - - def fix_e702(self, result, logical): - """Put semicolon-separated compound statement on separate lines.""" - if not logical: - return [] # pragma: no cover - logical_lines = logical[2] - - # Avoid applying this when indented. - # https://docs.python.org/reference/compound_stmts.html - for line in logical_lines: - if ':' in line: - return [] - - line_index = result['line'] - 1 - target = self.source[line_index] - - if target.rstrip().endswith('\\'): - # Normalize '1; \\\n2' into '1; 2'. - self.source[line_index] = target.rstrip('\n \r\t\\') - self.source[line_index + 1] = self.source[line_index + 1].lstrip() - return [line_index + 1, line_index + 2] - - if target.rstrip().endswith(';'): - self.source[line_index] = target.rstrip('\n \r\t;') + '\n' - return [line_index + 1] - - offset = result['column'] - 1 - first = target[:offset].rstrip(';').rstrip() - second = (_get_indentation(logical_lines[0]) + - target[offset:].lstrip(';').lstrip()) - - # Find inline comment. - inline_comment = None - if target[offset:].lstrip(';').lstrip()[:2] == '# ': - inline_comment = target[offset:].lstrip(';') - - if inline_comment: - self.source[line_index] = first + inline_comment - else: - self.source[line_index] = first + '\n' + second - return [line_index + 1] - - def fix_e704(self, result): - """Fix multiple statements on one line def""" - (line_index, _, target) = get_index_offset_contents(result, - self.source) - match = STARTSWITH_DEF_REGEX.match(target) - if match: - self.source[line_index] = '{0}\n{1}{2}'.format( - match.group(0), - _get_indentation(target) + self.indent_word, - target[match.end(0):].lstrip()) - - def fix_e711(self, result): - """Fix comparison with None.""" - (line_index, offset, target) = get_index_offset_contents(result, - self.source) - - right_offset = offset + 2 - if right_offset >= len(target): - return [] - - left = target[:offset].rstrip() - center = target[offset:right_offset] - right = target[right_offset:].lstrip() - - if not right.startswith('None'): - return [] - - if center.strip() == '==': - new_center = 'is' - elif center.strip() == '!=': - new_center = 'is not' - else: - return [] - - self.source[line_index] = ' '.join([left, new_center, right]) - - def fix_e712(self, result): - """Fix (trivial case of) comparison with boolean.""" - (line_index, offset, target) = get_index_offset_contents(result, - self.source) - - # Handle very easy "not" special cases. - if re.match(r'^\s*if [\w.]+ == False:$', target): - self.source[line_index] = re.sub(r'if ([\w.]+) == False:', - r'if not \1:', target, count=1) - elif re.match(r'^\s*if [\w.]+ != True:$', target): - self.source[line_index] = re.sub(r'if ([\w.]+) != True:', - r'if not \1:', target, count=1) - else: - right_offset = offset + 2 - if right_offset >= len(target): - return [] - - left = target[:offset].rstrip() - center = target[offset:right_offset] - right = target[right_offset:].lstrip() - - # Handle simple cases only. - new_right = None - if center.strip() == '==': - if re.match(r'\bTrue\b', right): - new_right = re.sub(r'\bTrue\b *', '', right, count=1) - elif center.strip() == '!=': - if re.match(r'\bFalse\b', right): - new_right = re.sub(r'\bFalse\b *', '', right, count=1) - - if new_right is None: - return [] - - if new_right[0].isalnum(): - new_right = ' ' + new_right - - self.source[line_index] = left + new_right - - def fix_e713(self, result): - """Fix (trivial case of) non-membership check.""" - (line_index, _, target) = get_index_offset_contents(result, - self.source) - - match = COMPARE_NEGATIVE_REGEX.search(target) - if match: - if match.group(3) == 'in': - pos_start = match.start(1) - self.source[line_index] = '{0}{1} {2} {3} {4}'.format( - target[:pos_start], match.group(2), match.group(1), - match.group(3), target[match.end():]) - - def fix_e714(self, result): - """Fix object identity should be 'is not' case.""" - (line_index, _, target) = get_index_offset_contents(result, - self.source) - - match = COMPARE_NEGATIVE_REGEX.search(target) - if match: - if match.group(3) == 'is': - pos_start = match.start(1) - self.source[line_index] = '{0}{1} {2} {3} {4}'.format( - target[:pos_start], match.group(2), match.group(3), - match.group(1), target[match.end():]) - - def fix_e722(self, result): - """fix bare except""" - (line_index, _, target) = get_index_offset_contents(result, - self.source) - match = BARE_EXCEPT_REGEX.search(target) - if match: - self.source[line_index] = '{0}{1}{2}'.format( - target[:result['column'] - 1], "except BaseException:", - target[match.end():]) - - def fix_e731(self, result): - """Fix do not assign a lambda expression check.""" - (line_index, _, target) = get_index_offset_contents(result, - self.source) - match = LAMBDA_REGEX.search(target) - if match: - end = match.end() - self.source[line_index] = '{0}def {1}({2}): return {3}'.format( - target[:match.start(0)], match.group(1), match.group(2), - target[end:].lstrip()) - - def fix_w291(self, result): - """Remove trailing whitespace.""" - fixed_line = self.source[result['line'] - 1].rstrip() - self.source[result['line'] - 1] = fixed_line + '\n' - - def fix_w391(self, _): - """Remove trailing blank lines.""" - blank_count = 0 - for line in reversed(self.source): - line = line.rstrip() - if line: - break - else: - blank_count += 1 - - original_length = len(self.source) - self.source = self.source[:original_length - blank_count] - return range(1, 1 + original_length) - - def fix_w503(self, result): - (line_index, _, target) = get_index_offset_contents(result, - self.source) - one_string_token = target.split()[0] - try: - ts = generate_tokens(one_string_token) - except tokenize.TokenError: - return - if not _is_binary_operator(ts[0][0], one_string_token): - return - # find comment - comment_index = None - for i in range(5): - # NOTE: try to parse code in 5 times - if (line_index - i) < 0: - break - from_index = line_index - i - 1 - to_index = line_index + 1 - try: - ts = generate_tokens("".join(self.source[from_index:to_index])) - except Exception: - continue - newline_count = 0 - newline_index = [] - for i, t in enumerate(ts): - if t[0] in (tokenize.NEWLINE, tokenize.NL): - newline_index.append(i) - newline_count += 1 - if newline_count > 2: - tts = ts[newline_index[-3]:] - else: - tts = ts - old = None - for t in tts: - if tokenize.COMMENT == t[0]: - if old is None: - comment_index = 0 - else: - comment_index = old[3][1] - break - old = t - break - i = target.index(one_string_token) - self.source[line_index] = '{0}{1}'.format( - target[:i], target[i + len(one_string_token):]) - nl = find_newline(self.source[line_index - 1:line_index]) - before_line = self.source[line_index - 1] - bl = before_line.index(nl) - if comment_index: - self.source[line_index - 1] = '{0} {1} {2}'.format( - before_line[:comment_index], one_string_token, - before_line[comment_index + 1:]) - else: - self.source[line_index - 1] = '{0} {1}{2}'.format( - before_line[:bl], one_string_token, before_line[bl:]) - - -def get_index_offset_contents(result, source): - """Return (line_index, column_offset, line_contents).""" - line_index = result['line'] - 1 - return (line_index, - result['column'] - 1, - source[line_index]) - - -def get_fixed_long_line(target, previous_line, original, - indent_word=' ', max_line_length=79, - aggressive=False, experimental=False, verbose=False): - """Break up long line and return result. - - Do this by generating multiple reformatted candidates and then - ranking the candidates to heuristically select the best option. - - """ - indent = _get_indentation(target) - source = target[len(indent):] - assert source.lstrip() == source - assert not target.lstrip().startswith('#') - - # Check for partial multiline. - tokens = list(generate_tokens(source)) - - candidates = shorten_line( - tokens, source, indent, - indent_word, - max_line_length, - aggressive=aggressive, - experimental=experimental, - previous_line=previous_line) - - # Also sort alphabetically as a tie breaker (for determinism). - candidates = sorted( - sorted(set(candidates).union([target, original])), - key=lambda x: line_shortening_rank( - x, - indent_word, - max_line_length, - experimental=experimental)) - - if verbose >= 4: - print(('-' * 79 + '\n').join([''] + candidates + ['']), - file=wrap_output(sys.stderr, 'utf-8')) - - if candidates: - best_candidate = candidates[0] - - # Don't allow things to get longer. - if longest_line_length(best_candidate) > longest_line_length(original): - return None - - return best_candidate - - -def longest_line_length(code): - """Return length of longest line.""" - return max(len(line) for line in code.splitlines()) - - -def join_logical_line(logical_line): - """Return single line based on logical line input.""" - indentation = _get_indentation(logical_line) - - return indentation + untokenize_without_newlines( - generate_tokens(logical_line.lstrip())) + '\n' - - -def untokenize_without_newlines(tokens): - """Return source code based on tokens.""" - text = '' - last_row = 0 - last_column = -1 - - for t in tokens: - token_string = t[1] - (start_row, start_column) = t[2] - (end_row, end_column) = t[3] - - if start_row > last_row: - last_column = 0 - if ( - (start_column > last_column or token_string == '\n') and - not text.endswith(' ') - ): - text += ' ' - - if token_string != '\n': - text += token_string - - last_row = end_row - last_column = end_column - - return text.rstrip() - - -def _find_logical(source_lines): - # Make a variable which is the index of all the starts of lines. - logical_start = [] - logical_end = [] - last_newline = True - parens = 0 - for t in generate_tokens(''.join(source_lines)): - if t[0] in [tokenize.COMMENT, tokenize.DEDENT, - tokenize.INDENT, tokenize.NL, - tokenize.ENDMARKER]: - continue - if not parens and t[0] in [tokenize.NEWLINE, tokenize.SEMI]: - last_newline = True - logical_end.append((t[3][0] - 1, t[2][1])) - continue - if last_newline and not parens: - logical_start.append((t[2][0] - 1, t[2][1])) - last_newline = False - if t[0] == tokenize.OP: - if t[1] in '([{': - parens += 1 - elif t[1] in '}])': - parens -= 1 - return (logical_start, logical_end) - - -def _get_logical(source_lines, result, logical_start, logical_end): - """Return the logical line corresponding to the result. - - Assumes input is already E702-clean. - - """ - row = result['line'] - 1 - col = result['column'] - 1 - ls = None - le = None - for i in range(0, len(logical_start), 1): - assert logical_end - x = logical_end[i] - if x[0] > row or (x[0] == row and x[1] > col): - le = x - ls = logical_start[i] - break - if ls is None: - return None - original = source_lines[ls[0]:le[0] + 1] - return ls, le, original - - -def get_item(items, index, default=None): - if 0 <= index < len(items): - return items[index] - - return default - - -def reindent(source, indent_size): - """Reindent all lines.""" - reindenter = Reindenter(source) - return reindenter.run(indent_size) - - -def code_almost_equal(a, b): - """Return True if code is similar. - - Ignore whitespace when comparing specific line. - - """ - split_a = split_and_strip_non_empty_lines(a) - split_b = split_and_strip_non_empty_lines(b) - - if len(split_a) != len(split_b): - return False - - for (index, _) in enumerate(split_a): - if ''.join(split_a[index].split()) != ''.join(split_b[index].split()): - return False - - return True - - -def split_and_strip_non_empty_lines(text): - """Return lines split by newline. - - Ignore empty lines. - - """ - return [line.strip() for line in text.splitlines() if line.strip()] - - -def fix_e265(source, aggressive=False): # pylint: disable=unused-argument - """Format block comments.""" - if '#' not in source: - # Optimization. - return source - - ignored_line_numbers = multiline_string_lines( - source, - include_docstrings=True) | set(commented_out_code_lines(source)) - - fixed_lines = [] - sio = io.StringIO(source) - for (line_number, line) in enumerate(sio.readlines(), start=1): - if ( - line.lstrip().startswith('#') and - line_number not in ignored_line_numbers and - not pycodestyle.noqa(line) - ): - indentation = _get_indentation(line) - line = line.lstrip() - - # Normalize beginning if not a shebang. - if len(line) > 1: - pos = next((index for index, c in enumerate(line) - if c != '#')) - if ( - # Leave multiple spaces like '# ' alone. - (line[:pos].count('#') > 1 or line[1].isalnum()) and - # Leave stylistic outlined blocks alone. - not line.rstrip().endswith('#') - ): - line = '# ' + line.lstrip('# \t') - - fixed_lines.append(indentation + line) - else: - fixed_lines.append(line) - - return ''.join(fixed_lines) - - -def refactor(source, fixer_names, ignore=None, filename=''): - """Return refactored code using lib2to3. - - Skip if ignore string is produced in the refactored code. - - """ - from lib2to3 import pgen2 - try: - new_text = refactor_with_2to3(source, - fixer_names=fixer_names, - filename=filename) - except (pgen2.parse.ParseError, - SyntaxError, - UnicodeDecodeError, - UnicodeEncodeError): - return source - - if ignore: - if ignore in new_text and ignore not in source: - return source - - return new_text - - -def code_to_2to3(select, ignore): - fixes = set() - for code, fix in CODE_TO_2TO3.items(): - if code_match(code, select=select, ignore=ignore): - fixes |= set(fix) - return fixes - - -def fix_2to3(source, - aggressive=True, select=None, ignore=None, filename=''): - """Fix various deprecated code (via lib2to3).""" - if not aggressive: - return source - - select = select or [] - ignore = ignore or [] - - return refactor(source, - code_to_2to3(select=select, - ignore=ignore), - filename=filename) - - -def fix_w602(source, aggressive=True): - """Fix deprecated form of raising exception.""" - if not aggressive: - return source - - return refactor(source, ['raise'], - ignore='with_traceback') - - -def find_newline(source): - """Return type of newline used in source. - - Input is a list of lines. - - """ - assert not isinstance(source, unicode) - - counter = collections.defaultdict(int) - for line in source: - if line.endswith(CRLF): - counter[CRLF] += 1 - elif line.endswith(CR): - counter[CR] += 1 - elif line.endswith(LF): - counter[LF] += 1 - - return (sorted(counter, key=counter.get, reverse=True) or [LF])[0] - - -def _get_indentword(source): - """Return indentation type.""" - indent_word = ' ' # Default in case source has no indentation - try: - for t in generate_tokens(source): - if t[0] == token.INDENT: - indent_word = t[1] - break - except (SyntaxError, tokenize.TokenError): - pass - return indent_word - - -def _get_indentation(line): - """Return leading whitespace.""" - if line.strip(): - non_whitespace_index = len(line) - len(line.lstrip()) - return line[:non_whitespace_index] - - return '' - - -def get_diff_text(old, new, filename): - """Return text of unified diff between old and new.""" - newline = '\n' - diff = difflib.unified_diff( - old, new, - 'original/' + filename, - 'fixed/' + filename, - lineterm=newline) - - text = '' - for line in diff: - text += line - - # Work around missing newline (http://bugs.python.org/issue2142). - if text and not line.endswith(newline): - text += newline + r'\ No newline at end of file' + newline - - return text - - -def _priority_key(pep8_result): - """Key for sorting PEP8 results. - - Global fixes should be done first. This is important for things like - indentation. - - """ - priority = [ - # Fix multiline colon-based before semicolon based. - 'e701', - # Break multiline statements early. - 'e702', - # Things that make lines longer. - 'e225', 'e231', - # Remove extraneous whitespace before breaking lines. - 'e201', - # Shorten whitespace in comment before resorting to wrapping. - 'e262' - ] - middle_index = 10000 - lowest_priority = [ - # We need to shorten lines last since the logical fixer can get in a - # loop, which causes us to exit early. - 'e501', - 'w503' - ] - key = pep8_result['id'].lower() - try: - return priority.index(key) - except ValueError: - try: - return middle_index + lowest_priority.index(key) + 1 - except ValueError: - return middle_index - - -def shorten_line(tokens, source, indentation, indent_word, max_line_length, - aggressive=False, experimental=False, previous_line=''): - """Separate line at OPERATOR. - - Multiple candidates will be yielded. - - """ - for candidate in _shorten_line(tokens=tokens, - source=source, - indentation=indentation, - indent_word=indent_word, - aggressive=aggressive, - previous_line=previous_line): - yield candidate - - if aggressive: - for key_token_strings in SHORTEN_OPERATOR_GROUPS: - shortened = _shorten_line_at_tokens( - tokens=tokens, - source=source, - indentation=indentation, - indent_word=indent_word, - key_token_strings=key_token_strings, - aggressive=aggressive) - - if shortened is not None and shortened != source: - yield shortened - - if experimental: - for shortened in _shorten_line_at_tokens_new( - tokens=tokens, - source=source, - indentation=indentation, - max_line_length=max_line_length): - - yield shortened - - -def _shorten_line(tokens, source, indentation, indent_word, - aggressive=False, previous_line=''): - """Separate line at OPERATOR. - - The input is expected to be free of newlines except for inside multiline - strings and at the end. - - Multiple candidates will be yielded. - - """ - for (token_type, - token_string, - start_offset, - end_offset) in token_offsets(tokens): - - if ( - token_type == tokenize.COMMENT and - not is_probably_part_of_multiline(previous_line) and - not is_probably_part_of_multiline(source) and - not source[start_offset + 1:].strip().lower().startswith( - ('noqa', 'pragma:', 'pylint:')) - ): - # Move inline comments to previous line. - first = source[:start_offset] - second = source[start_offset:] - yield (indentation + second.strip() + '\n' + - indentation + first.strip() + '\n') - elif token_type == token.OP and token_string != '=': - # Don't break on '=' after keyword as this violates PEP 8. - - assert token_type != token.INDENT - - first = source[:end_offset] - - second_indent = indentation - if first.rstrip().endswith('('): - second_indent += indent_word - elif '(' in first: - second_indent += ' ' * (1 + first.find('(')) - else: - second_indent += indent_word - - second = (second_indent + source[end_offset:].lstrip()) - if ( - not second.strip() or - second.lstrip().startswith('#') - ): - continue - - # Do not begin a line with a comma - if second.lstrip().startswith(','): - continue - # Do end a line with a dot - if first.rstrip().endswith('.'): - continue - if token_string in '+-*/': - fixed = first + ' \\' + '\n' + second - else: - fixed = first + '\n' + second - - # Only fix if syntax is okay. - if check_syntax(normalize_multiline(fixed) - if aggressive else fixed): - yield indentation + fixed - - -def _is_binary_operator(token_type, text): - return ((token_type == tokenize.OP or text in ['and', 'or']) and - text not in '()[]{},:.;@=%~') - - -# A convenient way to handle tokens. -Token = collections.namedtuple('Token', ['token_type', 'token_string', - 'spos', 'epos', 'line']) - - -class ReformattedLines(object): - - """The reflowed lines of atoms. - - Each part of the line is represented as an "atom." They can be moved - around when need be to get the optimal formatting. - - """ - - ########################################################################### - # Private Classes - - class _Indent(object): - - """Represent an indentation in the atom stream.""" - - def __init__(self, indent_amt): - self._indent_amt = indent_amt - - def emit(self): - return ' ' * self._indent_amt - - @property - def size(self): - return self._indent_amt - - class _Space(object): - - """Represent a space in the atom stream.""" - - def emit(self): - return ' ' - - @property - def size(self): - return 1 - - class _LineBreak(object): - - """Represent a line break in the atom stream.""" - - def emit(self): - return '\n' - - @property - def size(self): - return 0 - - def __init__(self, max_line_length): - self._max_line_length = max_line_length - self._lines = [] - self._bracket_depth = 0 - self._prev_item = None - self._prev_prev_item = None - - def __repr__(self): - return self.emit() - - ########################################################################### - # Public Methods - - def add(self, obj, indent_amt, break_after_open_bracket): - if isinstance(obj, Atom): - self._add_item(obj, indent_amt) - return - - self._add_container(obj, indent_amt, break_after_open_bracket) - - def add_comment(self, item): - num_spaces = 2 - if len(self._lines) > 1: - if isinstance(self._lines[-1], self._Space): - num_spaces -= 1 - if len(self._lines) > 2: - if isinstance(self._lines[-2], self._Space): - num_spaces -= 1 - - while num_spaces > 0: - self._lines.append(self._Space()) - num_spaces -= 1 - self._lines.append(item) - - def add_indent(self, indent_amt): - self._lines.append(self._Indent(indent_amt)) - - def add_line_break(self, indent): - self._lines.append(self._LineBreak()) - self.add_indent(len(indent)) - - def add_line_break_at(self, index, indent_amt): - self._lines.insert(index, self._LineBreak()) - self._lines.insert(index + 1, self._Indent(indent_amt)) - - def add_space_if_needed(self, curr_text, equal=False): - if ( - not self._lines or isinstance( - self._lines[-1], (self._LineBreak, self._Indent, self._Space)) - ): - return - - prev_text = unicode(self._prev_item) - prev_prev_text = ( - unicode(self._prev_prev_item) if self._prev_prev_item else '') - - if ( - # The previous item was a keyword or identifier and the current - # item isn't an operator that doesn't require a space. - ((self._prev_item.is_keyword or self._prev_item.is_string or - self._prev_item.is_name or self._prev_item.is_number) and - (curr_text[0] not in '([{.,:}])' or - (curr_text[0] == '=' and equal))) or - - # Don't place spaces around a '.', unless it's in an 'import' - # statement. - ((prev_prev_text != 'from' and prev_text[-1] != '.' and - curr_text != 'import') and - - # Don't place a space before a colon. - curr_text[0] != ':' and - - # Don't split up ending brackets by spaces. - ((prev_text[-1] in '}])' and curr_text[0] not in '.,}])') or - - # Put a space after a colon or comma. - prev_text[-1] in ':,' or - - # Put space around '=' if asked to. - (equal and prev_text == '=') or - - # Put spaces around non-unary arithmetic operators. - ((self._prev_prev_item and - (prev_text not in '+-' and - (self._prev_prev_item.is_name or - self._prev_prev_item.is_number or - self._prev_prev_item.is_string)) and - prev_text in ('+', '-', '%', '*', '/', '//', '**', 'in'))))) - ): - self._lines.append(self._Space()) - - def previous_item(self): - """Return the previous non-whitespace item.""" - return self._prev_item - - def fits_on_current_line(self, item_extent): - return self.current_size() + item_extent <= self._max_line_length - - def current_size(self): - """The size of the current line minus the indentation.""" - size = 0 - for item in reversed(self._lines): - size += item.size - if isinstance(item, self._LineBreak): - break - - return size - - def line_empty(self): - return (self._lines and - isinstance(self._lines[-1], - (self._LineBreak, self._Indent))) - - def emit(self): - string = '' - for item in self._lines: - if isinstance(item, self._LineBreak): - string = string.rstrip() - string += item.emit() - - return string.rstrip() + '\n' - - ########################################################################### - # Private Methods - - def _add_item(self, item, indent_amt): - """Add an item to the line. - - Reflow the line to get the best formatting after the item is - inserted. The bracket depth indicates if the item is being - inserted inside of a container or not. - - """ - if self._prev_item and self._prev_item.is_string and item.is_string: - # Place consecutive string literals on separate lines. - self._lines.append(self._LineBreak()) - self._lines.append(self._Indent(indent_amt)) - - item_text = unicode(item) - if self._lines and self._bracket_depth: - # Adding the item into a container. - self._prevent_default_initializer_splitting(item, indent_amt) - - if item_text in '.,)]}': - self._split_after_delimiter(item, indent_amt) - - elif self._lines and not self.line_empty(): - # Adding the item outside of a container. - if self.fits_on_current_line(len(item_text)): - self._enforce_space(item) - - else: - # Line break for the new item. - self._lines.append(self._LineBreak()) - self._lines.append(self._Indent(indent_amt)) - - self._lines.append(item) - self._prev_item, self._prev_prev_item = item, self._prev_item - - if item_text in '([{': - self._bracket_depth += 1 - - elif item_text in '}])': - self._bracket_depth -= 1 - assert self._bracket_depth >= 0 - - def _add_container(self, container, indent_amt, break_after_open_bracket): - actual_indent = indent_amt + 1 - - if ( - unicode(self._prev_item) != '=' and - not self.line_empty() and - not self.fits_on_current_line( - container.size + self._bracket_depth + 2) - ): - - if unicode(container)[0] == '(' and self._prev_item.is_name: - # Don't split before the opening bracket of a call. - break_after_open_bracket = True - actual_indent = indent_amt + 4 - elif ( - break_after_open_bracket or - unicode(self._prev_item) not in '([{' - ): - # If the container doesn't fit on the current line and the - # current line isn't empty, place the container on the next - # line. - self._lines.append(self._LineBreak()) - self._lines.append(self._Indent(indent_amt)) - break_after_open_bracket = False - else: - actual_indent = self.current_size() + 1 - break_after_open_bracket = False - - if isinstance(container, (ListComprehension, IfExpression)): - actual_indent = indent_amt - - # Increase the continued indentation only if recursing on a - # container. - container.reflow(self, ' ' * actual_indent, - break_after_open_bracket=break_after_open_bracket) - - def _prevent_default_initializer_splitting(self, item, indent_amt): - """Prevent splitting between a default initializer. - - When there is a default initializer, it's best to keep it all on - the same line. It's nicer and more readable, even if it goes - over the maximum allowable line length. This goes back along the - current line to determine if we have a default initializer, and, - if so, to remove extraneous whitespaces and add a line - break/indent before it if needed. - - """ - if unicode(item) == '=': - # This is the assignment in the initializer. Just remove spaces for - # now. - self._delete_whitespace() - return - - if (not self._prev_item or not self._prev_prev_item or - unicode(self._prev_item) != '='): - return - - self._delete_whitespace() - prev_prev_index = self._lines.index(self._prev_prev_item) - - if ( - isinstance(self._lines[prev_prev_index - 1], self._Indent) or - self.fits_on_current_line(item.size + 1) - ): - # The default initializer is already the only item on this line. - # Don't insert a newline here. - return - - # Replace the space with a newline/indent combo. - if isinstance(self._lines[prev_prev_index - 1], self._Space): - del self._lines[prev_prev_index - 1] - - self.add_line_break_at(self._lines.index(self._prev_prev_item), - indent_amt) - - def _split_after_delimiter(self, item, indent_amt): - """Split the line only after a delimiter.""" - self._delete_whitespace() - - if self.fits_on_current_line(item.size): - return - - last_space = None - for current_item in reversed(self._lines): - if ( - last_space and - (not isinstance(current_item, Atom) or - not current_item.is_colon) - ): - break - else: - last_space = None - if isinstance(current_item, self._Space): - last_space = current_item - if isinstance(current_item, (self._LineBreak, self._Indent)): - return - - if not last_space: - return - - self.add_line_break_at(self._lines.index(last_space), indent_amt) - - def _enforce_space(self, item): - """Enforce a space in certain situations. - - There are cases where we will want a space where normally we - wouldn't put one. This just enforces the addition of a space. - - """ - if isinstance(self._lines[-1], - (self._Space, self._LineBreak, self._Indent)): - return - - if not self._prev_item: - return - - item_text = unicode(item) - prev_text = unicode(self._prev_item) - - # Prefer a space around a '.' in an import statement, and between the - # 'import' and '('. - if ( - (item_text == '.' and prev_text == 'from') or - (item_text == 'import' and prev_text == '.') or - (item_text == '(' and prev_text == 'import') - ): - self._lines.append(self._Space()) - - def _delete_whitespace(self): - """Delete all whitespace from the end of the line.""" - while isinstance(self._lines[-1], (self._Space, self._LineBreak, - self._Indent)): - del self._lines[-1] - - -class Atom(object): - - """The smallest unbreakable unit that can be reflowed.""" - - def __init__(self, atom): - self._atom = atom - - def __repr__(self): - return self._atom.token_string - - def __len__(self): - return self.size - - def reflow( - self, reflowed_lines, continued_indent, extent, - break_after_open_bracket=False, - is_list_comp_or_if_expr=False, - next_is_dot=False - ): - if self._atom.token_type == tokenize.COMMENT: - reflowed_lines.add_comment(self) - return - - total_size = extent if extent else self.size - - if self._atom.token_string not in ',:([{}])': - # Some atoms will need an extra 1-sized space token after them. - total_size += 1 - - prev_item = reflowed_lines.previous_item() - if ( - not is_list_comp_or_if_expr and - not reflowed_lines.fits_on_current_line(total_size) and - not (next_is_dot and - reflowed_lines.fits_on_current_line(self.size + 1)) and - not reflowed_lines.line_empty() and - not self.is_colon and - not (prev_item and prev_item.is_name and - unicode(self) == '(') - ): - # Start a new line if there is already something on the line and - # adding this atom would make it go over the max line length. - reflowed_lines.add_line_break(continued_indent) - else: - reflowed_lines.add_space_if_needed(unicode(self)) - - reflowed_lines.add(self, len(continued_indent), - break_after_open_bracket) - - def emit(self): - return self.__repr__() - - @property - def is_keyword(self): - return keyword.iskeyword(self._atom.token_string) - - @property - def is_string(self): - return self._atom.token_type == tokenize.STRING - - @property - def is_name(self): - return self._atom.token_type == tokenize.NAME - - @property - def is_number(self): - return self._atom.token_type == tokenize.NUMBER - - @property - def is_comma(self): - return self._atom.token_string == ',' - - @property - def is_colon(self): - return self._atom.token_string == ':' - - @property - def size(self): - return len(self._atom.token_string) - - -class Container(object): - - """Base class for all container types.""" - - def __init__(self, items): - self._items = items - - def __repr__(self): - string = '' - last_was_keyword = False - - for item in self._items: - if item.is_comma: - string += ', ' - elif item.is_colon: - string += ': ' - else: - item_string = unicode(item) - if ( - string and - (last_was_keyword or - (not string.endswith(tuple('([{,.:}]) ')) and - not item_string.startswith(tuple('([{,.:}])')))) - ): - string += ' ' - string += item_string - - last_was_keyword = item.is_keyword - return string - - def __iter__(self): - for element in self._items: - yield element - - def __getitem__(self, idx): - return self._items[idx] - - def reflow(self, reflowed_lines, continued_indent, - break_after_open_bracket=False): - last_was_container = False - for (index, item) in enumerate(self._items): - next_item = get_item(self._items, index + 1) - - if isinstance(item, Atom): - is_list_comp_or_if_expr = ( - isinstance(self, (ListComprehension, IfExpression))) - item.reflow(reflowed_lines, continued_indent, - self._get_extent(index), - is_list_comp_or_if_expr=is_list_comp_or_if_expr, - next_is_dot=(next_item and - unicode(next_item) == '.')) - if last_was_container and item.is_comma: - reflowed_lines.add_line_break(continued_indent) - last_was_container = False - else: # isinstance(item, Container) - reflowed_lines.add(item, len(continued_indent), - break_after_open_bracket) - last_was_container = not isinstance(item, (ListComprehension, - IfExpression)) - - if ( - break_after_open_bracket and index == 0 and - # Prefer to keep empty containers together instead of - # separating them. - unicode(item) == self.open_bracket and - (not next_item or unicode(next_item) != self.close_bracket) and - (len(self._items) != 3 or not isinstance(next_item, Atom)) - ): - reflowed_lines.add_line_break(continued_indent) - break_after_open_bracket = False - else: - next_next_item = get_item(self._items, index + 2) - if ( - unicode(item) not in ['.', '%', 'in'] and - next_item and not isinstance(next_item, Container) and - unicode(next_item) != ':' and - next_next_item and (not isinstance(next_next_item, Atom) or - unicode(next_item) == 'not') and - not reflowed_lines.line_empty() and - not reflowed_lines.fits_on_current_line( - self._get_extent(index + 1) + 2) - ): - reflowed_lines.add_line_break(continued_indent) - - def _get_extent(self, index): - """The extent of the full element. - - E.g., the length of a function call or keyword. - - """ - extent = 0 - prev_item = get_item(self._items, index - 1) - seen_dot = prev_item and unicode(prev_item) == '.' - while index < len(self._items): - item = get_item(self._items, index) - index += 1 - - if isinstance(item, (ListComprehension, IfExpression)): - break - - if isinstance(item, Container): - if prev_item and prev_item.is_name: - if seen_dot: - extent += 1 - else: - extent += item.size - - prev_item = item - continue - elif (unicode(item) not in ['.', '=', ':', 'not'] and - not item.is_name and not item.is_string): - break - - if unicode(item) == '.': - seen_dot = True - - extent += item.size - prev_item = item - - return extent - - @property - def is_string(self): - return False - - @property - def size(self): - return len(self.__repr__()) - - @property - def is_keyword(self): - return False - - @property - def is_name(self): - return False - - @property - def is_comma(self): - return False - - @property - def is_colon(self): - return False - - @property - def open_bracket(self): - return None - - @property - def close_bracket(self): - return None - - -class Tuple(Container): - - """A high-level representation of a tuple.""" - - @property - def open_bracket(self): - return '(' - - @property - def close_bracket(self): - return ')' - - -class List(Container): - - """A high-level representation of a list.""" - - @property - def open_bracket(self): - return '[' - - @property - def close_bracket(self): - return ']' - - -class DictOrSet(Container): - - """A high-level representation of a dictionary or set.""" - - @property - def open_bracket(self): - return '{' - - @property - def close_bracket(self): - return '}' - - -class ListComprehension(Container): - - """A high-level representation of a list comprehension.""" - - @property - def size(self): - length = 0 - for item in self._items: - if isinstance(item, IfExpression): - break - length += item.size - return length - - -class IfExpression(Container): - - """A high-level representation of an if-expression.""" - - -def _parse_container(tokens, index, for_or_if=None): - """Parse a high-level container, such as a list, tuple, etc.""" - - # Store the opening bracket. - items = [Atom(Token(*tokens[index]))] - index += 1 - - num_tokens = len(tokens) - while index < num_tokens: - tok = Token(*tokens[index]) - - if tok.token_string in ',)]}': - # First check if we're at the end of a list comprehension or - # if-expression. Don't add the ending token as part of the list - # comprehension or if-expression, because they aren't part of those - # constructs. - if for_or_if == 'for': - return (ListComprehension(items), index - 1) - - elif for_or_if == 'if': - return (IfExpression(items), index - 1) - - # We've reached the end of a container. - items.append(Atom(tok)) - - # If not, then we are at the end of a container. - if tok.token_string == ')': - # The end of a tuple. - return (Tuple(items), index) - - elif tok.token_string == ']': - # The end of a list. - return (List(items), index) - - elif tok.token_string == '}': - # The end of a dictionary or set. - return (DictOrSet(items), index) - - elif tok.token_string in '([{': - # A sub-container is being defined. - (container, index) = _parse_container(tokens, index) - items.append(container) - - elif tok.token_string == 'for': - (container, index) = _parse_container(tokens, index, 'for') - items.append(container) - - elif tok.token_string == 'if': - (container, index) = _parse_container(tokens, index, 'if') - items.append(container) - - else: - items.append(Atom(tok)) - - index += 1 - - return (None, None) - - -def _parse_tokens(tokens): - """Parse the tokens. - - This converts the tokens into a form where we can manipulate them - more easily. - - """ - - index = 0 - parsed_tokens = [] - - num_tokens = len(tokens) - while index < num_tokens: - tok = Token(*tokens[index]) - - assert tok.token_type != token.INDENT - if tok.token_type == tokenize.NEWLINE: - # There's only one newline and it's at the end. - break - - if tok.token_string in '([{': - (container, index) = _parse_container(tokens, index) - if not container: - return None - parsed_tokens.append(container) - else: - parsed_tokens.append(Atom(tok)) - - index += 1 - - return parsed_tokens - - -def _reflow_lines(parsed_tokens, indentation, max_line_length, - start_on_prefix_line): - """Reflow the lines so that it looks nice.""" - - if unicode(parsed_tokens[0]) == 'def': - # A function definition gets indented a bit more. - continued_indent = indentation + ' ' * 2 * DEFAULT_INDENT_SIZE - else: - continued_indent = indentation + ' ' * DEFAULT_INDENT_SIZE - - break_after_open_bracket = not start_on_prefix_line - - lines = ReformattedLines(max_line_length) - lines.add_indent(len(indentation.lstrip('\r\n'))) - - if not start_on_prefix_line: - # If splitting after the opening bracket will cause the first element - # to be aligned weirdly, don't try it. - first_token = get_item(parsed_tokens, 0) - second_token = get_item(parsed_tokens, 1) - - if ( - first_token and second_token and - unicode(second_token)[0] == '(' and - len(indentation) + len(first_token) + 1 == len(continued_indent) - ): - return None - - for item in parsed_tokens: - lines.add_space_if_needed(unicode(item), equal=True) - - save_continued_indent = continued_indent - if start_on_prefix_line and isinstance(item, Container): - start_on_prefix_line = False - continued_indent = ' ' * (lines.current_size() + 1) - - item.reflow(lines, continued_indent, break_after_open_bracket) - continued_indent = save_continued_indent - - return lines.emit() - - -def _shorten_line_at_tokens_new(tokens, source, indentation, - max_line_length): - """Shorten the line taking its length into account. - - The input is expected to be free of newlines except for inside - multiline strings and at the end. - - """ - # Yield the original source so to see if it's a better choice than the - # shortened candidate lines we generate here. - yield indentation + source - - parsed_tokens = _parse_tokens(tokens) - - if parsed_tokens: - # Perform two reflows. The first one starts on the same line as the - # prefix. The second starts on the line after the prefix. - fixed = _reflow_lines(parsed_tokens, indentation, max_line_length, - start_on_prefix_line=True) - if fixed and check_syntax(normalize_multiline(fixed.lstrip())): - yield fixed - - fixed = _reflow_lines(parsed_tokens, indentation, max_line_length, - start_on_prefix_line=False) - if fixed and check_syntax(normalize_multiline(fixed.lstrip())): - yield fixed - - -def _shorten_line_at_tokens(tokens, source, indentation, indent_word, - key_token_strings, aggressive): - """Separate line by breaking at tokens in key_token_strings. - - The input is expected to be free of newlines except for inside - multiline strings and at the end. - - """ - offsets = [] - for (index, _t) in enumerate(token_offsets(tokens)): - (token_type, - token_string, - start_offset, - end_offset) = _t - - assert token_type != token.INDENT - - if token_string in key_token_strings: - # Do not break in containers with zero or one items. - unwanted_next_token = { - '(': ')', - '[': ']', - '{': '}'}.get(token_string) - if unwanted_next_token: - if ( - get_item(tokens, - index + 1, - default=[None, None])[1] == unwanted_next_token or - get_item(tokens, - index + 2, - default=[None, None])[1] == unwanted_next_token - ): - continue - - if ( - index > 2 and token_string == '(' and - tokens[index - 1][1] in ',(%[' - ): - # Don't split after a tuple start, or before a tuple start if - # the tuple is in a list. - continue - - if end_offset < len(source) - 1: - # Don't split right before newline. - offsets.append(end_offset) - else: - # Break at adjacent strings. These were probably meant to be on - # separate lines in the first place. - previous_token = get_item(tokens, index - 1) - if ( - token_type == tokenize.STRING and - previous_token and previous_token[0] == tokenize.STRING - ): - offsets.append(start_offset) - - current_indent = None - fixed = None - for line in split_at_offsets(source, offsets): - if fixed: - fixed += '\n' + current_indent + line - - for symbol in '([{': - if line.endswith(symbol): - current_indent += indent_word - else: - # First line. - fixed = line - assert not current_indent - current_indent = indent_word - - assert fixed is not None - - if check_syntax(normalize_multiline(fixed) - if aggressive > 1 else fixed): - return indentation + fixed - - return None - - -def token_offsets(tokens): - """Yield tokens and offsets.""" - end_offset = 0 - previous_end_row = 0 - previous_end_column = 0 - for t in tokens: - token_type = t[0] - token_string = t[1] - (start_row, start_column) = t[2] - (end_row, end_column) = t[3] - - # Account for the whitespace between tokens. - end_offset += start_column - if previous_end_row == start_row: - end_offset -= previous_end_column - - # Record the start offset of the token. - start_offset = end_offset - - # Account for the length of the token itself. - end_offset += len(token_string) - - yield (token_type, - token_string, - start_offset, - end_offset) - - previous_end_row = end_row - previous_end_column = end_column - - -def normalize_multiline(line): - """Normalize multiline-related code that will cause syntax error. - - This is for purposes of checking syntax. - - """ - if line.startswith('def ') and line.rstrip().endswith(':'): - return line + ' pass' - elif line.startswith('return '): - return 'def _(): ' + line - elif line.startswith('@'): - return line + 'def _(): pass' - elif line.startswith('class '): - return line + ' pass' - elif line.startswith(('if ', 'elif ', 'for ', 'while ')): - return line + ' pass' - - return line - - -def fix_whitespace(line, offset, replacement): - """Replace whitespace at offset and return fixed line.""" - # Replace escaped newlines too - left = line[:offset].rstrip('\n\r \t\\') - right = line[offset:].lstrip('\n\r \t\\') - if right.startswith('#'): - return line - - return left + replacement + right - - -def _execute_pep8(pep8_options, source): - """Execute pycodestyle via python method calls.""" - class QuietReport(pycodestyle.BaseReport): - - """Version of checker that does not print.""" - - def __init__(self, options): - super(QuietReport, self).__init__(options) - self.__full_error_results = [] - - def error(self, line_number, offset, text, check): - """Collect errors.""" - code = super(QuietReport, self).error(line_number, - offset, - text, - check) - if code: - self.__full_error_results.append( - {'id': code, - 'line': line_number, - 'column': offset + 1, - 'info': text}) - - def full_error_results(self): - """Return error results in detail. - - Results are in the form of a list of dictionaries. Each - dictionary contains 'id', 'line', 'column', and 'info'. - - """ - return self.__full_error_results - - checker = pycodestyle.Checker('', lines=source, reporter=QuietReport, - **pep8_options) - checker.check_all() - return checker.report.full_error_results() - - -def _remove_leading_and_normalize(line): - return line.lstrip().rstrip(CR + LF) + '\n' - - -class Reindenter(object): - - """Reindents badly-indented code to uniformly use four-space indentation. - - Released to the public domain, by Tim Peters, 03 October 2000. - - """ - - def __init__(self, input_text): - sio = io.StringIO(input_text) - source_lines = sio.readlines() - - self.string_content_line_numbers = multiline_string_lines(input_text) - - # File lines, rstripped & tab-expanded. Dummy at start is so - # that we can use tokenize's 1-based line numbering easily. - # Note that a line is all-blank iff it is a newline. - self.lines = [] - for line_number, line in enumerate(source_lines, start=1): - # Do not modify if inside a multiline string. - if line_number in self.string_content_line_numbers: - self.lines.append(line) - else: - # Only expand leading tabs. - self.lines.append(_get_indentation(line).expandtabs() + - _remove_leading_and_normalize(line)) - - self.lines.insert(0, None) - self.index = 1 # index into self.lines of next line - self.input_text = input_text - - def run(self, indent_size=DEFAULT_INDENT_SIZE): - """Fix indentation and return modified line numbers. - - Line numbers are indexed at 1. - - """ - if indent_size < 1: - return self.input_text - - try: - stats = _reindent_stats(tokenize.generate_tokens(self.getline)) - except (SyntaxError, tokenize.TokenError): - return self.input_text - # Remove trailing empty lines. - lines = self.lines - # Sentinel. - stats.append((len(lines), 0)) - # Map count of leading spaces to # we want. - have2want = {} - # Program after transformation. - after = [] - # Copy over initial empty lines -- there's nothing to do until - # we see a line with *something* on it. - i = stats[0][0] - after.extend(lines[1:i]) - for i in range(len(stats) - 1): - thisstmt, thislevel = stats[i] - nextstmt = stats[i + 1][0] - have = _leading_space_count(lines[thisstmt]) - want = thislevel * indent_size - if want < 0: - # A comment line. - if have: - # An indented comment line. If we saw the same - # indentation before, reuse what it most recently - # mapped to. - want = have2want.get(have, -1) - if want < 0: - # Then it probably belongs to the next real stmt. - for j in range(i + 1, len(stats) - 1): - jline, jlevel = stats[j] - if jlevel >= 0: - if have == _leading_space_count(lines[jline]): - want = jlevel * indent_size - break - if want < 0: # Maybe it's a hanging - # comment like this one, - # in which case we should shift it like its base - # line got shifted. - for j in range(i - 1, -1, -1): - jline, jlevel = stats[j] - if jlevel >= 0: - want = (have + _leading_space_count( - after[jline - 1]) - - _leading_space_count(lines[jline])) - break - if want < 0: - # Still no luck -- leave it alone. - want = have - else: - want = 0 - assert want >= 0 - have2want[have] = want - diff = want - have - if diff == 0 or have == 0: - after.extend(lines[thisstmt:nextstmt]) - else: - for line_number, line in enumerate(lines[thisstmt:nextstmt], - start=thisstmt): - if line_number in self.string_content_line_numbers: - after.append(line) - elif diff > 0: - if line == '\n': - after.append(line) - else: - after.append(' ' * diff + line) - else: - remove = min(_leading_space_count(line), -diff) - after.append(line[remove:]) - - return ''.join(after) - - def getline(self): - """Line-getter for tokenize.""" - if self.index >= len(self.lines): - line = '' - else: - line = self.lines[self.index] - self.index += 1 - return line - - -def _reindent_stats(tokens): - """Return list of (lineno, indentlevel) pairs. - - One for each stmt and comment line. indentlevel is -1 for comment - lines, as a signal that tokenize doesn't know what to do about them; - indeed, they're our headache! - - """ - find_stmt = 1 # Next token begins a fresh stmt? - level = 0 # Current indent level. - stats = [] - - for t in tokens: - token_type = t[0] - sline = t[2][0] - line = t[4] - - if token_type == tokenize.NEWLINE: - # A program statement, or ENDMARKER, will eventually follow, - # after some (possibly empty) run of tokens of the form - # (NL | COMMENT)* (INDENT | DEDENT+)? - find_stmt = 1 - - elif token_type == tokenize.INDENT: - find_stmt = 1 - level += 1 - - elif token_type == tokenize.DEDENT: - find_stmt = 1 - level -= 1 - - elif token_type == tokenize.COMMENT: - if find_stmt: - stats.append((sline, -1)) - # But we're still looking for a new stmt, so leave - # find_stmt alone. - - elif token_type == tokenize.NL: - pass - - elif find_stmt: - # This is the first "real token" following a NEWLINE, so it - # must be the first token of the next program statement, or an - # ENDMARKER. - find_stmt = 0 - if line: # Not endmarker. - stats.append((sline, level)) - - return stats - - -def _leading_space_count(line): - """Return number of leading spaces in line.""" - i = 0 - while i < len(line) and line[i] == ' ': - i += 1 - return i - - -def refactor_with_2to3(source_text, fixer_names, filename=''): - """Use lib2to3 to refactor the source. - - Return the refactored source code. - - """ - from lib2to3.refactor import RefactoringTool - fixers = ['lib2to3.fixes.fix_' + name for name in fixer_names] - tool = RefactoringTool(fixer_names=fixers, explicit=fixers) - - from lib2to3.pgen2 import tokenize as lib2to3_tokenize - try: - # The name parameter is necessary particularly for the "import" fixer. - return unicode(tool.refactor_string(source_text, name=filename)) - except lib2to3_tokenize.TokenError: - return source_text - - -def check_syntax(code): - """Return True if syntax is okay.""" - try: - return compile(code, '', 'exec') - except (SyntaxError, TypeError, UnicodeDecodeError): - return False - - -def filter_results(source, results, aggressive): - """Filter out spurious reports from pycodestyle. - - If aggressive is True, we allow possibly unsafe fixes (E711, E712). - - """ - non_docstring_string_line_numbers = multiline_string_lines( - source, include_docstrings=False) - all_string_line_numbers = multiline_string_lines( - source, include_docstrings=True) - - commented_out_code_line_numbers = commented_out_code_lines(source) - - has_e901 = any(result['id'].lower() == 'e901' for result in results) - - for r in results: - issue_id = r['id'].lower() - - if r['line'] in non_docstring_string_line_numbers: - if issue_id.startswith(('e1', 'e501', 'w191')): - continue - - if r['line'] in all_string_line_numbers: - if issue_id in ['e501']: - continue - - # We must offset by 1 for lines that contain the trailing contents of - # multiline strings. - if not aggressive and (r['line'] + 1) in all_string_line_numbers: - # Do not modify multiline strings in non-aggressive mode. Remove - # trailing whitespace could break doctests. - if issue_id.startswith(('w29', 'w39')): - continue - - if aggressive <= 0: - if issue_id.startswith(('e711', 'e72', 'w6')): - continue - - if aggressive <= 1: - if issue_id.startswith(('e712', 'e713', 'e714', 'w5')): - continue - - if aggressive <= 2: - if issue_id.startswith(('e704', 'w5')): - continue - - if r['line'] in commented_out_code_line_numbers: - if issue_id.startswith(('e26', 'e501')): - continue - - # Do not touch indentation if there is a token error caused by - # incomplete multi-line statement. Otherwise, we risk screwing up the - # indentation. - if has_e901: - if issue_id.startswith(('e1', 'e7')): - continue - - yield r - - -def multiline_string_lines(source, include_docstrings=False): - """Return line numbers that are within multiline strings. - - The line numbers are indexed at 1. - - Docstrings are ignored. - - """ - line_numbers = set() - previous_token_type = '' - try: - for t in generate_tokens(source): - token_type = t[0] - start_row = t[2][0] - end_row = t[3][0] - - if token_type == tokenize.STRING and start_row != end_row: - if ( - include_docstrings or - previous_token_type != tokenize.INDENT - ): - # We increment by one since we want the contents of the - # string. - line_numbers |= set(range(1 + start_row, 1 + end_row)) - - previous_token_type = token_type - except (SyntaxError, tokenize.TokenError): - pass - - return line_numbers - - -def commented_out_code_lines(source): - """Return line numbers of comments that are likely code. - - Commented-out code is bad practice, but modifying it just adds even - more clutter. - - """ - line_numbers = [] - try: - for t in generate_tokens(source): - token_type = t[0] - token_string = t[1] - start_row = t[2][0] - line = t[4] - - # Ignore inline comments. - if not line.lstrip().startswith('#'): - continue - - if token_type == tokenize.COMMENT: - stripped_line = token_string.lstrip('#').strip() - if ( - ' ' in stripped_line and - '#' not in stripped_line and - check_syntax(stripped_line) - ): - line_numbers.append(start_row) - except (SyntaxError, tokenize.TokenError): - pass - - return line_numbers - - -def shorten_comment(line, max_line_length, last_comment=False): - """Return trimmed or split long comment line. - - If there are no comments immediately following it, do a text wrap. - Doing this wrapping on all comments in general would lead to jagged - comment text. - - """ - assert len(line) > max_line_length - line = line.rstrip() - - # PEP 8 recommends 72 characters for comment text. - indentation = _get_indentation(line) + '# ' - max_line_length = min(max_line_length, - len(indentation) + 72) - - MIN_CHARACTER_REPEAT = 5 - if ( - len(line) - len(line.rstrip(line[-1])) >= MIN_CHARACTER_REPEAT and - not line[-1].isalnum() - ): - # Trim comments that end with things like --------- - return line[:max_line_length] + '\n' - elif last_comment and re.match(r'\s*#+\s*\w+', line): - split_lines = textwrap.wrap(line.lstrip(' \t#'), - initial_indent=indentation, - subsequent_indent=indentation, - width=max_line_length, - break_long_words=False, - break_on_hyphens=False) - return '\n'.join(split_lines) + '\n' - - return line + '\n' - - -def normalize_line_endings(lines, newline): - """Return fixed line endings. - - All lines will be modified to use the most common line ending. - - """ - return [line.rstrip('\n\r') + newline for line in lines] - - -def mutual_startswith(a, b): - return b.startswith(a) or a.startswith(b) - - -def code_match(code, select, ignore): - if ignore: - assert not isinstance(ignore, unicode) - for ignored_code in [c.strip() for c in ignore]: - if mutual_startswith(code.lower(), ignored_code.lower()): - return False - - if select: - assert not isinstance(select, unicode) - for selected_code in [c.strip() for c in select]: - if mutual_startswith(code.lower(), selected_code.lower()): - return True - return False - - return True - - -def fix_code(source, options=None, encoding=None, apply_config=False): - """Return fixed source code. - - "encoding" will be used to decode "source" if it is a byte string. - - """ - options = _get_options(options, apply_config) - - if not isinstance(source, unicode): - source = source.decode(encoding or get_encoding()) - - sio = io.StringIO(source) - return fix_lines(sio.readlines(), options=options) - - -def _get_options(raw_options, apply_config): - """Return parsed options.""" - if not raw_options: - return parse_args([''], apply_config=apply_config) - - if isinstance(raw_options, dict): - options = parse_args([''], apply_config=apply_config) - for name, value in raw_options.items(): - if not hasattr(options, name): - raise ValueError("No such option '{}'".format(name)) - - # Check for very basic type errors. - expected_type = type(getattr(options, name)) - if not isinstance(expected_type, (str, unicode)): - if isinstance(value, (str, unicode)): - raise ValueError( - "Option '{}' should not be a string".format(name)) - setattr(options, name, value) - else: - options = raw_options - - return options - - -def fix_lines(source_lines, options, filename=''): - """Return fixed source code.""" - # Transform everything to line feed. Then change them back to original - # before returning fixed source code. - original_newline = find_newline(source_lines) - tmp_source = ''.join(normalize_line_endings(source_lines, '\n')) - - # Keep a history to break out of cycles. - previous_hashes = set() - - if options.line_range: - # Disable "apply_local_fixes()" for now due to issue #175. - fixed_source = tmp_source - else: - # Apply global fixes only once (for efficiency). - fixed_source = apply_global_fixes(tmp_source, - options, - filename=filename) - - passes = 0 - long_line_ignore_cache = set() - while hash(fixed_source) not in previous_hashes: - if options.pep8_passes >= 0 and passes > options.pep8_passes: - break - passes += 1 - - previous_hashes.add(hash(fixed_source)) - - tmp_source = copy.copy(fixed_source) - - fix = FixPEP8( - filename, - options, - contents=tmp_source, - long_line_ignore_cache=long_line_ignore_cache) - - fixed_source = fix.fix() - - sio = io.StringIO(fixed_source) - return ''.join(normalize_line_endings(sio.readlines(), original_newline)) - - -def fix_file(filename, options=None, output=None, apply_config=False): - if not options: - options = parse_args([filename], apply_config=apply_config) - - original_source = readlines_from_file(filename) - - fixed_source = original_source - - if options.in_place or output: - encoding = detect_encoding(filename) - - if output: - output = LineEndingWrapper(wrap_output(output, encoding=encoding)) - - fixed_source = fix_lines(fixed_source, options, filename=filename) - - if options.diff: - new = io.StringIO(fixed_source) - new = new.readlines() - diff = get_diff_text(original_source, new, filename) - if output: - output.write(diff) - output.flush() - else: - return diff - elif options.in_place: - fp = open_with_encoding(filename, encoding=encoding, mode='w') - fp.write(fixed_source) - fp.close() - else: - if output: - output.write(fixed_source) - output.flush() - else: - return fixed_source - - -def global_fixes(): - """Yield multiple (code, function) tuples.""" - for function in list(globals().values()): - if inspect.isfunction(function): - arguments = _get_parameters(function) - if arguments[:1] != ['source']: - continue - - code = extract_code_from_function(function) - if code: - yield (code, function) - - -def _get_parameters(function): - # pylint: disable=deprecated-method - if sys.version_info >= (3, 3): - # We need to match "getargspec()", which includes "self" as the first - # value for methods. - # https://bugs.python.org/issue17481#msg209469 - if inspect.ismethod(function): - function = function.__func__ - - return list(inspect.signature(function).parameters) - else: - return inspect.getargspec(function)[0] - - -def apply_global_fixes(source, options, where='global', filename=''): - """Run global fixes on source code. - - These are fixes that only need be done once (unlike those in - FixPEP8, which are dependent on pycodestyle). - - """ - if any(code_match(code, select=options.select, ignore=options.ignore) - for code in ['E101', 'E111']): - source = reindent(source, - indent_size=options.indent_size) - - for (code, function) in global_fixes(): - if code_match(code, select=options.select, ignore=options.ignore): - if options.verbose: - print('---> Applying {0} fix for {1}'.format(where, - code.upper()), - file=sys.stderr) - source = function(source, - aggressive=options.aggressive) - - source = fix_2to3(source, - aggressive=options.aggressive, - select=options.select, - ignore=options.ignore, - filename=filename) - - return source - - -def extract_code_from_function(function): - """Return code handled by function.""" - if not function.__name__.startswith('fix_'): - return None - - code = re.sub('^fix_', '', function.__name__) - if not code: - return None - - try: - int(code[1:]) - except ValueError: - return None - - return code - - -def _get_package_version(): - packages = ["pycodestyle: {0}".format(pycodestyle.__version__)] - return ", ".join(packages) - - -def create_parser(): - """Return command-line parser.""" - # Do import locally to be friendly to those who use autopep8 as a library - # and are supporting Python 2.6. - import argparse - - parser = argparse.ArgumentParser(description=docstring_summary(__doc__), - prog='autopep8') - parser.add_argument('--version', action='version', - version='%(prog)s {0} ({1})'.format( - __version__, _get_package_version())) - parser.add_argument('-v', '--verbose', action='count', - default=0, - help='print verbose messages; ' - 'multiple -v result in more verbose messages') - parser.add_argument('-d', '--diff', action='store_true', - help='print the diff for the fixed source') - parser.add_argument('-i', '--in-place', action='store_true', - help='make changes to files in place') - parser.add_argument('--global-config', metavar='filename', - default=DEFAULT_CONFIG, - help='path to a global pep8 config file; if this file ' - 'does not exist then this is ignored ' - '(default: {0})'.format(DEFAULT_CONFIG)) - parser.add_argument('--ignore-local-config', action='store_true', - help="don't look for and apply local config files; " - 'if not passed, defaults are updated with any ' - "config files in the project's root directory") - parser.add_argument('-r', '--recursive', action='store_true', - help='run recursively over directories; ' - 'must be used with --in-place or --diff') - parser.add_argument('-j', '--jobs', type=int, metavar='n', default=1, - help='number of parallel jobs; ' - 'match CPU count if value is less than 1') - parser.add_argument('-p', '--pep8-passes', metavar='n', - default=-1, type=int, - help='maximum number of additional pep8 passes ' - '(default: infinite)') - parser.add_argument('-a', '--aggressive', action='count', default=0, - help='enable non-whitespace changes; ' - 'multiple -a result in more aggressive changes') - parser.add_argument('--experimental', action='store_true', - help='enable experimental fixes') - parser.add_argument('--exclude', metavar='globs', - help='exclude file/directory names that match these ' - 'comma-separated globs') - parser.add_argument('--list-fixes', action='store_true', - help='list codes for fixes; ' - 'used by --ignore and --select') - parser.add_argument('--ignore', metavar='errors', default='', - help='do not fix these errors/warnings ' - '(default: {0})'.format(DEFAULT_IGNORE)) - parser.add_argument('--select', metavar='errors', default='', - help='fix only these errors/warnings (e.g. E4,W)') - parser.add_argument('--max-line-length', metavar='n', default=79, type=int, - help='set maximum allowed line length ' - '(default: %(default)s)') - parser.add_argument('--line-range', '--range', metavar='line', - default=None, type=int, nargs=2, - help='only fix errors found within this inclusive ' - 'range of line numbers (e.g. 1 99); ' - 'line numbers are indexed at 1') - parser.add_argument('--indent-size', default=DEFAULT_INDENT_SIZE, - type=int, help=argparse.SUPPRESS) - parser.add_argument('files', nargs='*', - help="files to format or '-' for standard in") - - return parser - - -def parse_args(arguments, apply_config=False): - """Parse command-line options.""" - parser = create_parser() - args = parser.parse_args(arguments) - - if not args.files and not args.list_fixes: - parser.error('incorrect number of arguments') - - args.files = [decode_filename(name) for name in args.files] - - if apply_config: - parser = read_config(args, parser) - args = parser.parse_args(arguments) - args.files = [decode_filename(name) for name in args.files] - - if '-' in args.files: - if len(args.files) > 1: - parser.error('cannot mix stdin and regular files') - - if args.diff: - parser.error('--diff cannot be used with standard input') - - if args.in_place: - parser.error('--in-place cannot be used with standard input') - - if args.recursive: - parser.error('--recursive cannot be used with standard input') - - if len(args.files) > 1 and not (args.in_place or args.diff): - parser.error('autopep8 only takes one filename as argument ' - 'unless the "--in-place" or "--diff" args are ' - 'used') - - if args.recursive and not (args.in_place or args.diff): - parser.error('--recursive must be used with --in-place or --diff') - - if args.in_place and args.diff: - parser.error('--in-place and --diff are mutually exclusive') - - if args.max_line_length <= 0: - parser.error('--max-line-length must be greater than 0') - - if args.select: - args.select = _split_comma_separated(args.select) - - if args.ignore: - args.ignore = _split_comma_separated(args.ignore) - elif not args.select: - if args.aggressive: - # Enable everything by default if aggressive. - args.select = set(['E', 'W']) - else: - args.ignore = _split_comma_separated(DEFAULT_IGNORE) - - if args.exclude: - args.exclude = _split_comma_separated(args.exclude) - else: - args.exclude = set([]) - - if args.jobs < 1: - # Do not import multiprocessing globally in case it is not supported - # on the platform. - import multiprocessing - args.jobs = multiprocessing.cpu_count() - - if args.jobs > 1 and not args.in_place: - parser.error('parallel jobs requires --in-place') - - if args.line_range: - if args.line_range[0] <= 0: - parser.error('--range must be positive numbers') - if args.line_range[0] > args.line_range[1]: - parser.error('First value of --range should be less than or equal ' - 'to the second') - - return args - - -def read_config(args, parser): - """Read both user configuration and local configuration.""" - try: - from configparser import ConfigParser as SafeConfigParser - from configparser import Error - except ImportError: - from ConfigParser import SafeConfigParser - from ConfigParser import Error - - config = SafeConfigParser() - - try: - config.read(args.global_config) - - if not args.ignore_local_config: - parent = tail = args.files and os.path.abspath( - os.path.commonprefix(args.files)) - while tail: - if config.read([os.path.join(parent, fn) - for fn in PROJECT_CONFIG]): - break - (parent, tail) = os.path.split(parent) - - defaults = dict() - option_list = dict([(o.dest, o.type or type(o.default)) - for o in parser._actions]) - - for section in ['pep8', 'pycodestyle']: - if not config.has_section(section): - continue - for (k, _) in config.items(section): - norm_opt = k.lstrip('-').replace('-', '_') - opt_type = option_list[norm_opt] - if opt_type is int: - value = config.getint(section, k) - elif opt_type is bool: - value = config.getboolean(section, k) - else: - value = config.get(section, k) - defaults[norm_opt] = value - - parser.set_defaults(**defaults) - except Error: - # Ignore for now. - pass - - return parser - - -def _split_comma_separated(string): - """Return a set of strings.""" - return set(text.strip() for text in string.split(',') if text.strip()) - - -def decode_filename(filename): - """Return Unicode filename.""" - if isinstance(filename, unicode): - return filename - - return filename.decode(sys.getfilesystemencoding()) - - -def supported_fixes(): - """Yield pep8 error codes that autopep8 fixes. - - Each item we yield is a tuple of the code followed by its - description. - - """ - yield ('E101', docstring_summary(reindent.__doc__)) - - instance = FixPEP8(filename=None, options=None, contents='') - for attribute in dir(instance): - code = re.match('fix_([ew][0-9][0-9][0-9])', attribute) - if code: - yield ( - code.group(1).upper(), - re.sub(r'\s+', ' ', - docstring_summary(getattr(instance, attribute).__doc__)) - ) - - for (code, function) in sorted(global_fixes()): - yield (code.upper() + (4 - len(code)) * ' ', - re.sub(r'\s+', ' ', docstring_summary(function.__doc__))) - - for code in sorted(CODE_TO_2TO3): - yield (code.upper() + (4 - len(code)) * ' ', - re.sub(r'\s+', ' ', docstring_summary(fix_2to3.__doc__))) - - -def docstring_summary(docstring): - """Return summary of docstring.""" - return docstring.split('\n')[0] if docstring else '' - - -def line_shortening_rank(candidate, indent_word, max_line_length, - experimental=False): - """Return rank of candidate. - - This is for sorting candidates. - - """ - if not candidate.strip(): - return 0 - - rank = 0 - lines = candidate.rstrip().split('\n') - - offset = 0 - if ( - not lines[0].lstrip().startswith('#') and - lines[0].rstrip()[-1] not in '([{' - ): - for (opening, closing) in ('()', '[]', '{}'): - # Don't penalize empty containers that aren't split up. Things like - # this "foo(\n )" aren't particularly good. - opening_loc = lines[0].find(opening) - closing_loc = lines[0].find(closing) - if opening_loc >= 0: - if closing_loc < 0 or closing_loc != opening_loc + 1: - offset = max(offset, 1 + opening_loc) - - current_longest = max(offset + len(x.strip()) for x in lines) - - rank += 4 * max(0, current_longest - max_line_length) - - rank += len(lines) - - # Too much variation in line length is ugly. - rank += 2 * standard_deviation(len(line) for line in lines) - - bad_staring_symbol = { - '(': ')', - '[': ']', - '{': '}'}.get(lines[0][-1]) - - if len(lines) > 1: - if ( - bad_staring_symbol and - lines[1].lstrip().startswith(bad_staring_symbol) - ): - rank += 20 - - for lineno, current_line in enumerate(lines): - current_line = current_line.strip() - - if current_line.startswith('#'): - continue - - for bad_start in ['.', '%', '+', '-', '/']: - if current_line.startswith(bad_start): - rank += 100 - - # Do not tolerate operators on their own line. - if current_line == bad_start: - rank += 1000 - - if ( - current_line.endswith(('.', '%', '+', '-', '/')) and - "': " in current_line - ): - rank += 1000 - - if current_line.endswith(('(', '[', '{', '.')): - # Avoid lonely opening. They result in longer lines. - if len(current_line) <= len(indent_word): - rank += 100 - - # Avoid the ugliness of ", (\n". - if ( - current_line.endswith('(') and - current_line[:-1].rstrip().endswith(',') - ): - rank += 100 - - # Avoid the ugliness of "something[\n" and something[index][\n. - if ( - current_line.endswith('[') and - len(current_line) > 1 and - (current_line[-2].isalnum() or current_line[-2] in ']') - ): - rank += 300 - - # Also avoid the ugliness of "foo.\nbar" - if current_line.endswith('.'): - rank += 100 - - if has_arithmetic_operator(current_line): - rank += 100 - - # Avoid breaking at unary operators. - if re.match(r'.*[(\[{]\s*[\-\+~]$', current_line.rstrip('\\ ')): - rank += 1000 - - if re.match(r'.*lambda\s*\*$', current_line.rstrip('\\ ')): - rank += 1000 - - if current_line.endswith(('%', '(', '[', '{')): - rank -= 20 - - # Try to break list comprehensions at the "for". - if current_line.startswith('for '): - rank -= 50 - - if current_line.endswith('\\'): - # If a line ends in \-newline, it may be part of a - # multiline string. In that case, we would like to know - # how long that line is without the \-newline. If it's - # longer than the maximum, or has comments, then we assume - # that the \-newline is an okay candidate and only - # penalize it a bit. - total_len = len(current_line) - lineno += 1 - while lineno < len(lines): - total_len += len(lines[lineno]) - - if lines[lineno].lstrip().startswith('#'): - total_len = max_line_length - break - - if not lines[lineno].endswith('\\'): - break - - lineno += 1 - - if total_len < max_line_length: - rank += 10 - else: - rank += 100 if experimental else 1 - - # Prefer breaking at commas rather than colon. - if ',' in current_line and current_line.endswith(':'): - rank += 10 - - # Avoid splitting dictionaries between key and value. - if current_line.endswith(':'): - rank += 100 - - rank += 10 * count_unbalanced_brackets(current_line) - - return max(0, rank) - - -def standard_deviation(numbers): - """Return standard devation.""" - numbers = list(numbers) - if not numbers: - return 0 - mean = sum(numbers) / len(numbers) - return (sum((n - mean) ** 2 for n in numbers) / - len(numbers)) ** .5 - - -def has_arithmetic_operator(line): - """Return True if line contains any arithmetic operators.""" - for operator in pycodestyle.ARITHMETIC_OP: - if operator in line: - return True - - return False - - -def count_unbalanced_brackets(line): - """Return number of unmatched open/close brackets.""" - count = 0 - for opening, closing in ['()', '[]', '{}']: - count += abs(line.count(opening) - line.count(closing)) - - return count - - -def split_at_offsets(line, offsets): - """Split line at offsets. - - Return list of strings. - - """ - result = [] - - previous_offset = 0 - current_offset = 0 - for current_offset in sorted(offsets): - if current_offset < len(line) and previous_offset != current_offset: - result.append(line[previous_offset:current_offset].strip()) - previous_offset = current_offset - - result.append(line[current_offset:]) - - return result - - -class LineEndingWrapper(object): - - r"""Replace line endings to work with sys.stdout. - - It seems that sys.stdout expects only '\n' as the line ending, no matter - the platform. Otherwise, we get repeated line endings. - - """ - - def __init__(self, output): - self.__output = output - - def write(self, s): - self.__output.write(s.replace('\r\n', '\n').replace('\r', '\n')) - - def flush(self): - self.__output.flush() - - -def match_file(filename, exclude): - """Return True if file is okay for modifying/recursing.""" - base_name = os.path.basename(filename) - - if base_name.startswith('.'): - return False - - for pattern in exclude: - if fnmatch.fnmatch(base_name, pattern): - return False - if fnmatch.fnmatch(filename, pattern): - return False - - if not os.path.isdir(filename) and not is_python_file(filename): - return False - - return True - - -def find_files(filenames, recursive, exclude): - """Yield filenames.""" - while filenames: - name = filenames.pop(0) - if recursive and os.path.isdir(name): - for root, directories, children in os.walk(name): - filenames += [os.path.join(root, f) for f in children - if match_file(os.path.join(root, f), - exclude)] - directories[:] = [d for d in directories - if match_file(os.path.join(root, d), - exclude)] - else: - yield name - - -def _fix_file(parameters): - """Helper function for optionally running fix_file() in parallel.""" - if parameters[1].verbose: - print('[file:{0}]'.format(parameters[0]), file=sys.stderr) - try: - fix_file(*parameters) - except IOError as error: - print(unicode(error), file=sys.stderr) - - -def fix_multiple_files(filenames, options, output=None): - """Fix list of files. - - Optionally fix files recursively. - - """ - filenames = find_files(filenames, options.recursive, options.exclude) - if options.jobs > 1: - import multiprocessing - pool = multiprocessing.Pool(options.jobs) - pool.map(_fix_file, - [(name, options) for name in filenames]) - else: - for name in filenames: - _fix_file((name, options, output)) - - -def is_python_file(filename): - """Return True if filename is Python file.""" - if filename.endswith('.py'): - return True - - try: - with open_with_encoding( - filename, - limit_byte_check=MAX_PYTHON_FILE_DETECTION_BYTES) as f: - text = f.read(MAX_PYTHON_FILE_DETECTION_BYTES) - if not text: - return False - first_line = text.splitlines()[0] - except (IOError, IndexError): - return False - - if not PYTHON_SHEBANG_REGEX.match(first_line): - return False - - return True - - -def is_probably_part_of_multiline(line): - """Return True if line is likely part of a multiline string. - - When multiline strings are involved, pep8 reports the error as being - at the start of the multiline string, which doesn't work for us. - - """ - return ( - '"""' in line or - "'''" in line or - line.rstrip().endswith('\\') - ) - - -def wrap_output(output, encoding): - """Return output with specified encoding.""" - return codecs.getwriter(encoding)(output.buffer - if hasattr(output, 'buffer') - else output) - - -def get_encoding(): - """Return preferred encoding.""" - return locale.getpreferredencoding() or sys.getdefaultencoding() - - -def main(argv=None, apply_config=True): - """Command-line entry.""" - if argv is None: - argv = sys.argv - - try: - # Exit on broken pipe. - signal.signal(signal.SIGPIPE, signal.SIG_DFL) - except AttributeError: # pragma: no cover - # SIGPIPE is not available on Windows. - pass - - try: - args = parse_args(argv[1:], apply_config=apply_config) - - if args.list_fixes: - for code, description in sorted(supported_fixes()): - print('{code} - {description}'.format( - code=code, description=description)) - return 0 - - if args.files == ['-']: - assert not args.in_place - - encoding = sys.stdin.encoding or get_encoding() - - # LineEndingWrapper is unnecessary here due to the symmetry between - # standard in and standard out. - wrap_output(sys.stdout, encoding=encoding).write( - fix_code(sys.stdin.read(), args, encoding=encoding)) - else: - if args.in_place or args.diff: - args.files = list(set(args.files)) - else: - assert len(args.files) == 1 - assert not args.recursive - - fix_multiple_files(args.files, args, sys.stdout) - except KeyboardInterrupt: - return 1 # pragma: no cover - - -class CachedTokenizer(object): - - """A one-element cache around tokenize.generate_tokens(). - - Original code written by Ned Batchelder, in coverage.py. - - """ - - def __init__(self): - self.last_text = None - self.last_tokens = None - - def generate_tokens(self, text): - """A stand-in for tokenize.generate_tokens().""" - if text != self.last_text: - string_io = io.StringIO(text) - self.last_tokens = list( - tokenize.generate_tokens(string_io.readline) - ) - self.last_text = text - return self.last_tokens - - -_cached_tokenizer = CachedTokenizer() -generate_tokens = _cached_tokenizer.generate_tokens - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/pymode/autopep8.py b/pymode/autopep8.py new file mode 120000 index 00000000..0a26e017 --- /dev/null +++ b/pymode/autopep8.py @@ -0,0 +1 @@ +../submodules/autopep8/autopep8.py \ No newline at end of file diff --git a/pymode/libs/_markerlib/__init__.py b/pymode/libs/_markerlib/__init__.py new file mode 100644 index 00000000..e2b237b1 --- /dev/null +++ b/pymode/libs/_markerlib/__init__.py @@ -0,0 +1,16 @@ +try: + import ast + from _markerlib.markers import default_environment, compile, interpret +except ImportError: + if 'ast' in globals(): + raise + def default_environment(): + return {} + def compile(marker): + def marker_fn(environment=None, override=None): + # 'empty markers are True' heuristic won't install extra deps. + return not marker.strip() + marker_fn.__doc__ = marker + return marker_fn + def interpret(marker, environment=None, override=None): + return compile(marker)() diff --git a/pymode/libs/_markerlib/markers.py b/pymode/libs/_markerlib/markers.py new file mode 100644 index 00000000..fa837061 --- /dev/null +++ b/pymode/libs/_markerlib/markers.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +"""Interpret PEP 345 environment markers. + +EXPR [in|==|!=|not in] EXPR [or|and] ... + +where EXPR belongs to any of those: + + python_version = '%s.%s' % (sys.version_info[0], sys.version_info[1]) + python_full_version = sys.version.split()[0] + os.name = os.name + sys.platform = sys.platform + platform.version = platform.version() + platform.machine = platform.machine() + platform.python_implementation = platform.python_implementation() + a free string, like '2.6', or 'win32' +""" + +__all__ = ['default_environment', 'compile', 'interpret'] + +import ast +import os +import platform +import sys +import weakref + +_builtin_compile = compile + +try: + from platform import python_implementation +except ImportError: + if os.name == "java": + # Jython 2.5 has ast module, but not platform.python_implementation() function. + def python_implementation(): + return "Jython" + else: + raise + + +# restricted set of variables +_VARS = {'sys.platform': sys.platform, + 'python_version': '%s.%s' % sys.version_info[:2], + # FIXME parsing sys.platform is not reliable, but there is no other + # way to get e.g. 2.7.2+, and the PEP is defined with sys.version + 'python_full_version': sys.version.split(' ', 1)[0], + 'os.name': os.name, + 'platform.version': platform.version(), + 'platform.machine': platform.machine(), + 'platform.python_implementation': python_implementation(), + 'extra': None # wheel extension + } + +for var in list(_VARS.keys()): + if '.' in var: + _VARS[var.replace('.', '_')] = _VARS[var] + +def default_environment(): + """Return copy of default PEP 385 globals dictionary.""" + return dict(_VARS) + +class ASTWhitelist(ast.NodeTransformer): + def __init__(self, statement): + self.statement = statement # for error messages + + ALLOWED = (ast.Compare, ast.BoolOp, ast.Attribute, ast.Name, ast.Load, ast.Str) + # Bool operations + ALLOWED += (ast.And, ast.Or) + # Comparison operations + ALLOWED += (ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq, ast.NotIn) + + def visit(self, node): + """Ensure statement only contains allowed nodes.""" + if not isinstance(node, self.ALLOWED): + raise SyntaxError('Not allowed in environment markers.\n%s\n%s' % + (self.statement, + (' ' * node.col_offset) + '^')) + return ast.NodeTransformer.visit(self, node) + + def visit_Attribute(self, node): + """Flatten one level of attribute access.""" + new_node = ast.Name("%s.%s" % (node.value.id, node.attr), node.ctx) + return ast.copy_location(new_node, node) + +def parse_marker(marker): + tree = ast.parse(marker, mode='eval') + new_tree = ASTWhitelist(marker).generic_visit(tree) + return new_tree + +def compile_marker(parsed_marker): + return _builtin_compile(parsed_marker, '', 'eval', + dont_inherit=True) + +_cache = weakref.WeakValueDictionary() + +def compile(marker): + """Return compiled marker as a function accepting an environment dict.""" + try: + return _cache[marker] + except KeyError: + pass + if not marker.strip(): + def marker_fn(environment=None, override=None): + """""" + return True + else: + compiled_marker = compile_marker(parse_marker(marker)) + def marker_fn(environment=None, override=None): + """override updates environment""" + if override is None: + override = {} + if environment is None: + environment = default_environment() + environment.update(override) + return eval(compiled_marker, environment) + marker_fn.__doc__ = marker + _cache[marker] = marker_fn + return _cache[marker] + +def interpret(marker, environment=None): + return compile(marker)(environment) diff --git a/pymode/libs/backports.functools_lru_cache-1.3-py3.5-nspkg.pth b/pymode/libs/backports.functools_lru_cache-1.3-py3.5-nspkg.pth deleted file mode 100644 index 0b1f79dd..00000000 --- a/pymode/libs/backports.functools_lru_cache-1.3-py3.5-nspkg.pth +++ /dev/null @@ -1 +0,0 @@ -import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('backports',));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('backports', types.ModuleType('backports'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) diff --git a/pymode/libs/backports/configparser/__init__.py b/pymode/libs/backports/configparser/__init__.py deleted file mode 100644 index 06d7a085..00000000 --- a/pymode/libs/backports/configparser/__init__.py +++ /dev/null @@ -1,1390 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Configuration file parser. - -A configuration file consists of sections, lead by a "[section]" header, -and followed by "name: value" entries, with continuations and such in -the style of RFC 822. - -Intrinsic defaults can be specified by passing them into the -ConfigParser constructor as a dictionary. - -class: - -ConfigParser -- responsible for parsing a list of - configuration files, and managing the parsed database. - - methods: - - __init__(defaults=None, dict_type=_default_dict, allow_no_value=False, - delimiters=('=', ':'), comment_prefixes=('#', ';'), - inline_comment_prefixes=None, strict=True, - empty_lines_in_values=True, default_section='DEFAULT', - interpolation=, converters=): - Create the parser. When `defaults' is given, it is initialized into the - dictionary or intrinsic defaults. The keys must be strings, the values - must be appropriate for %()s string interpolation. - - When `dict_type' is given, it will be used to create the dictionary - objects for the list of sections, for the options within a section, and - for the default values. - - When `delimiters' is given, it will be used as the set of substrings - that divide keys from values. - - When `comment_prefixes' is given, it will be used as the set of - substrings that prefix comments in empty lines. Comments can be - indented. - - When `inline_comment_prefixes' is given, it will be used as the set of - substrings that prefix comments in non-empty lines. - - When `strict` is True, the parser won't allow for any section or option - duplicates while reading from a single source (file, string or - dictionary). Default is True. - - When `empty_lines_in_values' is False (default: True), each empty line - marks the end of an option. Otherwise, internal empty lines of - a multiline option are kept as part of the value. - - When `allow_no_value' is True (default: False), options without - values are accepted; the value presented for these is None. - - sections() - Return all the configuration section names, sans DEFAULT. - - has_section(section) - Return whether the given section exists. - - has_option(section, option) - Return whether the given option exists in the given section. - - options(section) - Return list of configuration options for the named section. - - read(filenames, encoding=None) - Read and parse the list of named configuration files, given by - name. A single filename is also allowed. Non-existing files - are ignored. Return list of successfully read files. - - read_file(f, filename=None) - Read and parse one configuration file, given as a file object. - The filename defaults to f.name; it is only used in error - messages (if f has no `name' attribute, the string `' is used). - - read_string(string) - Read configuration from a given string. - - read_dict(dictionary) - Read configuration from a dictionary. Keys are section names, - values are dictionaries with keys and values that should be present - in the section. If the used dictionary type preserves order, sections - and their keys will be added in order. Values are automatically - converted to strings. - - get(section, option, raw=False, vars=None, fallback=_UNSET) - Return a string value for the named option. All % interpolations are - expanded in the return values, based on the defaults passed into the - constructor and the DEFAULT section. Additional substitutions may be - provided using the `vars' argument, which must be a dictionary whose - contents override any pre-existing defaults. If `option' is a key in - `vars', the value from `vars' is used. - - getint(section, options, raw=False, vars=None, fallback=_UNSET) - Like get(), but convert value to an integer. - - getfloat(section, options, raw=False, vars=None, fallback=_UNSET) - Like get(), but convert value to a float. - - getboolean(section, options, raw=False, vars=None, fallback=_UNSET) - Like get(), but convert value to a boolean (currently case - insensitively defined as 0, false, no, off for False, and 1, true, - yes, on for True). Returns False or True. - - items(section=_UNSET, raw=False, vars=None) - If section is given, return a list of tuples with (name, value) for - each option in the section. Otherwise, return a list of tuples with - (section_name, section_proxy) for each section, including DEFAULTSECT. - - remove_section(section) - Remove the given file section and all its options. - - remove_option(section, option) - Remove the given option from the given section. - - set(section, option, value) - Set the given option. - - write(fp, space_around_delimiters=True) - Write the configuration state in .ini format. If - `space_around_delimiters' is True (the default), delimiters - between keys and values are surrounded by spaces. -""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -from collections import MutableMapping -import functools -import io -import itertools -import re -import sys -import warnings - -from backports.configparser.helpers import OrderedDict as _default_dict -from backports.configparser.helpers import ChainMap as _ChainMap -from backports.configparser.helpers import from_none, open, str, PY2 - -__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError", - "NoOptionError", "InterpolationError", "InterpolationDepthError", - "InterpolationMissingOptionError", "InterpolationSyntaxError", - "ParsingError", "MissingSectionHeaderError", - "ConfigParser", "SafeConfigParser", "RawConfigParser", - "Interpolation", "BasicInterpolation", "ExtendedInterpolation", - "LegacyInterpolation", "SectionProxy", "ConverterMapping", - "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"] - -DEFAULTSECT = "DEFAULT" - -MAX_INTERPOLATION_DEPTH = 10 - - -# exception classes -class Error(Exception): - """Base class for ConfigParser exceptions.""" - - def __init__(self, msg=''): - self.message = msg - Exception.__init__(self, msg) - - def __repr__(self): - return self.message - - __str__ = __repr__ - - -class NoSectionError(Error): - """Raised when no section matches a requested option.""" - - def __init__(self, section): - Error.__init__(self, 'No section: %r' % (section,)) - self.section = section - self.args = (section, ) - - -class DuplicateSectionError(Error): - """Raised when a section is repeated in an input source. - - Possible repetitions that raise this exception are: multiple creation - using the API or in strict parsers when a section is found more than once - in a single input file, string or dictionary. - """ - - def __init__(self, section, source=None, lineno=None): - msg = [repr(section), " already exists"] - if source is not None: - message = ["While reading from ", repr(source)] - if lineno is not None: - message.append(" [line {0:2d}]".format(lineno)) - message.append(": section ") - message.extend(msg) - msg = message - else: - msg.insert(0, "Section ") - Error.__init__(self, "".join(msg)) - self.section = section - self.source = source - self.lineno = lineno - self.args = (section, source, lineno) - - -class DuplicateOptionError(Error): - """Raised by strict parsers when an option is repeated in an input source. - - Current implementation raises this exception only when an option is found - more than once in a single file, string or dictionary. - """ - - def __init__(self, section, option, source=None, lineno=None): - msg = [repr(option), " in section ", repr(section), - " already exists"] - if source is not None: - message = ["While reading from ", repr(source)] - if lineno is not None: - message.append(" [line {0:2d}]".format(lineno)) - message.append(": option ") - message.extend(msg) - msg = message - else: - msg.insert(0, "Option ") - Error.__init__(self, "".join(msg)) - self.section = section - self.option = option - self.source = source - self.lineno = lineno - self.args = (section, option, source, lineno) - - -class NoOptionError(Error): - """A requested option was not found.""" - - def __init__(self, option, section): - Error.__init__(self, "No option %r in section: %r" % - (option, section)) - self.option = option - self.section = section - self.args = (option, section) - - -class InterpolationError(Error): - """Base class for interpolation-related exceptions.""" - - def __init__(self, option, section, msg): - Error.__init__(self, msg) - self.option = option - self.section = section - self.args = (option, section, msg) - - -class InterpolationMissingOptionError(InterpolationError): - """A string substitution required a setting which was not available.""" - - def __init__(self, option, section, rawval, reference): - msg = ("Bad value substitution: option {0!r} in section {1!r} contains " - "an interpolation key {2!r} which is not a valid option name. " - "Raw value: {3!r}".format(option, section, reference, rawval)) - InterpolationError.__init__(self, option, section, msg) - self.reference = reference - self.args = (option, section, rawval, reference) - - -class InterpolationSyntaxError(InterpolationError): - """Raised when the source text contains invalid syntax. - - Current implementation raises this exception when the source text into - which substitutions are made does not conform to the required syntax. - """ - - -class InterpolationDepthError(InterpolationError): - """Raised when substitutions are nested too deeply.""" - - def __init__(self, option, section, rawval): - msg = ("Recursion limit exceeded in value substitution: option {0!r} " - "in section {1!r} contains an interpolation key which " - "cannot be substituted in {2} steps. Raw value: {3!r}" - "".format(option, section, MAX_INTERPOLATION_DEPTH, - rawval)) - InterpolationError.__init__(self, option, section, msg) - self.args = (option, section, rawval) - - -class ParsingError(Error): - """Raised when a configuration file does not follow legal syntax.""" - - def __init__(self, source=None, filename=None): - # Exactly one of `source'/`filename' arguments has to be given. - # `filename' kept for compatibility. - if filename and source: - raise ValueError("Cannot specify both `filename' and `source'. " - "Use `source'.") - elif not filename and not source: - raise ValueError("Required argument `source' not given.") - elif filename: - source = filename - Error.__init__(self, 'Source contains parsing errors: %r' % source) - self.source = source - self.errors = [] - self.args = (source, ) - - @property - def filename(self): - """Deprecated, use `source'.""" - warnings.warn( - "The 'filename' attribute will be removed in future versions. " - "Use 'source' instead.", - DeprecationWarning, stacklevel=2 - ) - return self.source - - @filename.setter - def filename(self, value): - """Deprecated, user `source'.""" - warnings.warn( - "The 'filename' attribute will be removed in future versions. " - "Use 'source' instead.", - DeprecationWarning, stacklevel=2 - ) - self.source = value - - def append(self, lineno, line): - self.errors.append((lineno, line)) - self.message += '\n\t[line %2d]: %s' % (lineno, line) - - -class MissingSectionHeaderError(ParsingError): - """Raised when a key-value pair is found before any section header.""" - - def __init__(self, filename, lineno, line): - Error.__init__( - self, - 'File contains no section headers.\nfile: %r, line: %d\n%r' % - (filename, lineno, line)) - self.source = filename - self.lineno = lineno - self.line = line - self.args = (filename, lineno, line) - - -# Used in parser getters to indicate the default behaviour when a specific -# option is not found it to raise an exception. Created to enable `None' as -# a valid fallback value. -_UNSET = object() - - -class Interpolation(object): - """Dummy interpolation that passes the value through with no changes.""" - - def before_get(self, parser, section, option, value, defaults): - return value - - def before_set(self, parser, section, option, value): - return value - - def before_read(self, parser, section, option, value): - return value - - def before_write(self, parser, section, option, value): - return value - - -class BasicInterpolation(Interpolation): - """Interpolation as implemented in the classic ConfigParser. - - The option values can contain format strings which refer to other values in - the same section, or values in the special default section. - - For example: - - something: %(dir)s/whatever - - would resolve the "%(dir)s" to the value of dir. All reference - expansions are done late, on demand. If a user needs to use a bare % in - a configuration file, she can escape it by writing %%. Other % usage - is considered a user error and raises `InterpolationSyntaxError'.""" - - _KEYCRE = re.compile(r"%\(([^)]+)\)s") - - def before_get(self, parser, section, option, value, defaults): - L = [] - self._interpolate_some(parser, option, L, value, section, defaults, 1) - return ''.join(L) - - def before_set(self, parser, section, option, value): - tmp_value = value.replace('%%', '') # escaped percent signs - tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax - if '%' in tmp_value: - raise ValueError("invalid interpolation syntax in %r at " - "position %d" % (value, tmp_value.find('%'))) - return value - - def _interpolate_some(self, parser, option, accum, rest, section, map, - depth): - rawval = parser.get(section, option, raw=True, fallback=rest) - if depth > MAX_INTERPOLATION_DEPTH: - raise InterpolationDepthError(option, section, rawval) - while rest: - p = rest.find("%") - if p < 0: - accum.append(rest) - return - if p > 0: - accum.append(rest[:p]) - rest = rest[p:] - # p is no longer used - c = rest[1:2] - if c == "%": - accum.append("%") - rest = rest[2:] - elif c == "(": - m = self._KEYCRE.match(rest) - if m is None: - raise InterpolationSyntaxError(option, section, - "bad interpolation variable reference %r" % rest) - var = parser.optionxform(m.group(1)) - rest = rest[m.end():] - try: - v = map[var] - except KeyError: - raise from_none(InterpolationMissingOptionError( - option, section, rawval, var)) - if "%" in v: - self._interpolate_some(parser, option, accum, v, - section, map, depth + 1) - else: - accum.append(v) - else: - raise InterpolationSyntaxError( - option, section, - "'%%' must be followed by '%%' or '(', " - "found: %r" % (rest,)) - - -class ExtendedInterpolation(Interpolation): - """Advanced variant of interpolation, supports the syntax used by - `zc.buildout'. Enables interpolation between sections.""" - - _KEYCRE = re.compile(r"\$\{([^}]+)\}") - - def before_get(self, parser, section, option, value, defaults): - L = [] - self._interpolate_some(parser, option, L, value, section, defaults, 1) - return ''.join(L) - - def before_set(self, parser, section, option, value): - tmp_value = value.replace('$$', '') # escaped dollar signs - tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax - if '$' in tmp_value: - raise ValueError("invalid interpolation syntax in %r at " - "position %d" % (value, tmp_value.find('$'))) - return value - - def _interpolate_some(self, parser, option, accum, rest, section, map, - depth): - rawval = parser.get(section, option, raw=True, fallback=rest) - if depth > MAX_INTERPOLATION_DEPTH: - raise InterpolationDepthError(option, section, rawval) - while rest: - p = rest.find("$") - if p < 0: - accum.append(rest) - return - if p > 0: - accum.append(rest[:p]) - rest = rest[p:] - # p is no longer used - c = rest[1:2] - if c == "$": - accum.append("$") - rest = rest[2:] - elif c == "{": - m = self._KEYCRE.match(rest) - if m is None: - raise InterpolationSyntaxError(option, section, - "bad interpolation variable reference %r" % rest) - path = m.group(1).split(':') - rest = rest[m.end():] - sect = section - opt = option - try: - if len(path) == 1: - opt = parser.optionxform(path[0]) - v = map[opt] - elif len(path) == 2: - sect = path[0] - opt = parser.optionxform(path[1]) - v = parser.get(sect, opt, raw=True) - else: - raise InterpolationSyntaxError( - option, section, - "More than one ':' found: %r" % (rest,)) - except (KeyError, NoSectionError, NoOptionError): - raise from_none(InterpolationMissingOptionError( - option, section, rawval, ":".join(path))) - if "$" in v: - self._interpolate_some(parser, opt, accum, v, sect, - dict(parser.items(sect, raw=True)), - depth + 1) - else: - accum.append(v) - else: - raise InterpolationSyntaxError( - option, section, - "'$' must be followed by '$' or '{', " - "found: %r" % (rest,)) - - -class LegacyInterpolation(Interpolation): - """Deprecated interpolation used in old versions of ConfigParser. - Use BasicInterpolation or ExtendedInterpolation instead.""" - - _KEYCRE = re.compile(r"%\(([^)]*)\)s|.") - - def before_get(self, parser, section, option, value, vars): - rawval = value - depth = MAX_INTERPOLATION_DEPTH - while depth: # Loop through this until it's done - depth -= 1 - if value and "%(" in value: - replace = functools.partial(self._interpolation_replace, - parser=parser) - value = self._KEYCRE.sub(replace, value) - try: - value = value % vars - except KeyError as e: - raise from_none(InterpolationMissingOptionError( - option, section, rawval, e.args[0])) - else: - break - if value and "%(" in value: - raise InterpolationDepthError(option, section, rawval) - return value - - def before_set(self, parser, section, option, value): - return value - - @staticmethod - def _interpolation_replace(match, parser): - s = match.group(1) - if s is None: - return match.group() - else: - return "%%(%s)s" % parser.optionxform(s) - - -class RawConfigParser(MutableMapping): - """ConfigParser that does not do interpolation.""" - - # Regular expressions for parsing section headers and options - _SECT_TMPL = r""" - \[ # [ - (?P
[^]]+) # very permissive! - \] # ] - """ - _OPT_TMPL = r""" - (?P