Updated plugins. Switched to Ack as standard search tool (much better than grep/vimgrep)
This commit is contained in:
parent
e62adb8084
commit
8265dca5d5
76 changed files with 3855 additions and 143 deletions
|
@ -259,7 +259,7 @@ function! s:goyo_off()
|
||||||
for [k, v] in items(goyo_revert)
|
for [k, v] in items(goyo_revert)
|
||||||
execute printf("let &%s = %s", k, string(v))
|
execute printf("let &%s = %s", k, string(v))
|
||||||
endfor
|
endfor
|
||||||
execute 'colo '. g:colors_name
|
execute 'colo '. get(g:, 'colors_name', 'default')
|
||||||
|
|
||||||
if goyo_disabled_gitgutter
|
if goyo_disabled_gitgutter
|
||||||
silent! GitGutterEnable
|
silent! GitGutterEnable
|
||||||
|
@ -267,7 +267,7 @@ function! s:goyo_off()
|
||||||
|
|
||||||
if goyo_disabled_airline && !exists("#airline")
|
if goyo_disabled_airline && !exists("#airline")
|
||||||
AirlineToggle
|
AirlineToggle
|
||||||
AirlineRefresh
|
silent! AirlineRefresh
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if goyo_disabled_powerline && !exists("#PowerlineMain")
|
if goyo_disabled_powerline && !exists("#PowerlineMain")
|
||||||
|
|
1
sources_non_forked/pyflakes-pathogen/.gitignore
vendored
Normal file
1
sources_non_forked/pyflakes-pathogen/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.pyc
|
11
sources_non_forked/pyflakes-pathogen/README.rst
Normal file
11
sources_non_forked/pyflakes-pathogen/README.rst
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Pyflakes
|
||||||
|
==========
|
||||||
|
|
||||||
|
This is just a manual dump of the vim pyflakes plugin from:
|
||||||
|
http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
|
||||||
|
The purpose is to try to make this compatible with pathogen plugin. So creating
|
||||||
|
the dir structure and hopefully this means we can just keep the norm and git
|
||||||
|
clone the repo into the bundle directory and things will load up magically.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
pyflakes-vim
|
||||||
|
============
|
||||||
|
|
||||||
|
A Vim plugin for checking Python code on the fly.
|
||||||
|
|
||||||
|
PyFlakes catches common Python errors like mistyping a variable name or
|
||||||
|
accessing a local before it is bound, and also gives warnings for things like
|
||||||
|
unused imports.
|
||||||
|
|
||||||
|
pyflakes-vim uses the output from PyFlakes to highlight errors in your code.
|
||||||
|
To locate errors quickly, use quickfix_ commands like :cc.
|
||||||
|
|
||||||
|
Make sure to check vim.org_ for the latest updates.
|
||||||
|
|
||||||
|
.. _pyflakes.vim: http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
|
||||||
|
|
||||||
|
Quick Installation
|
||||||
|
------------------
|
||||||
|
|
||||||
|
1. Make sure your ``.vimrc`` has::
|
||||||
|
|
||||||
|
filetype on " enables filetype detection
|
||||||
|
filetype plugin on " enables filetype specific plugins
|
||||||
|
|
||||||
|
2. Download the latest release_.
|
||||||
|
|
||||||
|
3. Unzip ``pyflakes.vim`` and the ``pyflakes`` directory into
|
||||||
|
``~/.vim/ftplugin/python`` (or somewhere similar on your
|
||||||
|
`runtime path`_ that will be sourced for Python files).
|
||||||
|
|
||||||
|
.. _release: http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
.. _runtime path: http://vimdoc.sourceforge.net/htmldoc/options.html#'runtimepath'
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
If you downloaded this from vim.org_, then just drop the contents of the zip
|
||||||
|
file into ``~/.vim/ftplugin/python``.
|
||||||
|
|
||||||
|
Otherwise, if you're running "from source," you'll need PyFlakes on your
|
||||||
|
PYTHONPATH somewhere. I recommend getting my PyFlakes_ fork, which retains
|
||||||
|
column number information and has therfore has more specific error locations.
|
||||||
|
|
||||||
|
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
.. _PyFlakes: http://github.com/kevinw/pyflakes
|
||||||
|
|
||||||
|
Hacking
|
||||||
|
-------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
git clone git://github.com/kevinw/pyflakes-vim.git
|
||||||
|
cd pyflakes-vim
|
||||||
|
git clone git://github.com/kevinw/pyflakes.git
|
||||||
|
|
||||||
|
Options
|
||||||
|
-------
|
||||||
|
|
||||||
|
Set this option to you vimrc file to disable quickfix support::
|
||||||
|
|
||||||
|
let g:pyflakes_use_quickfix = 0
|
||||||
|
|
||||||
|
The value is set to 1 by default.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
* signs_ support (show warning and error icons to left of the buffer area)
|
||||||
|
* configuration variables
|
||||||
|
* parse or intercept useful output from the warnings module
|
||||||
|
|
||||||
|
.. _signs: http://www.vim.org/htmldoc/sign.html
|
||||||
|
|
||||||
|
Changelog
|
||||||
|
---------
|
||||||
|
|
||||||
|
Please see http://www.vim.org/scripts/script.php?script_id=2441 for a history of
|
||||||
|
all changes.
|
||||||
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
" pyflakes.vim - A script to highlight Python code on the fly with warnings
|
||||||
|
" from Pyflakes, a Python lint tool.
|
||||||
|
"
|
||||||
|
" Place this script and the accompanying pyflakes directory in
|
||||||
|
" .vim/ftplugin/python.
|
||||||
|
"
|
||||||
|
" See README for additional installation and information.
|
||||||
|
"
|
||||||
|
" Thanks to matlib.vim for ideas/code on interactive linting.
|
||||||
|
"
|
||||||
|
" Maintainer: Kevin Watters <kevin.watters@gmail.com>
|
||||||
|
" Version: 0.1
|
||||||
|
if !has('python')
|
||||||
|
" exit if python is not available.
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists("b:did_pyflakes_plugin")
|
||||||
|
finish " only load once
|
||||||
|
else
|
||||||
|
let b:did_pyflakes_plugin = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('g:pyflakes_builtins')
|
||||||
|
let g:pyflakes_builtins = []
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("b:did_python_init")
|
||||||
|
let b:did_python_init = 0
|
||||||
|
|
||||||
|
if !has('python')
|
||||||
|
echoerr "Error: the pyflakes.vim plugin requires Vim to be compiled with +python"
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('g:pyflakes_use_quickfix')
|
||||||
|
let g:pyflakes_use_quickfix = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
python << EOF
|
||||||
|
import vim
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info[:2] < (2, 5):
|
||||||
|
raise AssertionError('Vim must be compiled with Python 2.5 or higher; you have ' + sys.version)
|
||||||
|
|
||||||
|
# get the directory this script is in: the pyflakes python module should be installed there.
|
||||||
|
scriptdir = os.path.join(os.path.dirname(vim.eval('expand("<sfile>")')), 'pyflakes')
|
||||||
|
sys.path.insert(0, scriptdir)
|
||||||
|
|
||||||
|
import ast
|
||||||
|
from pyflakes import checker, messages
|
||||||
|
from operator import attrgetter
|
||||||
|
import re
|
||||||
|
|
||||||
|
class loc(object):
|
||||||
|
def __init__(self, lineno, col=None):
|
||||||
|
self.lineno = lineno
|
||||||
|
self.col_offset = col
|
||||||
|
|
||||||
|
class SyntaxError(messages.Message):
|
||||||
|
message = 'could not compile: %s'
|
||||||
|
def __init__(self, filename, lineno, col, message):
|
||||||
|
messages.Message.__init__(self, filename, loc(lineno, col))
|
||||||
|
self.message_args = (message,)
|
||||||
|
|
||||||
|
class blackhole(object):
|
||||||
|
write = flush = lambda *a, **k: None
|
||||||
|
|
||||||
|
def check(buffer):
|
||||||
|
filename = buffer.name
|
||||||
|
contents = buffer[:]
|
||||||
|
|
||||||
|
# shebang usually found at the top of the file, followed by source code encoding marker.
|
||||||
|
# assume everything else that follows is encoded in the encoding.
|
||||||
|
encoding_found = False
|
||||||
|
for n, line in enumerate(contents):
|
||||||
|
if n >= 2:
|
||||||
|
break
|
||||||
|
elif re.match(r'#.*coding[:=]\s*([-\w.]+)', line):
|
||||||
|
contents = ['']*(n+1) + contents[n+1:]
|
||||||
|
break
|
||||||
|
|
||||||
|
contents = '\n'.join(contents) + '\n'
|
||||||
|
|
||||||
|
vimenc = vim.eval('&encoding')
|
||||||
|
if vimenc:
|
||||||
|
contents = contents.decode(vimenc)
|
||||||
|
|
||||||
|
builtins = set(['__file__'])
|
||||||
|
try:
|
||||||
|
builtins.update(set(eval(vim.eval('string(g:pyflakes_builtins)'))))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
# TODO: use warnings filters instead of ignoring stderr
|
||||||
|
old_stderr, sys.stderr = sys.stderr, blackhole()
|
||||||
|
try:
|
||||||
|
tree = ast.parse(contents, filename or '<unknown>')
|
||||||
|
finally:
|
||||||
|
sys.stderr = old_stderr
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
value = sys.exc_info()[1]
|
||||||
|
lineno, offset, line = value[1][1:]
|
||||||
|
except IndexError:
|
||||||
|
lineno, offset, line = 1, 0, ''
|
||||||
|
if line and line.endswith("\n"):
|
||||||
|
line = line[:-1]
|
||||||
|
|
||||||
|
return [SyntaxError(filename, lineno, offset, str(value))]
|
||||||
|
else:
|
||||||
|
# pyflakes looks to _MAGIC_GLOBALS in checker.py to see which
|
||||||
|
# UndefinedNames to ignore
|
||||||
|
old_globals = getattr(checker,' _MAGIC_GLOBALS', [])
|
||||||
|
checker._MAGIC_GLOBALS = set(old_globals) | builtins
|
||||||
|
|
||||||
|
w = checker.Checker(tree, filename)
|
||||||
|
|
||||||
|
checker._MAGIC_GLOBALS = old_globals
|
||||||
|
|
||||||
|
w.messages.sort(key = attrgetter('lineno'))
|
||||||
|
return w.messages
|
||||||
|
|
||||||
|
|
||||||
|
def vim_quote(s):
|
||||||
|
return s.replace("'", "''")
|
||||||
|
EOF
|
||||||
|
let b:did_python_init = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !b:did_python_init
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
au BufLeave <buffer> call s:ClearPyflakes()
|
||||||
|
|
||||||
|
au BufEnter <buffer> call s:RunPyflakes()
|
||||||
|
au InsertLeave <buffer> call s:RunPyflakes()
|
||||||
|
au InsertEnter <buffer> call s:RunPyflakes()
|
||||||
|
au BufWritePost <buffer> call s:RunPyflakes()
|
||||||
|
|
||||||
|
au CursorHold <buffer> call s:RunPyflakes()
|
||||||
|
au CursorHoldI <buffer> call s:RunPyflakes()
|
||||||
|
|
||||||
|
au CursorHold <buffer> call s:GetPyflakesMessage()
|
||||||
|
au CursorMoved <buffer> call s:GetPyflakesMessage()
|
||||||
|
|
||||||
|
if !exists("*s:PyflakesUpdate")
|
||||||
|
function s:PyflakesUpdate()
|
||||||
|
silent call s:RunPyflakes()
|
||||||
|
call s:GetPyflakesMessage()
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Call this function in your .vimrc to update PyFlakes
|
||||||
|
if !exists(":PyflakesUpdate")
|
||||||
|
command PyflakesUpdate :call s:PyflakesUpdate()
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Hook common text manipulation commands to update PyFlakes
|
||||||
|
" TODO: is there a more general "text op" autocommand we could register
|
||||||
|
" for here?
|
||||||
|
noremap <buffer><silent> dd dd:PyflakesUpdate<CR>
|
||||||
|
noremap <buffer><silent> dw dw:PyflakesUpdate<CR>
|
||||||
|
noremap <buffer><silent> u u:PyflakesUpdate<CR>
|
||||||
|
noremap <buffer><silent> <C-R> <C-R>:PyflakesUpdate<CR>
|
||||||
|
|
||||||
|
" WideMsg() prints [long] message up to (&columns-1) length
|
||||||
|
" guaranteed without "Press Enter" prompt.
|
||||||
|
if !exists("*s:WideMsg")
|
||||||
|
function s:WideMsg(msg)
|
||||||
|
let x=&ruler | let y=&showcmd
|
||||||
|
set noruler noshowcmd
|
||||||
|
redraw
|
||||||
|
echo strpart(a:msg, 0, &columns-1)
|
||||||
|
let &ruler=x | let &showcmd=y
|
||||||
|
endfun
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("*s:GetQuickFixStackCount")
|
||||||
|
function s:GetQuickFixStackCount()
|
||||||
|
let l:stack_count = 0
|
||||||
|
try
|
||||||
|
silent colder 9
|
||||||
|
catch /E380:/
|
||||||
|
endtry
|
||||||
|
|
||||||
|
try
|
||||||
|
for i in range(9)
|
||||||
|
silent cnewer
|
||||||
|
let l:stack_count = l:stack_count + 1
|
||||||
|
endfor
|
||||||
|
catch /E381:/
|
||||||
|
return l:stack_count
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("*s:ActivatePyflakesQuickFixWindow")
|
||||||
|
function s:ActivatePyflakesQuickFixWindow()
|
||||||
|
try
|
||||||
|
silent colder 9 " go to the bottom of quickfix stack
|
||||||
|
catch /E380:/
|
||||||
|
endtry
|
||||||
|
|
||||||
|
if s:pyflakes_qf > 0
|
||||||
|
try
|
||||||
|
exe "silent cnewer " . s:pyflakes_qf
|
||||||
|
catch /E381:/
|
||||||
|
echoerr "Could not activate Pyflakes Quickfix Window."
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("*s:RunPyflakes")
|
||||||
|
function s:RunPyflakes()
|
||||||
|
highlight link PyFlakes SpellBad
|
||||||
|
|
||||||
|
if exists("b:cleared")
|
||||||
|
if b:cleared == 0
|
||||||
|
silent call s:ClearPyflakes()
|
||||||
|
let b:cleared = 1
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
let b:cleared = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
let b:matched = []
|
||||||
|
let b:matchedlines = {}
|
||||||
|
|
||||||
|
let b:qf_list = []
|
||||||
|
let b:qf_window_count = -1
|
||||||
|
|
||||||
|
python << EOF
|
||||||
|
for w in check(vim.current.buffer):
|
||||||
|
vim.command('let s:matchDict = {}')
|
||||||
|
vim.command("let s:matchDict['lineNum'] = " + str(w.lineno))
|
||||||
|
vim.command("let s:matchDict['message'] = '%s'" % vim_quote(w.message % w.message_args))
|
||||||
|
vim.command("let b:matchedlines[" + str(w.lineno) + "] = s:matchDict")
|
||||||
|
|
||||||
|
vim.command("let l:qf_item = {}")
|
||||||
|
vim.command("let l:qf_item.bufnr = bufnr('%')")
|
||||||
|
vim.command("let l:qf_item.filename = expand('%')")
|
||||||
|
vim.command("let l:qf_item.lnum = %s" % str(w.lineno))
|
||||||
|
vim.command("let l:qf_item.text = '%s'" % vim_quote(w.message % w.message_args))
|
||||||
|
vim.command("let l:qf_item.type = 'E'")
|
||||||
|
|
||||||
|
if getattr(w, 'col', None) is None or isinstance(w, SyntaxError):
|
||||||
|
# without column information, just highlight the whole line
|
||||||
|
# (minus the newline)
|
||||||
|
vim.command(r"let s:mID = matchadd('PyFlakes', '\%" + str(w.lineno) + r"l\n\@!')")
|
||||||
|
else:
|
||||||
|
# with a column number, highlight the first keyword there
|
||||||
|
vim.command(r"let s:mID = matchadd('PyFlakes', '^\%" + str(w.lineno) + r"l\_.\{-}\zs\k\+\k\@!\%>" + str(w.col) + r"c')")
|
||||||
|
|
||||||
|
vim.command("let l:qf_item.vcol = 1")
|
||||||
|
vim.command("let l:qf_item.col = %s" % str(w.col + 1))
|
||||||
|
|
||||||
|
vim.command("call add(b:matched, s:matchDict)")
|
||||||
|
vim.command("call add(b:qf_list, l:qf_item)")
|
||||||
|
EOF
|
||||||
|
if g:pyflakes_use_quickfix == 1
|
||||||
|
if exists("s:pyflakes_qf")
|
||||||
|
" if pyflakes quickfix window is already created, reuse it
|
||||||
|
call s:ActivatePyflakesQuickFixWindow()
|
||||||
|
call setqflist(b:qf_list, 'r')
|
||||||
|
else
|
||||||
|
" one pyflakes quickfix window for all buffer
|
||||||
|
call setqflist(b:qf_list, '')
|
||||||
|
let s:pyflakes_qf = s:GetQuickFixStackCount()
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let b:cleared = 0
|
||||||
|
endfunction
|
||||||
|
end
|
||||||
|
|
||||||
|
" keep track of whether or not we are showing a message
|
||||||
|
let b:showing_message = 0
|
||||||
|
|
||||||
|
if !exists("*s:GetPyflakesMessage")
|
||||||
|
function s:GetPyflakesMessage()
|
||||||
|
let s:cursorPos = getpos(".")
|
||||||
|
|
||||||
|
" Bail if RunPyflakes hasn't been called yet.
|
||||||
|
if !exists('b:matchedlines')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" if there's a message for the line the cursor is currently on, echo
|
||||||
|
" it to the console
|
||||||
|
if has_key(b:matchedlines, s:cursorPos[1])
|
||||||
|
let s:pyflakesMatch = get(b:matchedlines, s:cursorPos[1])
|
||||||
|
call s:WideMsg(s:pyflakesMatch['message'])
|
||||||
|
let b:showing_message = 1
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" otherwise, if we're showing a message, clear it
|
||||||
|
if b:showing_message == 1
|
||||||
|
echo
|
||||||
|
let b:showing_message = 0
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('*s:ClearPyflakes')
|
||||||
|
function s:ClearPyflakes()
|
||||||
|
let s:matches = getmatches()
|
||||||
|
for s:matchId in s:matches
|
||||||
|
if s:matchId['group'] == 'PyFlakes'
|
||||||
|
call matchdelete(s:matchId['id'])
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
let b:matched = []
|
||||||
|
let b:matchedlines = {}
|
||||||
|
let b:cleared = 1
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
Copyright (c) 2005 Divmod, Inc., http://www.divmod.com/
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,29 @@
|
||||||
|
0.4.0 (2009-11-25):
|
||||||
|
- Fix reporting for certain SyntaxErrors which lack line number
|
||||||
|
information.
|
||||||
|
- Check for syntax errors more rigorously.
|
||||||
|
- Support checking names used with the class decorator syntax in versions
|
||||||
|
of Python which have it.
|
||||||
|
- Detect local variables which are bound but never used.
|
||||||
|
- Handle permission errors when trying to read source files.
|
||||||
|
- Handle problems with the encoding of source files.
|
||||||
|
- Support importing dotted names so as not to incorrectly report them as
|
||||||
|
redefined unused names.
|
||||||
|
- Support all forms of the with statement.
|
||||||
|
- Consider static `__all__` definitions and avoid reporting unused names
|
||||||
|
if the names are listed there.
|
||||||
|
- Fix incorrect checking of class names with respect to the names of their
|
||||||
|
bases in the class statement.
|
||||||
|
- Support the `__path__` global in `__init__.py`.
|
||||||
|
|
||||||
|
0.3.0 (2009-01-30):
|
||||||
|
- Display more informative SyntaxError messages.
|
||||||
|
- Don't hang flymake with unmatched triple quotes (only report a single
|
||||||
|
line of source for a multiline syntax error).
|
||||||
|
- Recognize __builtins__ as a defined name.
|
||||||
|
- Improve pyflakes support for python versions 2.3-2.5
|
||||||
|
- Support for if-else expressions and with statements.
|
||||||
|
- Warn instead of error on non-existant file paths.
|
||||||
|
- Check for __future__ imports after other statements.
|
||||||
|
- Add reporting for some types of import shadowing.
|
||||||
|
- Improve reporting of unbound locals
|
|
@ -0,0 +1,36 @@
|
||||||
|
pyflakes
|
||||||
|
========
|
||||||
|
|
||||||
|
This version of PyFlakes_ has been improved to use Python's newer ``ast``
|
||||||
|
module, instead of ``compiler``. So code checking happens faster, and will stay
|
||||||
|
up to date with new language changes.
|
||||||
|
|
||||||
|
.. _PyFlakes: http://http://www.divmod.org/trac/wiki/DivmodPyflakes
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
|
||||||
|
Importing several modules from the same package results in unnecessary warnings:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
import a.b
|
||||||
|
import a.c # Redefinition of unused "a" from line 1
|
||||||
|
|
||||||
|
The following construct for defining a function differently depending on some
|
||||||
|
condition results in a redefinition warning:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
if some_condition:
|
||||||
|
def foo(): do_foo()
|
||||||
|
else:
|
||||||
|
def foo(): do_bar() # redefinition of function 'foo' from line 2
|
||||||
|
|
||||||
|
IDE Integration
|
||||||
|
---------------
|
||||||
|
|
||||||
|
* vim: pyflakes-vim_
|
||||||
|
|
||||||
|
.. _pyflakes-vim: http://github.com/kevinw/pyflakes-vim
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
- Check for methods that override other methods except that they vary by case.
|
||||||
|
- assign/increment + unbound local error not caught
|
||||||
|
def foo():
|
||||||
|
bar = 5
|
||||||
|
def meep():
|
||||||
|
bar += 2
|
||||||
|
meep()
|
||||||
|
print bar
|
||||||
|
|
||||||
|
print foo()
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
__version__ = '0.4.0'
|
|
@ -0,0 +1,311 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
ast
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The `ast` module helps Python applications to process trees of the Python
|
||||||
|
abstract syntax grammar. The abstract syntax itself might change with
|
||||||
|
each Python release; this module helps to find out programmatically what
|
||||||
|
the current grammar looks like and allows modifications of it.
|
||||||
|
|
||||||
|
An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
|
||||||
|
a flag to the `compile()` builtin function or by using the `parse()`
|
||||||
|
function from this module. The result will be a tree of objects whose
|
||||||
|
classes all inherit from `ast.AST`.
|
||||||
|
|
||||||
|
A modified abstract syntax tree can be compiled into a Python code object
|
||||||
|
using the built-in `compile()` function.
|
||||||
|
|
||||||
|
Additionally various helper functions are provided that make working with
|
||||||
|
the trees simpler. The main intention of the helper functions and this
|
||||||
|
module in general is to provide an easy to use interface for libraries
|
||||||
|
that work tightly with the python syntax (template engines for example).
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright 2008 by Armin Ronacher.
|
||||||
|
:license: Python License.
|
||||||
|
"""
|
||||||
|
from _ast import *
|
||||||
|
from _ast import __version__
|
||||||
|
|
||||||
|
|
||||||
|
def parse(expr, filename='<unknown>', mode='exec'):
|
||||||
|
"""
|
||||||
|
Parse an expression into an AST node.
|
||||||
|
Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
|
||||||
|
"""
|
||||||
|
return compile(expr, filename, mode, PyCF_ONLY_AST)
|
||||||
|
|
||||||
|
|
||||||
|
def literal_eval(node_or_string):
|
||||||
|
"""
|
||||||
|
Safely evaluate an expression node or a string containing a Python
|
||||||
|
expression. The string or node provided may only consist of the following
|
||||||
|
Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
|
||||||
|
and None.
|
||||||
|
"""
|
||||||
|
_safe_names = {'None': None, 'True': True, 'False': False}
|
||||||
|
if isinstance(node_or_string, basestring):
|
||||||
|
node_or_string = parse(node_or_string, mode='eval')
|
||||||
|
if isinstance(node_or_string, Expression):
|
||||||
|
node_or_string = node_or_string.body
|
||||||
|
def _convert(node):
|
||||||
|
if isinstance(node, Str):
|
||||||
|
return node.s
|
||||||
|
elif isinstance(node, Num):
|
||||||
|
return node.n
|
||||||
|
elif isinstance(node, Tuple):
|
||||||
|
return tuple(map(_convert, node.elts))
|
||||||
|
elif isinstance(node, List):
|
||||||
|
return list(map(_convert, node.elts))
|
||||||
|
elif isinstance(node, Dict):
|
||||||
|
return dict((_convert(k), _convert(v)) for k, v
|
||||||
|
in zip(node.keys, node.values))
|
||||||
|
elif isinstance(node, Name):
|
||||||
|
if node.id in _safe_names:
|
||||||
|
return _safe_names[node.id]
|
||||||
|
raise ValueError('malformed string')
|
||||||
|
return _convert(node_or_string)
|
||||||
|
|
||||||
|
|
||||||
|
def dump(node, annotate_fields=True, include_attributes=False):
|
||||||
|
"""
|
||||||
|
Return a formatted dump of the tree in *node*. This is mainly useful for
|
||||||
|
debugging purposes. The returned string will show the names and the values
|
||||||
|
for fields. This makes the code impossible to evaluate, so if evaluation is
|
||||||
|
wanted *annotate_fields* must be set to False. Attributes such as line
|
||||||
|
numbers and column offsets are not dumped by default. If this is wanted,
|
||||||
|
*include_attributes* can be set to True.
|
||||||
|
"""
|
||||||
|
def _format(node):
|
||||||
|
if isinstance(node, AST):
|
||||||
|
fields = [(a, _format(b)) for a, b in iter_fields(node)]
|
||||||
|
rv = '%s(%s' % (node.__class__.__name__, ', '.join(
|
||||||
|
('%s=%s' % field for field in fields)
|
||||||
|
if annotate_fields else
|
||||||
|
(b for a, b in fields)
|
||||||
|
))
|
||||||
|
if include_attributes and node._attributes:
|
||||||
|
rv += fields and ', ' or ' '
|
||||||
|
rv += ', '.join('%s=%s' % (a, _format(getattr(node, a)))
|
||||||
|
for a in node._attributes)
|
||||||
|
return rv + ')'
|
||||||
|
elif isinstance(node, list):
|
||||||
|
return '[%s]' % ', '.join(_format(x) for x in node)
|
||||||
|
return repr(node)
|
||||||
|
if not isinstance(node, AST):
|
||||||
|
raise TypeError('expected AST, got %r' % node.__class__.__name__)
|
||||||
|
return _format(node)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_location(new_node, old_node):
|
||||||
|
"""
|
||||||
|
Copy source location (`lineno` and `col_offset` attributes) from
|
||||||
|
*old_node* to *new_node* if possible, and return *new_node*.
|
||||||
|
"""
|
||||||
|
for attr in 'lineno', 'col_offset':
|
||||||
|
if attr in old_node._attributes and attr in new_node._attributes \
|
||||||
|
and hasattr(old_node, attr):
|
||||||
|
setattr(new_node, attr, getattr(old_node, attr))
|
||||||
|
return new_node
|
||||||
|
|
||||||
|
|
||||||
|
def fix_missing_locations(node):
|
||||||
|
"""
|
||||||
|
When you compile a node tree with compile(), the compiler expects lineno and
|
||||||
|
col_offset attributes for every node that supports them. This is rather
|
||||||
|
tedious to fill in for generated nodes, so this helper adds these attributes
|
||||||
|
recursively where not already set, by setting them to the values of the
|
||||||
|
parent node. It works recursively starting at *node*.
|
||||||
|
"""
|
||||||
|
def _fix(node, lineno, col_offset):
|
||||||
|
if 'lineno' in node._attributes:
|
||||||
|
if not hasattr(node, 'lineno'):
|
||||||
|
node.lineno = lineno
|
||||||
|
else:
|
||||||
|
lineno = node.lineno
|
||||||
|
if 'col_offset' in node._attributes:
|
||||||
|
if not hasattr(node, 'col_offset'):
|
||||||
|
node.col_offset = col_offset
|
||||||
|
else:
|
||||||
|
col_offset = node.col_offset
|
||||||
|
for child in iter_child_nodes(node):
|
||||||
|
_fix(child, lineno, col_offset)
|
||||||
|
_fix(node, 1, 0)
|
||||||
|
return node
|
||||||
|
|
||||||
|
def add_col_end(node):
|
||||||
|
def _fix(node, next):
|
||||||
|
children = list(iter_child_nodes(node))
|
||||||
|
for i, child in enumerate(children):
|
||||||
|
next_offset = children[i+1].col_offset if i < len(children) else next.col_offset
|
||||||
|
child.col_end = next_offset
|
||||||
|
|
||||||
|
|
||||||
|
def increment_lineno(node, n=1):
|
||||||
|
"""
|
||||||
|
Increment the line number of each node in the tree starting at *node* by *n*.
|
||||||
|
This is useful to "move code" to a different location in a file.
|
||||||
|
"""
|
||||||
|
if 'lineno' in node._attributes:
|
||||||
|
node.lineno = getattr(node, 'lineno', 0) + n
|
||||||
|
for child in walk(node):
|
||||||
|
if 'lineno' in child._attributes:
|
||||||
|
child.lineno = getattr(child, 'lineno', 0) + n
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def iter_fields(node):
|
||||||
|
"""
|
||||||
|
Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
|
||||||
|
that is present on *node*.
|
||||||
|
"""
|
||||||
|
if node._fields is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
for field in node._fields:
|
||||||
|
try:
|
||||||
|
yield field, getattr(node, field)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def iter_child_nodes(node):
|
||||||
|
"""
|
||||||
|
Yield all direct child nodes of *node*, that is, all fields that are nodes
|
||||||
|
and all items of fields that are lists of nodes.
|
||||||
|
"""
|
||||||
|
for name, field in iter_fields(node):
|
||||||
|
if isinstance(field, AST):
|
||||||
|
yield field
|
||||||
|
elif isinstance(field, list):
|
||||||
|
for item in field:
|
||||||
|
if isinstance(item, AST):
|
||||||
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
def get_docstring(node, clean=True):
|
||||||
|
"""
|
||||||
|
Return the docstring for the given node or None if no docstring can
|
||||||
|
be found. If the node provided does not have docstrings a TypeError
|
||||||
|
will be raised.
|
||||||
|
"""
|
||||||
|
if not isinstance(node, (FunctionDef, ClassDef, Module)):
|
||||||
|
raise TypeError("%r can't have docstrings" % node.__class__.__name__)
|
||||||
|
if node.body and isinstance(node.body[0], Expr) and \
|
||||||
|
isinstance(node.body[0].value, Str):
|
||||||
|
if clean:
|
||||||
|
import inspect
|
||||||
|
return inspect.cleandoc(node.body[0].value.s)
|
||||||
|
return node.body[0].value.s
|
||||||
|
|
||||||
|
|
||||||
|
def walk(node):
|
||||||
|
"""
|
||||||
|
Recursively yield all child nodes of *node*, in no specified order. This is
|
||||||
|
useful if you only want to modify nodes in place and don't care about the
|
||||||
|
context.
|
||||||
|
"""
|
||||||
|
from collections import deque
|
||||||
|
todo = deque([node])
|
||||||
|
while todo:
|
||||||
|
node = todo.popleft()
|
||||||
|
todo.extend(iter_child_nodes(node))
|
||||||
|
yield node
|
||||||
|
|
||||||
|
|
||||||
|
class NodeVisitor(object):
|
||||||
|
"""
|
||||||
|
A node visitor base class that walks the abstract syntax tree and calls a
|
||||||
|
visitor function for every node found. This function may return a value
|
||||||
|
which is forwarded by the `visit` method.
|
||||||
|
|
||||||
|
This class is meant to be subclassed, with the subclass adding visitor
|
||||||
|
methods.
|
||||||
|
|
||||||
|
Per default the visitor functions for the nodes are ``'visit_'`` +
|
||||||
|
class name of the node. So a `TryFinally` node visit function would
|
||||||
|
be `visit_TryFinally`. This behavior can be changed by overriding
|
||||||
|
the `visit` method. If no visitor function exists for a node
|
||||||
|
(return value `None`) the `generic_visit` visitor is used instead.
|
||||||
|
|
||||||
|
Don't use the `NodeVisitor` if you want to apply changes to nodes during
|
||||||
|
traversing. For this a special visitor exists (`NodeTransformer`) that
|
||||||
|
allows modifications.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def visit(self, node):
|
||||||
|
"""Visit a node."""
|
||||||
|
method = 'visit_' + node.__class__.__name__
|
||||||
|
visitor = getattr(self, method, self.generic_visit)
|
||||||
|
return visitor(node)
|
||||||
|
|
||||||
|
def generic_visit(self, node):
|
||||||
|
"""Called if no explicit visitor function exists for a node."""
|
||||||
|
for field, value in iter_fields(node):
|
||||||
|
if isinstance(value, list):
|
||||||
|
for item in value:
|
||||||
|
if isinstance(item, AST):
|
||||||
|
self.visit(item)
|
||||||
|
elif isinstance(value, AST):
|
||||||
|
self.visit(value)
|
||||||
|
|
||||||
|
|
||||||
|
class NodeTransformer(NodeVisitor):
|
||||||
|
"""
|
||||||
|
A :class:`NodeVisitor` subclass that walks the abstract syntax tree and
|
||||||
|
allows modification of nodes.
|
||||||
|
|
||||||
|
The `NodeTransformer` will walk the AST and use the return value of the
|
||||||
|
visitor methods to replace or remove the old node. If the return value of
|
||||||
|
the visitor method is ``None``, the node will be removed from its location,
|
||||||
|
otherwise it is replaced with the return value. The return value may be the
|
||||||
|
original node in which case no replacement takes place.
|
||||||
|
|
||||||
|
Here is an example transformer that rewrites all occurrences of name lookups
|
||||||
|
(``foo``) to ``data['foo']``::
|
||||||
|
|
||||||
|
class RewriteName(NodeTransformer):
|
||||||
|
|
||||||
|
def visit_Name(self, node):
|
||||||
|
return copy_location(Subscript(
|
||||||
|
value=Name(id='data', ctx=Load()),
|
||||||
|
slice=Index(value=Str(s=node.id)),
|
||||||
|
ctx=node.ctx
|
||||||
|
), node)
|
||||||
|
|
||||||
|
Keep in mind that if the node you're operating on has child nodes you must
|
||||||
|
either transform the child nodes yourself or call the :meth:`generic_visit`
|
||||||
|
method for the node first.
|
||||||
|
|
||||||
|
For nodes that were part of a collection of statements (that applies to all
|
||||||
|
statement nodes), the visitor may also return a list of nodes rather than
|
||||||
|
just a single node.
|
||||||
|
|
||||||
|
Usually you use the transformer like this::
|
||||||
|
|
||||||
|
node = YourTransformer().visit(node)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def generic_visit(self, node):
|
||||||
|
for field, old_value in iter_fields(node):
|
||||||
|
old_value = getattr(node, field, None)
|
||||||
|
if isinstance(old_value, list):
|
||||||
|
new_values = []
|
||||||
|
for value in old_value:
|
||||||
|
if isinstance(value, AST):
|
||||||
|
value = self.visit(value)
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
elif not isinstance(value, AST):
|
||||||
|
new_values.extend(value)
|
||||||
|
continue
|
||||||
|
new_values.append(value)
|
||||||
|
old_value[:] = new_values
|
||||||
|
elif isinstance(old_value, AST):
|
||||||
|
new_node = self.visit(old_value)
|
||||||
|
if new_node is None:
|
||||||
|
delattr(node, field)
|
||||||
|
else:
|
||||||
|
setattr(node, field, new_node)
|
||||||
|
return node
|
|
@ -0,0 +1,625 @@
|
||||||
|
# -*- test-case-name: pyflakes -*-
|
||||||
|
# (c) 2005-2010 Divmod, Inc.
|
||||||
|
# See LICENSE file for details
|
||||||
|
|
||||||
|
import __builtin__
|
||||||
|
import os.path
|
||||||
|
import _ast
|
||||||
|
|
||||||
|
from pyflakes import messages
|
||||||
|
|
||||||
|
|
||||||
|
# utility function to iterate over an AST node's children, adapted
|
||||||
|
# from Python 2.6's standard ast module
|
||||||
|
try:
|
||||||
|
import ast
|
||||||
|
iter_child_nodes = ast.iter_child_nodes
|
||||||
|
except (ImportError, AttributeError):
|
||||||
|
def iter_child_nodes(node, astcls=_ast.AST):
|
||||||
|
"""
|
||||||
|
Yield all direct child nodes of *node*, that is, all fields that are nodes
|
||||||
|
and all items of fields that are lists of nodes.
|
||||||
|
"""
|
||||||
|
for name in node._fields:
|
||||||
|
field = getattr(node, name, None)
|
||||||
|
if isinstance(field, astcls):
|
||||||
|
yield field
|
||||||
|
elif isinstance(field, list):
|
||||||
|
for item in field:
|
||||||
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
class Binding(object):
|
||||||
|
"""
|
||||||
|
Represents the binding of a value to a name.
|
||||||
|
|
||||||
|
The checker uses this to keep track of which names have been bound and
|
||||||
|
which names have not. See L{Assignment} for a special type of binding that
|
||||||
|
is checked with stricter rules.
|
||||||
|
|
||||||
|
@ivar used: pair of (L{Scope}, line-number) indicating the scope and
|
||||||
|
line number that this binding was last used
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, source):
|
||||||
|
self.name = name
|
||||||
|
self.source = source
|
||||||
|
self.used = False
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
|
||||||
|
self.name,
|
||||||
|
self.source.lineno,
|
||||||
|
id(self))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UnBinding(Binding):
|
||||||
|
'''Created by the 'del' operator.'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Importation(Binding):
|
||||||
|
"""
|
||||||
|
A binding created by an import statement.
|
||||||
|
|
||||||
|
@ivar fullName: The complete name given to the import statement,
|
||||||
|
possibly including multiple dotted components.
|
||||||
|
@type fullName: C{str}
|
||||||
|
"""
|
||||||
|
def __init__(self, name, source):
|
||||||
|
self.fullName = name
|
||||||
|
name = name.split('.')[0]
|
||||||
|
super(Importation, self).__init__(name, source)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Argument(Binding):
|
||||||
|
"""
|
||||||
|
Represents binding a name as an argument.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Assignment(Binding):
|
||||||
|
"""
|
||||||
|
Represents binding a name with an explicit assignment.
|
||||||
|
|
||||||
|
The checker will raise warnings for any Assignment that isn't used. Also,
|
||||||
|
the checker does not consider assignments in tuple/list unpacking to be
|
||||||
|
Assignments, rather it treats them as simple Bindings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionDefinition(Binding):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ExportBinding(Binding):
|
||||||
|
"""
|
||||||
|
A binding created by an C{__all__} assignment. If the names in the list
|
||||||
|
can be determined statically, they will be treated as names for export and
|
||||||
|
additional checking applied to them.
|
||||||
|
|
||||||
|
The only C{__all__} assignment that can be recognized is one which takes
|
||||||
|
the value of a literal list containing literal strings. For example::
|
||||||
|
|
||||||
|
__all__ = ["foo", "bar"]
|
||||||
|
|
||||||
|
Names which are imported and not otherwise used but appear in the value of
|
||||||
|
C{__all__} will not have an unused import warning reported for them.
|
||||||
|
"""
|
||||||
|
def names(self):
|
||||||
|
"""
|
||||||
|
Return a list of the names referenced by this binding.
|
||||||
|
"""
|
||||||
|
names = []
|
||||||
|
if isinstance(self.source, _ast.List):
|
||||||
|
for node in self.source.elts:
|
||||||
|
if isinstance(node, _ast.Str):
|
||||||
|
names.append(node.s)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Scope(dict):
|
||||||
|
importStarred = False # set to True when import * is found
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self))
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Scope, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ClassScope(Scope):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionScope(Scope):
|
||||||
|
"""
|
||||||
|
I represent a name scope for a function.
|
||||||
|
|
||||||
|
@ivar globals: Names declared 'global' in this function.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
super(FunctionScope, self).__init__()
|
||||||
|
self.globals = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleScope(Scope):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Globally defined names which are not attributes of the __builtin__ module.
|
||||||
|
_MAGIC_GLOBALS = ['__file__', '__builtins__']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Checker(object):
|
||||||
|
"""
|
||||||
|
I check the cleanliness and sanity of Python code.
|
||||||
|
|
||||||
|
@ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
|
||||||
|
of the list are two-tuples. The first element is the callable passed
|
||||||
|
to L{deferFunction}. The second element is a copy of the scope stack
|
||||||
|
at the time L{deferFunction} was called.
|
||||||
|
|
||||||
|
@ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
|
||||||
|
callables which are deferred assignment checks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
nodeDepth = 0
|
||||||
|
traceTree = False
|
||||||
|
|
||||||
|
def __init__(self, tree, filename='(none)'):
|
||||||
|
self._deferredFunctions = []
|
||||||
|
self._deferredAssignments = []
|
||||||
|
self.dead_scopes = []
|
||||||
|
self.messages = []
|
||||||
|
self.filename = filename
|
||||||
|
self.scopeStack = [ModuleScope()]
|
||||||
|
self.futuresAllowed = True
|
||||||
|
self.handleChildren(tree)
|
||||||
|
self._runDeferred(self._deferredFunctions)
|
||||||
|
# Set _deferredFunctions to None so that deferFunction will fail
|
||||||
|
# noisily if called after we've run through the deferred functions.
|
||||||
|
self._deferredFunctions = None
|
||||||
|
self._runDeferred(self._deferredAssignments)
|
||||||
|
# Set _deferredAssignments to None so that deferAssignment will fail
|
||||||
|
# noisly if called after we've run through the deferred assignments.
|
||||||
|
self._deferredAssignments = None
|
||||||
|
del self.scopeStack[1:]
|
||||||
|
self.popScope()
|
||||||
|
self.check_dead_scopes()
|
||||||
|
|
||||||
|
|
||||||
|
def deferFunction(self, callable):
|
||||||
|
'''
|
||||||
|
Schedule a function handler to be called just before completion.
|
||||||
|
|
||||||
|
This is used for handling function bodies, which must be deferred
|
||||||
|
because code later in the file might modify the global scope. When
|
||||||
|
`callable` is called, the scope at the time this is called will be
|
||||||
|
restored, however it will contain any new bindings added to it.
|
||||||
|
'''
|
||||||
|
self._deferredFunctions.append((callable, self.scopeStack[:]))
|
||||||
|
|
||||||
|
|
||||||
|
def deferAssignment(self, callable):
|
||||||
|
"""
|
||||||
|
Schedule an assignment handler to be called just after deferred
|
||||||
|
function handlers.
|
||||||
|
"""
|
||||||
|
self._deferredAssignments.append((callable, self.scopeStack[:]))
|
||||||
|
|
||||||
|
|
||||||
|
def _runDeferred(self, deferred):
|
||||||
|
"""
|
||||||
|
Run the callables in C{deferred} using their associated scope stack.
|
||||||
|
"""
|
||||||
|
for handler, scope in deferred:
|
||||||
|
self.scopeStack = scope
|
||||||
|
handler()
|
||||||
|
|
||||||
|
|
||||||
|
def scope(self):
|
||||||
|
return self.scopeStack[-1]
|
||||||
|
scope = property(scope)
|
||||||
|
|
||||||
|
def popScope(self):
|
||||||
|
self.dead_scopes.append(self.scopeStack.pop())
|
||||||
|
|
||||||
|
|
||||||
|
def check_dead_scopes(self):
|
||||||
|
"""
|
||||||
|
Look at scopes which have been fully examined and report names in them
|
||||||
|
which were imported but unused.
|
||||||
|
"""
|
||||||
|
for scope in self.dead_scopes:
|
||||||
|
export = isinstance(scope.get('__all__'), ExportBinding)
|
||||||
|
if export:
|
||||||
|
all = scope['__all__'].names()
|
||||||
|
if os.path.split(self.filename)[1] != '__init__.py':
|
||||||
|
# Look for possible mistakes in the export list
|
||||||
|
undefined = set(all) - set(scope)
|
||||||
|
for name in undefined:
|
||||||
|
self.report(
|
||||||
|
messages.UndefinedExport,
|
||||||
|
scope['__all__'].source,
|
||||||
|
name)
|
||||||
|
else:
|
||||||
|
all = []
|
||||||
|
|
||||||
|
# Look for imported names that aren't used.
|
||||||
|
for importation in scope.itervalues():
|
||||||
|
if isinstance(importation, Importation):
|
||||||
|
if not importation.used and importation.name not in all:
|
||||||
|
self.report(
|
||||||
|
messages.UnusedImport,
|
||||||
|
importation.source,
|
||||||
|
importation.name)
|
||||||
|
|
||||||
|
|
||||||
|
def pushFunctionScope(self):
|
||||||
|
self.scopeStack.append(FunctionScope())
|
||||||
|
|
||||||
|
def pushClassScope(self):
|
||||||
|
self.scopeStack.append(ClassScope())
|
||||||
|
|
||||||
|
def report(self, messageClass, *args, **kwargs):
|
||||||
|
self.messages.append(messageClass(self.filename, *args, **kwargs))
|
||||||
|
|
||||||
|
def handleChildren(self, tree):
|
||||||
|
for node in iter_child_nodes(tree):
|
||||||
|
self.handleNode(node, tree)
|
||||||
|
|
||||||
|
def isDocstring(self, node):
|
||||||
|
"""
|
||||||
|
Determine if the given node is a docstring, as long as it is at the
|
||||||
|
correct place in the node tree.
|
||||||
|
"""
|
||||||
|
return isinstance(node, _ast.Str) or \
|
||||||
|
(isinstance(node, _ast.Expr) and
|
||||||
|
isinstance(node.value, _ast.Str))
|
||||||
|
|
||||||
|
def handleNode(self, node, parent):
|
||||||
|
node.parent = parent
|
||||||
|
if self.traceTree:
|
||||||
|
print ' ' * self.nodeDepth + node.__class__.__name__
|
||||||
|
self.nodeDepth += 1
|
||||||
|
if self.futuresAllowed and not \
|
||||||
|
(isinstance(node, _ast.ImportFrom) or self.isDocstring(node)):
|
||||||
|
self.futuresAllowed = False
|
||||||
|
nodeType = node.__class__.__name__.upper()
|
||||||
|
try:
|
||||||
|
handler = getattr(self, nodeType)
|
||||||
|
handler(node)
|
||||||
|
finally:
|
||||||
|
self.nodeDepth -= 1
|
||||||
|
if self.traceTree:
|
||||||
|
print ' ' * self.nodeDepth + 'end ' + node.__class__.__name__
|
||||||
|
|
||||||
|
def ignore(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# "stmt" type nodes
|
||||||
|
RETURN = DELETE = PRINT = WHILE = IF = WITH = RAISE = TRYEXCEPT = \
|
||||||
|
TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren
|
||||||
|
|
||||||
|
CONTINUE = BREAK = PASS = ignore
|
||||||
|
|
||||||
|
# "expr" type nodes
|
||||||
|
BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = COMPARE = \
|
||||||
|
CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = handleChildren
|
||||||
|
|
||||||
|
NUM = STR = ELLIPSIS = ignore
|
||||||
|
|
||||||
|
# "slice" type nodes
|
||||||
|
SLICE = EXTSLICE = INDEX = handleChildren
|
||||||
|
|
||||||
|
# expression contexts are node instances too, though being constants
|
||||||
|
LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore
|
||||||
|
|
||||||
|
# same for operators
|
||||||
|
AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
|
||||||
|
BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
|
||||||
|
EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
|
||||||
|
|
||||||
|
# additional node types
|
||||||
|
COMPREHENSION = EXCEPTHANDLER = KEYWORD = handleChildren
|
||||||
|
|
||||||
|
def addBinding(self, loc, value, reportRedef=True):
|
||||||
|
'''Called when a binding is altered.
|
||||||
|
|
||||||
|
- `loc` is the location (an object with lineno and optionally
|
||||||
|
col_offset attributes) of the statement responsible for the change
|
||||||
|
- `value` is the optional new value, a Binding instance, associated
|
||||||
|
with the binding; if None, the binding is deleted if it exists.
|
||||||
|
- if `reportRedef` is True (default), rebinding while unused will be
|
||||||
|
reported.
|
||||||
|
'''
|
||||||
|
if (isinstance(self.scope.get(value.name), FunctionDefinition)
|
||||||
|
and isinstance(value, FunctionDefinition)):
|
||||||
|
self.report(messages.RedefinedFunction,
|
||||||
|
loc, value.name, self.scope[value.name].source)
|
||||||
|
|
||||||
|
if not isinstance(self.scope, ClassScope):
|
||||||
|
for scope in self.scopeStack[::-1]:
|
||||||
|
existing = scope.get(value.name)
|
||||||
|
if (isinstance(existing, Importation)
|
||||||
|
and not existing.used
|
||||||
|
and (not isinstance(value, Importation) or value.fullName == existing.fullName)
|
||||||
|
and reportRedef):
|
||||||
|
|
||||||
|
self.report(messages.RedefinedWhileUnused,
|
||||||
|
loc, value.name, scope[value.name].source)
|
||||||
|
|
||||||
|
if isinstance(value, UnBinding):
|
||||||
|
try:
|
||||||
|
del self.scope[value.name]
|
||||||
|
except KeyError:
|
||||||
|
self.report(messages.UndefinedName, loc, value.name)
|
||||||
|
else:
|
||||||
|
self.scope[value.name] = value
|
||||||
|
|
||||||
|
def GLOBAL(self, node):
|
||||||
|
"""
|
||||||
|
Keep track of globals declarations.
|
||||||
|
"""
|
||||||
|
if isinstance(self.scope, FunctionScope):
|
||||||
|
self.scope.globals.update(dict.fromkeys(node.names))
|
||||||
|
|
||||||
|
def LISTCOMP(self, node):
|
||||||
|
# handle generators before element
|
||||||
|
for gen in node.generators:
|
||||||
|
self.handleNode(gen, node)
|
||||||
|
self.handleNode(node.elt, node)
|
||||||
|
|
||||||
|
GENERATOREXP = SETCOMP = LISTCOMP
|
||||||
|
|
||||||
|
# dictionary comprehensions; introduced in Python 2.7
|
||||||
|
def DICTCOMP(self, node):
|
||||||
|
for gen in node.generators:
|
||||||
|
self.handleNode(gen, node)
|
||||||
|
self.handleNode(node.key, node)
|
||||||
|
self.handleNode(node.value, node)
|
||||||
|
|
||||||
|
def FOR(self, node):
|
||||||
|
"""
|
||||||
|
Process bindings for loop variables.
|
||||||
|
"""
|
||||||
|
vars = []
|
||||||
|
def collectLoopVars(n):
|
||||||
|
if isinstance(n, _ast.Name):
|
||||||
|
vars.append(n.id)
|
||||||
|
elif isinstance(n, _ast.expr_context):
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
for c in iter_child_nodes(n):
|
||||||
|
collectLoopVars(c)
|
||||||
|
|
||||||
|
collectLoopVars(node.target)
|
||||||
|
for varn in vars:
|
||||||
|
if (isinstance(self.scope.get(varn), Importation)
|
||||||
|
# unused ones will get an unused import warning
|
||||||
|
and self.scope[varn].used):
|
||||||
|
self.report(messages.ImportShadowedByLoopVar,
|
||||||
|
node, varn, self.scope[varn].source)
|
||||||
|
|
||||||
|
self.handleChildren(node)
|
||||||
|
|
||||||
|
def NAME(self, node):
|
||||||
|
"""
|
||||||
|
Handle occurrence of Name (which can be a load/store/delete access.)
|
||||||
|
"""
|
||||||
|
# Locate the name in locals / function / globals scopes.
|
||||||
|
if isinstance(node.ctx, (_ast.Load, _ast.AugLoad)):
|
||||||
|
# try local scope
|
||||||
|
importStarred = self.scope.importStarred
|
||||||
|
try:
|
||||||
|
self.scope[node.id].used = (self.scope, node)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# try enclosing function scopes
|
||||||
|
|
||||||
|
for scope in self.scopeStack[-2:0:-1]:
|
||||||
|
importStarred = importStarred or scope.importStarred
|
||||||
|
if not isinstance(scope, FunctionScope):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
scope[node.id].used = (self.scope, node)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# try global scope
|
||||||
|
|
||||||
|
importStarred = importStarred or self.scopeStack[0].importStarred
|
||||||
|
try:
|
||||||
|
self.scopeStack[0][node.id].used = (self.scope, node)
|
||||||
|
except KeyError:
|
||||||
|
if ((not hasattr(__builtin__, node.id))
|
||||||
|
and node.id not in _MAGIC_GLOBALS
|
||||||
|
and not importStarred):
|
||||||
|
if (os.path.basename(self.filename) == '__init__.py' and
|
||||||
|
node.id == '__path__'):
|
||||||
|
# the special name __path__ is valid only in packages
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.report(messages.UndefinedName, node, node.id)
|
||||||
|
elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):
|
||||||
|
# if the name hasn't already been defined in the current scope
|
||||||
|
if isinstance(self.scope, FunctionScope) and node.id not in self.scope:
|
||||||
|
# for each function or module scope above us
|
||||||
|
for scope in self.scopeStack[:-1]:
|
||||||
|
if not isinstance(scope, (FunctionScope, ModuleScope)):
|
||||||
|
continue
|
||||||
|
# if the name was defined in that scope, and the name has
|
||||||
|
# been accessed already in the current scope, and hasn't
|
||||||
|
# been declared global
|
||||||
|
if (node.id in scope
|
||||||
|
and scope[node.id].used
|
||||||
|
and scope[node.id].used[0] is self.scope
|
||||||
|
and node.id not in self.scope.globals):
|
||||||
|
# then it's probably a mistake
|
||||||
|
self.report(messages.UndefinedLocal,
|
||||||
|
scope[node.id].used[1],
|
||||||
|
node.id,
|
||||||
|
scope[node.id].source)
|
||||||
|
break
|
||||||
|
|
||||||
|
if isinstance(node.parent,
|
||||||
|
(_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)):
|
||||||
|
binding = Binding(node.id, node)
|
||||||
|
elif (node.id == '__all__' and
|
||||||
|
isinstance(self.scope, ModuleScope)):
|
||||||
|
binding = ExportBinding(node.id, node.parent.value)
|
||||||
|
else:
|
||||||
|
binding = Assignment(node.id, node)
|
||||||
|
if node.id in self.scope:
|
||||||
|
binding.used = self.scope[node.id].used
|
||||||
|
self.addBinding(node, binding)
|
||||||
|
elif isinstance(node.ctx, _ast.Del):
|
||||||
|
if isinstance(self.scope, FunctionScope) and \
|
||||||
|
node.id in self.scope.globals:
|
||||||
|
del self.scope.globals[node.id]
|
||||||
|
else:
|
||||||
|
self.addBinding(node, UnBinding(node.id, node))
|
||||||
|
else:
|
||||||
|
# must be a Param context -- this only happens for names in function
|
||||||
|
# arguments, but these aren't dispatched through here
|
||||||
|
raise RuntimeError(
|
||||||
|
"Got impossible expression context: %r" % (node.ctx,))
|
||||||
|
|
||||||
|
|
||||||
|
def FUNCTIONDEF(self, node):
|
||||||
|
# the decorators attribute is called decorator_list as of Python 2.6
|
||||||
|
if hasattr(node, 'decorators'):
|
||||||
|
for deco in node.decorators:
|
||||||
|
self.handleNode(deco, node)
|
||||||
|
else:
|
||||||
|
for deco in node.decorator_list:
|
||||||
|
self.handleNode(deco, node)
|
||||||
|
self.addBinding(node, FunctionDefinition(node.name, node))
|
||||||
|
self.LAMBDA(node)
|
||||||
|
|
||||||
|
def LAMBDA(self, node):
|
||||||
|
for default in node.args.defaults:
|
||||||
|
self.handleNode(default, node)
|
||||||
|
|
||||||
|
def runFunction():
|
||||||
|
args = []
|
||||||
|
|
||||||
|
def addArgs(arglist):
|
||||||
|
for arg in arglist:
|
||||||
|
if isinstance(arg, _ast.Tuple):
|
||||||
|
addArgs(arg.elts)
|
||||||
|
else:
|
||||||
|
if arg.id in args:
|
||||||
|
self.report(messages.DuplicateArgument,
|
||||||
|
node, arg.id)
|
||||||
|
args.append(arg.id)
|
||||||
|
|
||||||
|
self.pushFunctionScope()
|
||||||
|
addArgs(node.args.args)
|
||||||
|
# vararg/kwarg identifiers are not Name nodes
|
||||||
|
if node.args.vararg:
|
||||||
|
args.append(node.args.vararg)
|
||||||
|
if node.args.kwarg:
|
||||||
|
args.append(node.args.kwarg)
|
||||||
|
for name in args:
|
||||||
|
self.addBinding(node, Argument(name, node), reportRedef=False)
|
||||||
|
if isinstance(node.body, list):
|
||||||
|
# case for FunctionDefs
|
||||||
|
for stmt in node.body:
|
||||||
|
self.handleNode(stmt, node)
|
||||||
|
else:
|
||||||
|
# case for Lambdas
|
||||||
|
self.handleNode(node.body, node)
|
||||||
|
def checkUnusedAssignments():
|
||||||
|
"""
|
||||||
|
Check to see if any assignments have not been used.
|
||||||
|
"""
|
||||||
|
for name, binding in self.scope.iteritems():
|
||||||
|
if (not binding.used and not name in self.scope.globals
|
||||||
|
and isinstance(binding, Assignment)):
|
||||||
|
self.report(messages.UnusedVariable,
|
||||||
|
binding.source, name)
|
||||||
|
self.deferAssignment(checkUnusedAssignments)
|
||||||
|
self.popScope()
|
||||||
|
|
||||||
|
self.deferFunction(runFunction)
|
||||||
|
|
||||||
|
|
||||||
|
def CLASSDEF(self, node):
|
||||||
|
"""
|
||||||
|
Check names used in a class definition, including its decorators, base
|
||||||
|
classes, and the body of its definition. Additionally, add its name to
|
||||||
|
the current scope.
|
||||||
|
"""
|
||||||
|
# decorator_list is present as of Python 2.6
|
||||||
|
for deco in getattr(node, 'decorator_list', []):
|
||||||
|
self.handleNode(deco, node)
|
||||||
|
for baseNode in node.bases:
|
||||||
|
self.handleNode(baseNode, node)
|
||||||
|
self.pushClassScope()
|
||||||
|
for stmt in node.body:
|
||||||
|
self.handleNode(stmt, node)
|
||||||
|
self.popScope()
|
||||||
|
self.addBinding(node, Binding(node.name, node))
|
||||||
|
|
||||||
|
def ASSIGN(self, node):
|
||||||
|
self.handleNode(node.value, node)
|
||||||
|
for target in node.targets:
|
||||||
|
self.handleNode(target, node)
|
||||||
|
|
||||||
|
def AUGASSIGN(self, node):
|
||||||
|
# AugAssign is awkward: must set the context explicitly and visit twice,
|
||||||
|
# once with AugLoad context, once with AugStore context
|
||||||
|
node.target.ctx = _ast.AugLoad()
|
||||||
|
self.handleNode(node.target, node)
|
||||||
|
self.handleNode(node.value, node)
|
||||||
|
node.target.ctx = _ast.AugStore()
|
||||||
|
self.handleNode(node.target, node)
|
||||||
|
|
||||||
|
def IMPORT(self, node):
|
||||||
|
for alias in node.names:
|
||||||
|
name = alias.asname or alias.name
|
||||||
|
importation = Importation(name, node)
|
||||||
|
self.addBinding(node, importation)
|
||||||
|
|
||||||
|
def IMPORTFROM(self, node):
|
||||||
|
if node.module == '__future__':
|
||||||
|
if not self.futuresAllowed:
|
||||||
|
self.report(messages.LateFutureImport, node,
|
||||||
|
[n.name for n in node.names])
|
||||||
|
else:
|
||||||
|
self.futuresAllowed = False
|
||||||
|
|
||||||
|
for alias in node.names:
|
||||||
|
if alias.name == '*':
|
||||||
|
self.scope.importStarred = True
|
||||||
|
self.report(messages.ImportStarUsed, node, node.module)
|
||||||
|
continue
|
||||||
|
name = alias.asname or alias.name
|
||||||
|
importation = Importation(name, node)
|
||||||
|
if node.module == '__future__':
|
||||||
|
importation.used = (self.scope, node)
|
||||||
|
self.addBinding(node, importation)
|
|
@ -0,0 +1,96 @@
|
||||||
|
# (c) 2005 Divmod, Inc. See LICENSE file for details
|
||||||
|
|
||||||
|
class Message(object):
|
||||||
|
message = ''
|
||||||
|
message_args = ()
|
||||||
|
def __init__(self, filename, loc, use_column=True):
|
||||||
|
self.filename = filename
|
||||||
|
self.lineno = loc.lineno
|
||||||
|
self.col = getattr(loc, 'col_offset', None) if use_column else None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s:%s: %s' % (self.filename, self.lineno, self.message % self.message_args)
|
||||||
|
|
||||||
|
|
||||||
|
class UnusedImport(Message):
|
||||||
|
message = '%r imported but unused'
|
||||||
|
def __init__(self, filename, loc, name):
|
||||||
|
Message.__init__(self, filename, loc, use_column=False)
|
||||||
|
self.message_args = (name,)
|
||||||
|
|
||||||
|
|
||||||
|
class RedefinedWhileUnused(Message):
|
||||||
|
message = 'redefinition of unused %r from line %r'
|
||||||
|
def __init__(self, filename, loc, name, orig_loc):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name, orig_loc.lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class ImportShadowedByLoopVar(Message):
|
||||||
|
message = 'import %r from line %r shadowed by loop variable'
|
||||||
|
def __init__(self, filename, loc, name, orig_loc):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name, orig_loc.lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class ImportStarUsed(Message):
|
||||||
|
message = "'from %s import *' used; unable to detect undefined names"
|
||||||
|
def __init__(self, filename, loc, modname):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (modname,)
|
||||||
|
|
||||||
|
|
||||||
|
class UndefinedName(Message):
|
||||||
|
message = 'undefined name %r'
|
||||||
|
def __init__(self, filename, loc, name):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name,)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UndefinedExport(Message):
|
||||||
|
message = 'undefined name %r in __all__'
|
||||||
|
def __init__(self, filename, loc, name):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name,)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UndefinedLocal(Message):
|
||||||
|
message = "local variable %r (defined in enclosing scope on line %r) referenced before assignment"
|
||||||
|
def __init__(self, filename, loc, name, orig_loc):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name, orig_loc.lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateArgument(Message):
|
||||||
|
message = 'duplicate argument %r in function definition'
|
||||||
|
def __init__(self, filename, loc, name):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name,)
|
||||||
|
|
||||||
|
|
||||||
|
class RedefinedFunction(Message):
|
||||||
|
message = 'redefinition of function %r from line %r'
|
||||||
|
def __init__(self, filename, loc, name, orig_loc):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (name, orig_loc.lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class LateFutureImport(Message):
|
||||||
|
message = 'future import(s) %r after other statements'
|
||||||
|
def __init__(self, filename, loc, names):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (names,)
|
||||||
|
|
||||||
|
|
||||||
|
class UnusedVariable(Message):
|
||||||
|
"""
|
||||||
|
Indicates that a variable has been explicity assigned to but not actually
|
||||||
|
used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
message = 'local variable %r is assigned to but never used'
|
||||||
|
def __init__(self, filename, loc, names):
|
||||||
|
Message.__init__(self, filename, loc)
|
||||||
|
self.message_args = (names,)
|
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
"""
|
||||||
|
Implementation of the command-line I{pyflakes} tool.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import _ast
|
||||||
|
|
||||||
|
checker = __import__('pyflakes.checker').checker
|
||||||
|
|
||||||
|
def check(codeString, filename):
|
||||||
|
"""
|
||||||
|
Check the Python source given by C{codeString} for flakes.
|
||||||
|
|
||||||
|
@param codeString: The Python source to check.
|
||||||
|
@type codeString: C{str}
|
||||||
|
|
||||||
|
@param filename: The name of the file the source came from, used to report
|
||||||
|
errors.
|
||||||
|
@type filename: C{str}
|
||||||
|
|
||||||
|
@return: The number of warnings emitted.
|
||||||
|
@rtype: C{int}
|
||||||
|
"""
|
||||||
|
# First, compile into an AST and handle syntax errors.
|
||||||
|
try:
|
||||||
|
tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
|
||||||
|
except SyntaxError, value:
|
||||||
|
msg = value.args[0]
|
||||||
|
|
||||||
|
(lineno, offset, text) = value.lineno, value.offset, value.text
|
||||||
|
|
||||||
|
# If there's an encoding problem with the file, the text is None.
|
||||||
|
if text is None:
|
||||||
|
# Avoid using msg, since for the only known case, it contains a
|
||||||
|
# bogus message that claims the encoding the file declared was
|
||||||
|
# unknown.
|
||||||
|
print >> sys.stderr, "%s: problem decoding source" % (filename, )
|
||||||
|
else:
|
||||||
|
line = text.splitlines()[-1]
|
||||||
|
|
||||||
|
if offset is not None:
|
||||||
|
offset = offset - (len(text) - len(line))
|
||||||
|
|
||||||
|
print >> sys.stderr, '%s:%d: %s' % (filename, lineno, msg)
|
||||||
|
print >> sys.stderr, line
|
||||||
|
|
||||||
|
if offset is not None:
|
||||||
|
print >> sys.stderr, " " * offset, "^"
|
||||||
|
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
# Okay, it's syntactically valid. Now check it.
|
||||||
|
w = checker.Checker(tree, filename)
|
||||||
|
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
|
||||||
|
for warning in w.messages:
|
||||||
|
print warning
|
||||||
|
return len(w.messages)
|
||||||
|
|
||||||
|
|
||||||
|
def checkPath(filename):
|
||||||
|
"""
|
||||||
|
Check the given path, printing out any warnings detected.
|
||||||
|
|
||||||
|
@return: the number of warnings printed
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return check(file(filename, 'U').read() + '\n', filename)
|
||||||
|
except IOError, msg:
|
||||||
|
print >> sys.stderr, "%s: %s" % (filename, msg.args[1])
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
warnings = 0
|
||||||
|
args = sys.argv[1:]
|
||||||
|
if args:
|
||||||
|
for arg in args:
|
||||||
|
if os.path.isdir(arg):
|
||||||
|
for dirpath, dirnames, filenames in os.walk(arg):
|
||||||
|
for filename in filenames:
|
||||||
|
if filename.endswith('.py'):
|
||||||
|
warnings += checkPath(os.path.join(dirpath, filename))
|
||||||
|
else:
|
||||||
|
warnings += checkPath(arg)
|
||||||
|
else:
|
||||||
|
warnings += check(sys.stdin.read(), '<stdin>')
|
||||||
|
|
||||||
|
raise SystemExit(warnings > 0)
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
import textwrap
|
||||||
|
import _ast
|
||||||
|
|
||||||
|
from twisted.trial import unittest
|
||||||
|
|
||||||
|
from pyflakes import checker
|
||||||
|
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def flakes(self, input, *expectedOutputs, **kw):
|
||||||
|
ast = compile(textwrap.dedent(input), "<test>", "exec",
|
||||||
|
_ast.PyCF_ONLY_AST)
|
||||||
|
w = checker.Checker(ast, **kw)
|
||||||
|
outputs = [type(o) for o in w.messages]
|
||||||
|
expectedOutputs = list(expectedOutputs)
|
||||||
|
outputs.sort()
|
||||||
|
expectedOutputs.sort()
|
||||||
|
self.assert_(outputs == expectedOutputs, '''\
|
||||||
|
for input:
|
||||||
|
%s
|
||||||
|
expected outputs:
|
||||||
|
%s
|
||||||
|
but got:
|
||||||
|
%s''' % (input, repr(expectedOutputs), '\n'.join([str(o) for o in w.messages])))
|
||||||
|
return w
|
|
@ -0,0 +1,673 @@
|
||||||
|
|
||||||
|
from sys import version_info
|
||||||
|
|
||||||
|
from pyflakes import messages as m
|
||||||
|
from pyflakes.test import harness
|
||||||
|
|
||||||
|
class Test(harness.Test):
|
||||||
|
|
||||||
|
def test_unusedImport(self):
|
||||||
|
self.flakes('import fu, bar', m.UnusedImport, m.UnusedImport)
|
||||||
|
self.flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport)
|
||||||
|
|
||||||
|
def test_aliasedImport(self):
|
||||||
|
self.flakes('import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
|
||||||
|
self.flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
|
||||||
|
|
||||||
|
def test_usedImport(self):
|
||||||
|
self.flakes('import fu; print fu')
|
||||||
|
self.flakes('from baz import fu; print fu')
|
||||||
|
|
||||||
|
def test_redefinedWhileUnused(self):
|
||||||
|
self.flakes('import fu; fu = 3', m.RedefinedWhileUnused)
|
||||||
|
self.flakes('import fu; del fu', m.RedefinedWhileUnused)
|
||||||
|
self.flakes('import fu; fu, bar = 3', m.RedefinedWhileUnused)
|
||||||
|
self.flakes('import fu; [fu, bar] = 3', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
def test_redefinedByFunction(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def fu():
|
||||||
|
pass
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
def test_redefinedInNestedFunction(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a global name with a nested function definition
|
||||||
|
generates a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def bar():
|
||||||
|
def baz():
|
||||||
|
def fu():
|
||||||
|
pass
|
||||||
|
''', m.RedefinedWhileUnused, m.UnusedImport)
|
||||||
|
|
||||||
|
def test_redefinedByClass(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
class fu:
|
||||||
|
pass
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
|
||||||
|
def test_redefinedBySubclass(self):
|
||||||
|
"""
|
||||||
|
If an imported name is redefined by a class statement which also uses
|
||||||
|
that name in the bases list, no warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from fu import bar
|
||||||
|
class bar(bar):
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_redefinedInClass(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a global with a class attribute does not produce a
|
||||||
|
warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
class bar:
|
||||||
|
fu = 1
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInFunction(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def fun():
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_shadowedByParameter(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def fun(fu):
|
||||||
|
print fu
|
||||||
|
''', m.UnusedImport)
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def fun(fu):
|
||||||
|
print fu
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_newAssignment(self):
|
||||||
|
self.flakes('fu = None')
|
||||||
|
|
||||||
|
def test_usedInGetattr(self):
|
||||||
|
self.flakes('import fu; fu.bar.baz')
|
||||||
|
self.flakes('import fu; "bar".fu.baz', m.UnusedImport)
|
||||||
|
|
||||||
|
def test_usedInSlice(self):
|
||||||
|
self.flakes('import fu; print fu.bar[1:]')
|
||||||
|
|
||||||
|
def test_usedInIfBody(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
if True: print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInIfConditional(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
if fu: pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInElifConditional(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
if False: pass
|
||||||
|
elif fu: pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInElse(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
if False: pass
|
||||||
|
else: print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInCall(self):
|
||||||
|
self.flakes('import fu; fu.bar()')
|
||||||
|
|
||||||
|
def test_usedInClass(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
class bar:
|
||||||
|
bar = fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInClassBase(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
class bar(object, fu.baz):
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_notUsedInNestedScope(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def bleh():
|
||||||
|
pass
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInFor(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
for bar in range(9):
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInForElse(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
for bar in range(10):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_redefinedByFor(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
for fu in range(2):
|
||||||
|
pass
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
def test_shadowedByFor(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a global name with a for loop variable generates a
|
||||||
|
warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
fu.bar()
|
||||||
|
for fu in ():
|
||||||
|
pass
|
||||||
|
''', m.ImportShadowedByLoopVar)
|
||||||
|
|
||||||
|
def test_shadowedByForDeep(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a global name with a for loop variable nested in a
|
||||||
|
tuple unpack generates a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
fu.bar()
|
||||||
|
for (x, y, z, (a, b, c, (fu,))) in ():
|
||||||
|
pass
|
||||||
|
''', m.ImportShadowedByLoopVar)
|
||||||
|
|
||||||
|
def test_usedInReturn(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def fun():
|
||||||
|
return fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInOperators(self):
|
||||||
|
self.flakes('import fu; 3 + fu.bar')
|
||||||
|
self.flakes('import fu; 3 % fu.bar')
|
||||||
|
self.flakes('import fu; 3 - fu.bar')
|
||||||
|
self.flakes('import fu; 3 * fu.bar')
|
||||||
|
self.flakes('import fu; 3 ** fu.bar')
|
||||||
|
self.flakes('import fu; 3 / fu.bar')
|
||||||
|
self.flakes('import fu; 3 // fu.bar')
|
||||||
|
self.flakes('import fu; -fu.bar')
|
||||||
|
self.flakes('import fu; ~fu.bar')
|
||||||
|
self.flakes('import fu; 1 == fu.bar')
|
||||||
|
self.flakes('import fu; 1 | fu.bar')
|
||||||
|
self.flakes('import fu; 1 & fu.bar')
|
||||||
|
self.flakes('import fu; 1 ^ fu.bar')
|
||||||
|
self.flakes('import fu; 1 >> fu.bar')
|
||||||
|
self.flakes('import fu; 1 << fu.bar')
|
||||||
|
|
||||||
|
def test_usedInAssert(self):
|
||||||
|
self.flakes('import fu; assert fu.bar')
|
||||||
|
|
||||||
|
def test_usedInSubscript(self):
|
||||||
|
self.flakes('import fu; fu.bar[1]')
|
||||||
|
|
||||||
|
def test_usedInLogic(self):
|
||||||
|
self.flakes('import fu; fu and False')
|
||||||
|
self.flakes('import fu; fu or False')
|
||||||
|
self.flakes('import fu; not fu.bar')
|
||||||
|
|
||||||
|
def test_usedInList(self):
|
||||||
|
self.flakes('import fu; [fu]')
|
||||||
|
|
||||||
|
def test_usedInTuple(self):
|
||||||
|
self.flakes('import fu; (fu,)')
|
||||||
|
|
||||||
|
def test_usedInTry(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
try: fu
|
||||||
|
except: pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInExcept(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
try: fu
|
||||||
|
except: pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_redefinedByExcept(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
try: pass
|
||||||
|
except Exception, fu: pass
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
def test_usedInRaise(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
raise fu.bar
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInYield(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def gen():
|
||||||
|
yield fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInDict(self):
|
||||||
|
self.flakes('import fu; {fu:None}')
|
||||||
|
self.flakes('import fu; {1:fu}')
|
||||||
|
|
||||||
|
def test_usedInParameterDefault(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def f(bar=fu):
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInAttributeAssign(self):
|
||||||
|
self.flakes('import fu; fu.bar = 1')
|
||||||
|
|
||||||
|
def test_usedInKeywordArg(self):
|
||||||
|
self.flakes('import fu; fu.bar(stuff=fu)')
|
||||||
|
|
||||||
|
def test_usedInAssignment(self):
|
||||||
|
self.flakes('import fu; bar=fu')
|
||||||
|
self.flakes('import fu; n=0; n+=fu')
|
||||||
|
|
||||||
|
def test_usedInListComp(self):
|
||||||
|
self.flakes('import fu; [fu for _ in range(1)]')
|
||||||
|
self.flakes('import fu; [1 for _ in range(1) if fu]')
|
||||||
|
|
||||||
|
def test_redefinedByListComp(self):
|
||||||
|
self.flakes('import fu; [1 for fu in range(1)]', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
|
||||||
|
def test_usedInTryFinally(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
try: pass
|
||||||
|
finally: fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
try: fu
|
||||||
|
finally: pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInWhile(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
while 0:
|
||||||
|
fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
while fu: pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_usedInGlobal(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def f(): global fu
|
||||||
|
''', m.UnusedImport)
|
||||||
|
|
||||||
|
def test_usedInBackquote(self):
|
||||||
|
self.flakes('import fu; `fu`')
|
||||||
|
|
||||||
|
def test_usedInExec(self):
|
||||||
|
self.flakes('import fu; exec "print 1" in fu.bar')
|
||||||
|
|
||||||
|
def test_usedInLambda(self):
|
||||||
|
self.flakes('import fu; lambda: fu')
|
||||||
|
|
||||||
|
def test_shadowedByLambda(self):
|
||||||
|
self.flakes('import fu; lambda fu: fu', m.UnusedImport)
|
||||||
|
|
||||||
|
def test_usedInSliceObj(self):
|
||||||
|
self.flakes('import fu; "meow"[::fu]')
|
||||||
|
|
||||||
|
def test_unusedInNestedScope(self):
|
||||||
|
self.flakes('''
|
||||||
|
def bar():
|
||||||
|
import fu
|
||||||
|
fu
|
||||||
|
''', m.UnusedImport, m.UndefinedName)
|
||||||
|
|
||||||
|
def test_methodsDontUseClassScope(self):
|
||||||
|
self.flakes('''
|
||||||
|
class bar:
|
||||||
|
import fu
|
||||||
|
def fun(self):
|
||||||
|
fu
|
||||||
|
''', m.UnusedImport, m.UndefinedName)
|
||||||
|
|
||||||
|
def test_nestedFunctionsNestScope(self):
|
||||||
|
self.flakes('''
|
||||||
|
def a():
|
||||||
|
def b():
|
||||||
|
fu
|
||||||
|
import fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_nestedClassAndFunctionScope(self):
|
||||||
|
self.flakes('''
|
||||||
|
def a():
|
||||||
|
import fu
|
||||||
|
class b:
|
||||||
|
def c(self):
|
||||||
|
print fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_importStar(self):
|
||||||
|
self.flakes('from fu import *', m.ImportStarUsed)
|
||||||
|
|
||||||
|
|
||||||
|
def test_packageImport(self):
|
||||||
|
"""
|
||||||
|
If a dotted name is imported and used, no warning is reported.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu.bar
|
||||||
|
fu.bar
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_unusedPackageImport(self):
|
||||||
|
"""
|
||||||
|
If a dotted name is imported and not used, an unused import warning is
|
||||||
|
reported.
|
||||||
|
"""
|
||||||
|
self.flakes('import fu.bar', m.UnusedImport)
|
||||||
|
|
||||||
|
|
||||||
|
def test_duplicateSubmoduleImport(self):
|
||||||
|
"""
|
||||||
|
If a submodule of a package is imported twice, an unused import warning
|
||||||
|
and a redefined while unused warning are reported.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu.bar, fu.bar
|
||||||
|
fu.bar
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
self.flakes('''
|
||||||
|
import fu.bar
|
||||||
|
import fu.bar
|
||||||
|
fu.bar
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
|
||||||
|
def test_differentSubmoduleImport(self):
|
||||||
|
"""
|
||||||
|
If two different submodules of a package are imported, no duplicate
|
||||||
|
import warning is reported for the package.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import fu.bar, fu.baz
|
||||||
|
fu.bar, fu.baz
|
||||||
|
''')
|
||||||
|
self.flakes('''
|
||||||
|
import fu.bar
|
||||||
|
import fu.baz
|
||||||
|
fu.bar, fu.baz
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_assignRHSFirst(self):
|
||||||
|
self.flakes('import fu; fu = fu')
|
||||||
|
self.flakes('import fu; fu, bar = fu')
|
||||||
|
self.flakes('import fu; [fu, bar] = fu')
|
||||||
|
self.flakes('import fu; fu += fu')
|
||||||
|
|
||||||
|
def test_tryingMultipleImports(self):
|
||||||
|
self.flakes('''
|
||||||
|
try:
|
||||||
|
import fu
|
||||||
|
except ImportError:
|
||||||
|
import bar as fu
|
||||||
|
''')
|
||||||
|
test_tryingMultipleImports.todo = ''
|
||||||
|
|
||||||
|
def test_nonGlobalDoesNotRedefine(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def a():
|
||||||
|
fu = 3
|
||||||
|
return fu
|
||||||
|
fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_functionsRunLater(self):
|
||||||
|
self.flakes('''
|
||||||
|
def a():
|
||||||
|
fu
|
||||||
|
import fu
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_functionNamesAreBoundNow(self):
|
||||||
|
self.flakes('''
|
||||||
|
import fu
|
||||||
|
def fu():
|
||||||
|
fu
|
||||||
|
fu
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
def test_ignoreNonImportRedefinitions(self):
|
||||||
|
self.flakes('a = 1; a = 2')
|
||||||
|
|
||||||
|
def test_importingForImportError(self):
|
||||||
|
self.flakes('''
|
||||||
|
try:
|
||||||
|
import fu
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
test_importingForImportError.todo = ''
|
||||||
|
|
||||||
|
def test_importedInClass(self):
|
||||||
|
'''Imports in class scope can be used through self'''
|
||||||
|
self.flakes('''
|
||||||
|
class c:
|
||||||
|
import i
|
||||||
|
def __init__(self):
|
||||||
|
self.i
|
||||||
|
''')
|
||||||
|
test_importedInClass.todo = 'requires evaluating attribute access'
|
||||||
|
|
||||||
|
def test_futureImport(self):
|
||||||
|
'''__future__ is special'''
|
||||||
|
self.flakes('from __future__ import division')
|
||||||
|
self.flakes('''
|
||||||
|
"docstring is allowed before future import"
|
||||||
|
from __future__ import division
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_futureImportFirst(self):
|
||||||
|
"""
|
||||||
|
__future__ imports must come before anything else.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
x = 5
|
||||||
|
from __future__ import division
|
||||||
|
''', m.LateFutureImport)
|
||||||
|
self.flakes('''
|
||||||
|
from foo import bar
|
||||||
|
from __future__ import division
|
||||||
|
bar
|
||||||
|
''', m.LateFutureImport)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestSpecialAll(harness.Test):
|
||||||
|
"""
|
||||||
|
Tests for suppression of unused import warnings by C{__all__}.
|
||||||
|
"""
|
||||||
|
def test_ignoredInFunction(self):
|
||||||
|
"""
|
||||||
|
An C{__all__} definition does not suppress unused import warnings in a
|
||||||
|
function scope.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def foo():
|
||||||
|
import bar
|
||||||
|
__all__ = ["bar"]
|
||||||
|
''', m.UnusedImport, m.UnusedVariable)
|
||||||
|
|
||||||
|
|
||||||
|
def test_ignoredInClass(self):
|
||||||
|
"""
|
||||||
|
An C{__all__} definition does not suppress unused import warnings in a
|
||||||
|
class scope.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
class foo:
|
||||||
|
import bar
|
||||||
|
__all__ = ["bar"]
|
||||||
|
''', m.UnusedImport)
|
||||||
|
|
||||||
|
|
||||||
|
def test_warningSuppressed(self):
|
||||||
|
"""
|
||||||
|
If a name is imported and unused but is named in C{__all__}, no warning
|
||||||
|
is reported.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import foo
|
||||||
|
__all__ = ["foo"]
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_unrecognizable(self):
|
||||||
|
"""
|
||||||
|
If C{__all__} is defined in a way that can't be recognized statically,
|
||||||
|
it is ignored.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
import foo
|
||||||
|
__all__ = ["f" + "oo"]
|
||||||
|
''', m.UnusedImport)
|
||||||
|
self.flakes('''
|
||||||
|
import foo
|
||||||
|
__all__ = [] + ["foo"]
|
||||||
|
''', m.UnusedImport)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unboundExported(self):
|
||||||
|
"""
|
||||||
|
If C{__all__} includes a name which is not bound, a warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
__all__ = ["foo"]
|
||||||
|
''', m.UndefinedExport)
|
||||||
|
|
||||||
|
# Skip this in __init__.py though, since the rules there are a little
|
||||||
|
# different.
|
||||||
|
for filename in ["foo/__init__.py", "__init__.py"]:
|
||||||
|
self.flakes('''
|
||||||
|
__all__ = ["foo"]
|
||||||
|
''', filename=filename)
|
||||||
|
|
||||||
|
|
||||||
|
def test_usedInGenExp(self):
|
||||||
|
"""
|
||||||
|
Using a global in a generator expression results in no warnings.
|
||||||
|
"""
|
||||||
|
self.flakes('import fu; (fu for _ in range(1))')
|
||||||
|
self.flakes('import fu; (1 for _ in range(1) if fu)')
|
||||||
|
|
||||||
|
|
||||||
|
def test_redefinedByGenExp(self):
|
||||||
|
"""
|
||||||
|
Re-using a global name as the loop variable for a generator
|
||||||
|
expression results in a redefinition warning.
|
||||||
|
"""
|
||||||
|
self.flakes('import fu; (1 for fu in range(1))', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
|
||||||
|
def test_usedAsDecorator(self):
|
||||||
|
"""
|
||||||
|
Using a global name in a decorator statement results in no warnings,
|
||||||
|
but using an undefined name in a decorator statement results in an
|
||||||
|
undefined name warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from interior import decorate
|
||||||
|
@decorate
|
||||||
|
def f():
|
||||||
|
return "hello"
|
||||||
|
''')
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
from interior import decorate
|
||||||
|
@decorate('value')
|
||||||
|
def f():
|
||||||
|
return "hello"
|
||||||
|
''')
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
@decorate
|
||||||
|
def f():
|
||||||
|
return "hello"
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
class Python26Tests(harness.Test):
|
||||||
|
"""
|
||||||
|
Tests for checking of syntax which is valid in PYthon 2.6 and newer.
|
||||||
|
"""
|
||||||
|
if version_info < (2, 6):
|
||||||
|
skip = "Python 2.6 required for class decorator tests."
|
||||||
|
|
||||||
|
|
||||||
|
def test_usedAsClassDecorator(self):
|
||||||
|
"""
|
||||||
|
Using an imported name as a class decorator results in no warnings,
|
||||||
|
but using an undefined name as a class decorator results in an
|
||||||
|
undefined name warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from interior import decorate
|
||||||
|
@decorate
|
||||||
|
class foo:
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
from interior import decorate
|
||||||
|
@decorate("foo")
|
||||||
|
class bar:
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
@decorate
|
||||||
|
class foo:
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
|
@ -0,0 +1,575 @@
|
||||||
|
# (c) 2005-2010 Divmod, Inc.
|
||||||
|
# See LICENSE file for details
|
||||||
|
|
||||||
|
"""
|
||||||
|
Tests for various Pyflakes behavior.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sys import version_info
|
||||||
|
|
||||||
|
from pyflakes import messages as m
|
||||||
|
from pyflakes.test import harness
|
||||||
|
|
||||||
|
|
||||||
|
class Test(harness.Test):
|
||||||
|
|
||||||
|
def test_duplicateArgs(self):
|
||||||
|
self.flakes('def fu(bar, bar): pass', m.DuplicateArgument)
|
||||||
|
|
||||||
|
def test_localReferencedBeforeAssignment(self):
|
||||||
|
self.flakes('''
|
||||||
|
a = 1
|
||||||
|
def f():
|
||||||
|
a; a=1
|
||||||
|
f()
|
||||||
|
''', m.UndefinedName)
|
||||||
|
test_localReferencedBeforeAssignment.todo = 'this requires finding all assignments in the function body first'
|
||||||
|
|
||||||
|
def test_redefinedFunction(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a function definition with another one raises a
|
||||||
|
warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def a(): pass
|
||||||
|
def a(): pass
|
||||||
|
''', m.RedefinedFunction)
|
||||||
|
|
||||||
|
def test_redefinedClassFunction(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a function definition in a class suite with another
|
||||||
|
one raises a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
class A:
|
||||||
|
def a(): pass
|
||||||
|
def a(): pass
|
||||||
|
''', m.RedefinedFunction)
|
||||||
|
|
||||||
|
def test_functionDecorator(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a function definition with a decorated version of
|
||||||
|
that function does not raise a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from somewhere import somedecorator
|
||||||
|
|
||||||
|
def a(): pass
|
||||||
|
a = somedecorator(a)
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_classFunctionDecorator(self):
|
||||||
|
"""
|
||||||
|
Test that shadowing a function definition in a class suite with a
|
||||||
|
decorated version of that function does not raise a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
class A:
|
||||||
|
def a(): pass
|
||||||
|
a = classmethod(a)
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_unaryPlus(self):
|
||||||
|
'''Don't die on unary +'''
|
||||||
|
self.flakes('+1')
|
||||||
|
|
||||||
|
|
||||||
|
def test_undefinedBaseClass(self):
|
||||||
|
"""
|
||||||
|
If a name in the base list of a class definition is undefined, a
|
||||||
|
warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
class foo(foo):
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_classNameUndefinedInClassBody(self):
|
||||||
|
"""
|
||||||
|
If a class name is used in the body of that class's definition and
|
||||||
|
the name is not already defined, a warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
class foo:
|
||||||
|
foo
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_classNameDefinedPreviously(self):
|
||||||
|
"""
|
||||||
|
If a class name is used in the body of that class's definition and
|
||||||
|
the name was previously defined in some other way, no warning is
|
||||||
|
emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
foo = None
|
||||||
|
class foo:
|
||||||
|
foo
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_comparison(self):
|
||||||
|
"""
|
||||||
|
If a defined name is used on either side of any of the six comparison
|
||||||
|
operators, no warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
x = 10
|
||||||
|
y = 20
|
||||||
|
x < y
|
||||||
|
x <= y
|
||||||
|
x == y
|
||||||
|
x != y
|
||||||
|
x >= y
|
||||||
|
x > y
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_identity(self):
|
||||||
|
"""
|
||||||
|
If a deefined name is used on either side of an identity test, no
|
||||||
|
warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
x = 10
|
||||||
|
y = 20
|
||||||
|
x is y
|
||||||
|
x is not y
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_containment(self):
|
||||||
|
"""
|
||||||
|
If a defined name is used on either side of a containment test, no
|
||||||
|
warning is emitted.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
x = 10
|
||||||
|
y = 20
|
||||||
|
x in y
|
||||||
|
x not in y
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_loopControl(self):
|
||||||
|
"""
|
||||||
|
break and continue statements are supported.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
for x in [1, 2]:
|
||||||
|
break
|
||||||
|
''')
|
||||||
|
self.flakes('''
|
||||||
|
for x in [1, 2]:
|
||||||
|
continue
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_ellipsis(self):
|
||||||
|
"""
|
||||||
|
Ellipsis in a slice is supported.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
[1, 2][...]
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_extendedSlice(self):
|
||||||
|
"""
|
||||||
|
Extended slices are supported.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
x = 3
|
||||||
|
[1, 2][x,:]
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnusedAssignment(harness.Test):
|
||||||
|
"""
|
||||||
|
Tests for warning about unused assignments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_unusedVariable(self):
|
||||||
|
"""
|
||||||
|
Warn when a variable in a function is assigned a value that's never
|
||||||
|
used.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def a():
|
||||||
|
b = 1
|
||||||
|
''', m.UnusedVariable)
|
||||||
|
|
||||||
|
|
||||||
|
def test_assignToGlobal(self):
|
||||||
|
"""
|
||||||
|
Assigning to a global and then not using that global is perfectly
|
||||||
|
acceptable. Do not mistake it for an unused local variable.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
b = 0
|
||||||
|
def a():
|
||||||
|
global b
|
||||||
|
b = 1
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_assignToMember(self):
|
||||||
|
"""
|
||||||
|
Assigning to a member of another object and then not using that member
|
||||||
|
variable is perfectly acceptable. Do not mistake it for an unused
|
||||||
|
local variable.
|
||||||
|
"""
|
||||||
|
# XXX: Adding this test didn't generate a failure. Maybe not
|
||||||
|
# necessary?
|
||||||
|
self.flakes('''
|
||||||
|
class b:
|
||||||
|
pass
|
||||||
|
def a():
|
||||||
|
b.foo = 1
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_assignInForLoop(self):
|
||||||
|
"""
|
||||||
|
Don't warn when a variable in a for loop is assigned to but not used.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
for i in range(10):
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_assignInListComprehension(self):
|
||||||
|
"""
|
||||||
|
Don't warn when a variable in a list comprehension is assigned to but
|
||||||
|
not used.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
[None for i in range(10)]
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_generatorExpression(self):
|
||||||
|
"""
|
||||||
|
Don't warn when a variable in a generator expression is assigned to but not used.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
(None for i in range(10))
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_assignmentInsideLoop(self):
|
||||||
|
"""
|
||||||
|
Don't warn when a variable assignment occurs lexically after its use.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
x = None
|
||||||
|
for i in range(10):
|
||||||
|
if i > 2:
|
||||||
|
return x
|
||||||
|
x = i * 2
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_tupleUnpacking(self):
|
||||||
|
"""
|
||||||
|
Don't warn when a variable included in tuple unpacking is unused. It's
|
||||||
|
very common for variables in a tuple unpacking assignment to be unused
|
||||||
|
in good Python code, so warning will only create false positives.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
(x, y) = 1, 2
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_listUnpacking(self):
|
||||||
|
"""
|
||||||
|
Don't warn when a variable included in list unpacking is unused.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
[x, y] = [1, 2]
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_closedOver(self):
|
||||||
|
"""
|
||||||
|
Don't warn when the assignment is used in an inner function.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def barMaker():
|
||||||
|
foo = 5
|
||||||
|
def bar():
|
||||||
|
return foo
|
||||||
|
return bar
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_doubleClosedOver(self):
|
||||||
|
"""
|
||||||
|
Don't warn when the assignment is used in an inner function, even if
|
||||||
|
that inner function itself is in an inner function.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def barMaker():
|
||||||
|
foo = 5
|
||||||
|
def bar():
|
||||||
|
def baz():
|
||||||
|
return foo
|
||||||
|
return bar
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Python25Test(harness.Test):
|
||||||
|
"""
|
||||||
|
Tests for checking of syntax only available in Python 2.5 and newer.
|
||||||
|
"""
|
||||||
|
if version_info < (2, 5):
|
||||||
|
skip = "Python 2.5 required for if-else and with tests"
|
||||||
|
|
||||||
|
def test_ifexp(self):
|
||||||
|
"""
|
||||||
|
Test C{foo if bar else baz} statements.
|
||||||
|
"""
|
||||||
|
self.flakes("a = 'moo' if True else 'oink'")
|
||||||
|
self.flakes("a = foo if True else 'oink'", m.UndefinedName)
|
||||||
|
self.flakes("a = 'moo' if True else bar", m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementNoNames(self):
|
||||||
|
"""
|
||||||
|
No warnings are emitted for using inside or after a nameless C{with}
|
||||||
|
statement a name defined beforehand.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
bar = None
|
||||||
|
with open("foo"):
|
||||||
|
bar
|
||||||
|
bar
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_withStatementSingleName(self):
|
||||||
|
"""
|
||||||
|
No warnings are emitted for using a name defined by a C{with} statement
|
||||||
|
within the suite or afterwards.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with open('foo') as bar:
|
||||||
|
bar
|
||||||
|
bar
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementAttributeName(self):
|
||||||
|
"""
|
||||||
|
No warnings are emitted for using an attribute as the target of a
|
||||||
|
C{with} statement.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
import foo
|
||||||
|
with open('foo') as foo.bar:
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementSubscript(self):
|
||||||
|
"""
|
||||||
|
No warnings are emitted for using a subscript as the target of a
|
||||||
|
C{with} statement.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
import foo
|
||||||
|
with open('foo') as foo[0]:
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementSubscriptUndefined(self):
|
||||||
|
"""
|
||||||
|
An undefined name warning is emitted if the subscript used as the
|
||||||
|
target of a C{with} statement is not defined.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
import foo
|
||||||
|
with open('foo') as foo[bar]:
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementTupleNames(self):
|
||||||
|
"""
|
||||||
|
No warnings are emitted for using any of the tuple of names defined by
|
||||||
|
a C{with} statement within the suite or afterwards.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with open('foo') as (bar, baz):
|
||||||
|
bar, baz
|
||||||
|
bar, baz
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementListNames(self):
|
||||||
|
"""
|
||||||
|
No warnings are emitted for using any of the list of names defined by a
|
||||||
|
C{with} statement within the suite or afterwards.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with open('foo') as [bar, baz]:
|
||||||
|
bar, baz
|
||||||
|
bar, baz
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementComplicatedTarget(self):
|
||||||
|
"""
|
||||||
|
If the target of a C{with} statement uses any or all of the valid forms
|
||||||
|
for that part of the grammar (See
|
||||||
|
U{http://docs.python.org/reference/compound_stmts.html#the-with-statement}),
|
||||||
|
the names involved are checked both for definedness and any bindings
|
||||||
|
created are respected in the suite of the statement and afterwards.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
c = d = e = g = h = i = None
|
||||||
|
with open('foo') as [(a, b), c[d], e.f, g[h:i]]:
|
||||||
|
a, b, c, d, e, g, h, i
|
||||||
|
a, b, c, d, e, g, h, i
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementSingleNameUndefined(self):
|
||||||
|
"""
|
||||||
|
An undefined name warning is emitted if the name first defined by a
|
||||||
|
C{with} statement is used before the C{with} statement.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
bar
|
||||||
|
with open('foo') as bar:
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementTupleNamesUndefined(self):
|
||||||
|
"""
|
||||||
|
An undefined name warning is emitted if a name first defined by a the
|
||||||
|
tuple-unpacking form of the C{with} statement is used before the
|
||||||
|
C{with} statement.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
baz
|
||||||
|
with open('foo') as (bar, baz):
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementSingleNameRedefined(self):
|
||||||
|
"""
|
||||||
|
A redefined name warning is emitted if a name bound by an import is
|
||||||
|
rebound by the name defined by a C{with} statement.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
import bar
|
||||||
|
with open('foo') as bar:
|
||||||
|
pass
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementTupleNamesRedefined(self):
|
||||||
|
"""
|
||||||
|
A redefined name warning is emitted if a name bound by an import is
|
||||||
|
rebound by one of the names defined by the tuple-unpacking form of a
|
||||||
|
C{with} statement.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
import bar
|
||||||
|
with open('foo') as (bar, baz):
|
||||||
|
pass
|
||||||
|
''', m.RedefinedWhileUnused)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementUndefinedInside(self):
|
||||||
|
"""
|
||||||
|
An undefined name warning is emitted if a name is used inside the
|
||||||
|
body of a C{with} statement without first being bound.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with open('foo') as bar:
|
||||||
|
baz
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementNameDefinedInBody(self):
|
||||||
|
"""
|
||||||
|
A name defined in the body of a C{with} statement can be used after
|
||||||
|
the body ends without warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with open('foo') as bar:
|
||||||
|
baz = 10
|
||||||
|
baz
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def test_withStatementUndefinedInExpression(self):
|
||||||
|
"""
|
||||||
|
An undefined name warning is emitted if a name in the I{test}
|
||||||
|
expression of a C{with} statement is undefined.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with bar as baz:
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
self.flakes('''
|
||||||
|
from __future__ import with_statement
|
||||||
|
with bar as bar:
|
||||||
|
pass
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Python27Test(harness.Test):
|
||||||
|
"""
|
||||||
|
Tests for checking of syntax only available in Python 2.7 and newer.
|
||||||
|
"""
|
||||||
|
if version_info < (2, 7):
|
||||||
|
skip = "Python 2.7 required for dict/set comprehension tests"
|
||||||
|
|
||||||
|
def test_dictComprehension(self):
|
||||||
|
"""
|
||||||
|
Dict comprehensions are properly handled.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
a = {1: x for x in range(10)}
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_setComprehensionAndLiteral(self):
|
||||||
|
"""
|
||||||
|
Set comprehensions are properly handled.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
a = {1, 2, 3}
|
||||||
|
b = {x for x in range(10)}
|
||||||
|
''')
|
|
@ -0,0 +1,185 @@
|
||||||
|
|
||||||
|
"""
|
||||||
|
Tests for L{pyflakes.scripts.pyflakes}.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
from twisted.python.filepath import FilePath
|
||||||
|
from twisted.trial.unittest import TestCase
|
||||||
|
|
||||||
|
from pyflakes.scripts.pyflakes import checkPath
|
||||||
|
|
||||||
|
def withStderrTo(stderr, f):
|
||||||
|
"""
|
||||||
|
Call C{f} with C{sys.stderr} redirected to C{stderr}.
|
||||||
|
"""
|
||||||
|
(outer, sys.stderr) = (sys.stderr, stderr)
|
||||||
|
try:
|
||||||
|
return f()
|
||||||
|
finally:
|
||||||
|
sys.stderr = outer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CheckTests(TestCase):
|
||||||
|
"""
|
||||||
|
Tests for L{check} and L{checkPath} which check a file for flakes.
|
||||||
|
"""
|
||||||
|
def test_missingTrailingNewline(self):
|
||||||
|
"""
|
||||||
|
Source which doesn't end with a newline shouldn't cause any
|
||||||
|
exception to be raised nor an error indicator to be returned by
|
||||||
|
L{check}.
|
||||||
|
"""
|
||||||
|
fName = self.mktemp()
|
||||||
|
FilePath(fName).setContent("def foo():\n\tpass\n\t")
|
||||||
|
self.assertFalse(checkPath(fName))
|
||||||
|
|
||||||
|
|
||||||
|
def test_checkPathNonExisting(self):
|
||||||
|
"""
|
||||||
|
L{checkPath} handles non-existing files.
|
||||||
|
"""
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath('extremo'))
|
||||||
|
self.assertEquals(err.getvalue(), 'extremo: No such file or directory\n')
|
||||||
|
self.assertEquals(count, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_multilineSyntaxError(self):
|
||||||
|
"""
|
||||||
|
Source which includes a syntax error which results in the raised
|
||||||
|
L{SyntaxError.text} containing multiple lines of source are reported
|
||||||
|
with only the last line of that source.
|
||||||
|
"""
|
||||||
|
source = """\
|
||||||
|
def foo():
|
||||||
|
'''
|
||||||
|
|
||||||
|
def bar():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
'''quux'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Sanity check - SyntaxError.text should be multiple lines, if it
|
||||||
|
# isn't, something this test was unprepared for has happened.
|
||||||
|
def evaluate(source):
|
||||||
|
exec source
|
||||||
|
exc = self.assertRaises(SyntaxError, evaluate, source)
|
||||||
|
self.assertTrue(exc.text.count('\n') > 1)
|
||||||
|
|
||||||
|
sourcePath = FilePath(self.mktemp())
|
||||||
|
sourcePath.setContent(source)
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
|
||||||
|
self.assertEqual(count, 1)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
err.getvalue(),
|
||||||
|
"""\
|
||||||
|
%s:8: invalid syntax
|
||||||
|
'''quux'''
|
||||||
|
^
|
||||||
|
""" % (sourcePath.path,))
|
||||||
|
|
||||||
|
|
||||||
|
def test_eofSyntaxError(self):
|
||||||
|
"""
|
||||||
|
The error reported for source files which end prematurely causing a
|
||||||
|
syntax error reflects the cause for the syntax error.
|
||||||
|
"""
|
||||||
|
source = "def foo("
|
||||||
|
sourcePath = FilePath(self.mktemp())
|
||||||
|
sourcePath.setContent(source)
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
|
||||||
|
self.assertEqual(count, 1)
|
||||||
|
self.assertEqual(
|
||||||
|
err.getvalue(),
|
||||||
|
"""\
|
||||||
|
%s:1: unexpected EOF while parsing
|
||||||
|
def foo(
|
||||||
|
^
|
||||||
|
""" % (sourcePath.path,))
|
||||||
|
|
||||||
|
|
||||||
|
def test_nonDefaultFollowsDefaultSyntaxError(self):
|
||||||
|
"""
|
||||||
|
Source which has a non-default argument following a default argument
|
||||||
|
should include the line number of the syntax error. However these
|
||||||
|
exceptions do not include an offset.
|
||||||
|
"""
|
||||||
|
source = """\
|
||||||
|
def foo(bar=baz, bax):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
sourcePath = FilePath(self.mktemp())
|
||||||
|
sourcePath.setContent(source)
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
|
||||||
|
self.assertEqual(count, 1)
|
||||||
|
self.assertEqual(
|
||||||
|
err.getvalue(),
|
||||||
|
"""\
|
||||||
|
%s:1: non-default argument follows default argument
|
||||||
|
def foo(bar=baz, bax):
|
||||||
|
""" % (sourcePath.path,))
|
||||||
|
|
||||||
|
|
||||||
|
def test_nonKeywordAfterKeywordSyntaxError(self):
|
||||||
|
"""
|
||||||
|
Source which has a non-keyword argument after a keyword argument should
|
||||||
|
include the line number of the syntax error. However these exceptions
|
||||||
|
do not include an offset.
|
||||||
|
"""
|
||||||
|
source = """\
|
||||||
|
foo(bar=baz, bax)
|
||||||
|
"""
|
||||||
|
sourcePath = FilePath(self.mktemp())
|
||||||
|
sourcePath.setContent(source)
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
|
||||||
|
self.assertEqual(count, 1)
|
||||||
|
self.assertEqual(
|
||||||
|
err.getvalue(),
|
||||||
|
"""\
|
||||||
|
%s:1: non-keyword arg after keyword arg
|
||||||
|
foo(bar=baz, bax)
|
||||||
|
""" % (sourcePath.path,))
|
||||||
|
|
||||||
|
|
||||||
|
def test_permissionDenied(self):
|
||||||
|
"""
|
||||||
|
If the a source file is not readable, this is reported on standard
|
||||||
|
error.
|
||||||
|
"""
|
||||||
|
sourcePath = FilePath(self.mktemp())
|
||||||
|
sourcePath.setContent('')
|
||||||
|
sourcePath.chmod(0)
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
|
||||||
|
self.assertEquals(count, 1)
|
||||||
|
self.assertEquals(
|
||||||
|
err.getvalue(), "%s: Permission denied\n" % (sourcePath.path,))
|
||||||
|
|
||||||
|
|
||||||
|
def test_misencodedFile(self):
|
||||||
|
"""
|
||||||
|
If a source file contains bytes which cannot be decoded, this is
|
||||||
|
reported on stderr.
|
||||||
|
"""
|
||||||
|
source = u"""\
|
||||||
|
# coding: ascii
|
||||||
|
x = "\N{SNOWMAN}"
|
||||||
|
""".encode('utf-8')
|
||||||
|
sourcePath = FilePath(self.mktemp())
|
||||||
|
sourcePath.setContent(source)
|
||||||
|
err = StringIO()
|
||||||
|
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
|
||||||
|
self.assertEquals(count, 1)
|
||||||
|
self.assertEquals(
|
||||||
|
err.getvalue(), "%s: problem decoding source\n" % (sourcePath.path,))
|
|
@ -0,0 +1,265 @@
|
||||||
|
|
||||||
|
from _ast import PyCF_ONLY_AST
|
||||||
|
|
||||||
|
from twisted.trial.unittest import TestCase
|
||||||
|
|
||||||
|
from pyflakes import messages as m, checker
|
||||||
|
from pyflakes.test import harness
|
||||||
|
|
||||||
|
|
||||||
|
class Test(harness.Test):
|
||||||
|
def test_undefined(self):
|
||||||
|
self.flakes('bar', m.UndefinedName)
|
||||||
|
|
||||||
|
def test_definedInListComp(self):
|
||||||
|
self.flakes('[a for a in range(10) if a]')
|
||||||
|
|
||||||
|
|
||||||
|
def test_functionsNeedGlobalScope(self):
|
||||||
|
self.flakes('''
|
||||||
|
class a:
|
||||||
|
def b():
|
||||||
|
fu
|
||||||
|
fu = 1
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_builtins(self):
|
||||||
|
self.flakes('range(10)')
|
||||||
|
|
||||||
|
|
||||||
|
def test_magicGlobalsFile(self):
|
||||||
|
"""
|
||||||
|
Use of the C{__file__} magic global should not emit an undefined name
|
||||||
|
warning.
|
||||||
|
"""
|
||||||
|
self.flakes('__file__')
|
||||||
|
|
||||||
|
|
||||||
|
def test_magicGlobalsBuiltins(self):
|
||||||
|
"""
|
||||||
|
Use of the C{__builtins__} magic global should not emit an undefined
|
||||||
|
name warning.
|
||||||
|
"""
|
||||||
|
self.flakes('__builtins__')
|
||||||
|
|
||||||
|
|
||||||
|
def test_magicGlobalsName(self):
|
||||||
|
"""
|
||||||
|
Use of the C{__name__} magic global should not emit an undefined name
|
||||||
|
warning.
|
||||||
|
"""
|
||||||
|
self.flakes('__name__')
|
||||||
|
|
||||||
|
|
||||||
|
def test_magicGlobalsPath(self):
|
||||||
|
"""
|
||||||
|
Use of the C{__path__} magic global should not emit an undefined name
|
||||||
|
warning, if you refer to it from a file called __init__.py.
|
||||||
|
"""
|
||||||
|
self.flakes('__path__', m.UndefinedName)
|
||||||
|
self.flakes('__path__', filename='package/__init__.py')
|
||||||
|
|
||||||
|
|
||||||
|
def test_globalImportStar(self):
|
||||||
|
'''Can't find undefined names with import *'''
|
||||||
|
self.flakes('from fu import *; bar', m.ImportStarUsed)
|
||||||
|
|
||||||
|
def test_localImportStar(self):
|
||||||
|
'''A local import * still allows undefined names to be found in upper scopes'''
|
||||||
|
self.flakes('''
|
||||||
|
def a():
|
||||||
|
from fu import *
|
||||||
|
bar
|
||||||
|
''', m.ImportStarUsed, m.UndefinedName)
|
||||||
|
|
||||||
|
def test_unpackedParameter(self):
|
||||||
|
'''Unpacked function parameters create bindings'''
|
||||||
|
self.flakes('''
|
||||||
|
def a((bar, baz)):
|
||||||
|
bar; baz
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_definedByGlobal(self):
|
||||||
|
'''"global" can make an otherwise undefined name in another function defined'''
|
||||||
|
self.flakes('''
|
||||||
|
def a(): global fu; fu = 1
|
||||||
|
def b(): fu
|
||||||
|
''')
|
||||||
|
test_definedByGlobal.todo = ''
|
||||||
|
|
||||||
|
def test_globalInGlobalScope(self):
|
||||||
|
"""
|
||||||
|
A global statement in the global scope is ignored.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
global x
|
||||||
|
def foo():
|
||||||
|
print x
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
def test_del(self):
|
||||||
|
'''del deletes bindings'''
|
||||||
|
self.flakes('a = 1; del a; a', m.UndefinedName)
|
||||||
|
|
||||||
|
def test_delGlobal(self):
|
||||||
|
'''del a global binding from a function'''
|
||||||
|
self.flakes('''
|
||||||
|
a = 1
|
||||||
|
def f():
|
||||||
|
global a
|
||||||
|
del a
|
||||||
|
a
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_delUndefined(self):
|
||||||
|
'''del an undefined name'''
|
||||||
|
self.flakes('del a', m.UndefinedName)
|
||||||
|
|
||||||
|
def test_globalFromNestedScope(self):
|
||||||
|
'''global names are available from nested scopes'''
|
||||||
|
self.flakes('''
|
||||||
|
a = 1
|
||||||
|
def b():
|
||||||
|
def c():
|
||||||
|
a
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_laterRedefinedGlobalFromNestedScope(self):
|
||||||
|
"""
|
||||||
|
Test that referencing a local name that shadows a global, before it is
|
||||||
|
defined, generates a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
a = 1
|
||||||
|
def fun():
|
||||||
|
a
|
||||||
|
a = 2
|
||||||
|
return a
|
||||||
|
''', m.UndefinedLocal)
|
||||||
|
|
||||||
|
def test_laterRedefinedGlobalFromNestedScope2(self):
|
||||||
|
"""
|
||||||
|
Test that referencing a local name in a nested scope that shadows a
|
||||||
|
global declared in an enclosing scope, before it is defined, generates
|
||||||
|
a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
a = 1
|
||||||
|
def fun():
|
||||||
|
global a
|
||||||
|
def fun2():
|
||||||
|
a
|
||||||
|
a = 2
|
||||||
|
return a
|
||||||
|
''', m.UndefinedLocal)
|
||||||
|
|
||||||
|
|
||||||
|
def test_intermediateClassScopeIgnored(self):
|
||||||
|
"""
|
||||||
|
If a name defined in an enclosing scope is shadowed by a local variable
|
||||||
|
and the name is used locally before it is bound, an unbound local
|
||||||
|
warning is emitted, even if there is a class scope between the enclosing
|
||||||
|
scope and the local scope.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
x = 1
|
||||||
|
class g:
|
||||||
|
def h(self):
|
||||||
|
a = x
|
||||||
|
x = None
|
||||||
|
print x, a
|
||||||
|
print x
|
||||||
|
''', m.UndefinedLocal)
|
||||||
|
|
||||||
|
|
||||||
|
def test_doubleNestingReportsClosestName(self):
|
||||||
|
"""
|
||||||
|
Test that referencing a local name in a nested scope that shadows a
|
||||||
|
variable declared in two different outer scopes before it is defined
|
||||||
|
in the innermost scope generates an UnboundLocal warning which
|
||||||
|
refers to the nearest shadowed name.
|
||||||
|
"""
|
||||||
|
exc = self.flakes('''
|
||||||
|
def a():
|
||||||
|
x = 1
|
||||||
|
def b():
|
||||||
|
x = 2 # line 5
|
||||||
|
def c():
|
||||||
|
x
|
||||||
|
x = 3
|
||||||
|
return x
|
||||||
|
return x
|
||||||
|
return x
|
||||||
|
''', m.UndefinedLocal).messages[0]
|
||||||
|
self.assertEqual(exc.message_args, ('x', 5))
|
||||||
|
|
||||||
|
|
||||||
|
def test_laterRedefinedGlobalFromNestedScope3(self):
|
||||||
|
"""
|
||||||
|
Test that referencing a local name in a nested scope that shadows a
|
||||||
|
global, before it is defined, generates a warning.
|
||||||
|
"""
|
||||||
|
self.flakes('''
|
||||||
|
def fun():
|
||||||
|
a = 1
|
||||||
|
def fun2():
|
||||||
|
a
|
||||||
|
a = 1
|
||||||
|
return a
|
||||||
|
return a
|
||||||
|
''', m.UndefinedLocal)
|
||||||
|
|
||||||
|
def test_nestedClass(self):
|
||||||
|
'''nested classes can access enclosing scope'''
|
||||||
|
self.flakes('''
|
||||||
|
def f(foo):
|
||||||
|
class C:
|
||||||
|
bar = foo
|
||||||
|
def f(self):
|
||||||
|
return foo
|
||||||
|
return C()
|
||||||
|
|
||||||
|
f(123).f()
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_badNestedClass(self):
|
||||||
|
'''free variables in nested classes must bind at class creation'''
|
||||||
|
self.flakes('''
|
||||||
|
def f():
|
||||||
|
class C:
|
||||||
|
bar = foo
|
||||||
|
foo = 456
|
||||||
|
return foo
|
||||||
|
f()
|
||||||
|
''', m.UndefinedName)
|
||||||
|
|
||||||
|
def test_definedAsStarArgs(self):
|
||||||
|
'''star and double-star arg names are defined'''
|
||||||
|
self.flakes('''
|
||||||
|
def f(a, *b, **c):
|
||||||
|
print a, b, c
|
||||||
|
''')
|
||||||
|
|
||||||
|
def test_definedInGenExp(self):
|
||||||
|
"""
|
||||||
|
Using the loop variable of a generator expression results in no
|
||||||
|
warnings.
|
||||||
|
"""
|
||||||
|
self.flakes('(a for a in xrange(10) if a)')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class NameTests(TestCase):
|
||||||
|
"""
|
||||||
|
Tests for some extra cases of name handling.
|
||||||
|
"""
|
||||||
|
def test_impossibleContext(self):
|
||||||
|
"""
|
||||||
|
A Name node with an unrecognized context results in a RuntimeError being
|
||||||
|
raised.
|
||||||
|
"""
|
||||||
|
tree = compile("x = 10", "<test>", "exec", PyCF_ONLY_AST)
|
||||||
|
# Make it into something unrecognizable.
|
||||||
|
tree.body[0].targets[0].ctx = object()
|
||||||
|
self.assertRaises(RuntimeError, checker.Checker, tree)
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# (c) 2005-2009 Divmod, Inc. See LICENSE file for details
|
||||||
|
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="pyflakes",
|
||||||
|
license="MIT",
|
||||||
|
version="0.4.0",
|
||||||
|
description="passive checker of Python programs",
|
||||||
|
author="Phil Frost",
|
||||||
|
maintainer="Moe Aboulkheir",
|
||||||
|
maintainer_email="moe@divmod.com",
|
||||||
|
url="http://www.divmod.org/trac/wiki/DivmodPyflakes",
|
||||||
|
packages=["pyflakes", "pyflakes.scripts", "pyflakes.test"],
|
||||||
|
scripts=["bin/pyflakes"],
|
||||||
|
long_description="""Pyflakes is program to analyze Python programs and detect various errors. It
|
||||||
|
works by parsing the source file, not importing it, so it is safe to use on
|
||||||
|
modules with side effects. It's also much faster.""",
|
||||||
|
classifiers=[
|
||||||
|
"Development Status :: 6 - Mature",
|
||||||
|
"Environment :: Console",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Topic :: Software Development",
|
||||||
|
"Topic :: Utilities",
|
||||||
|
])
|
|
@ -0,0 +1,124 @@
|
||||||
|
diff --git a/README.rst b/README.rst
|
||||||
|
index 5f8467f..acff657 100644
|
||||||
|
--- a/README.rst
|
||||||
|
+++ b/README.rst
|
||||||
|
@@ -8,11 +8,13 @@ accessing a local before it is bound, and also gives warnings for things like
|
||||||
|
unused imports.
|
||||||
|
|
||||||
|
pyflakes-vim uses the output from PyFlakes to highlight errors in your code.
|
||||||
|
+To locate errors quickly, use quickfix_ commands:
|
||||||
|
|
||||||
|
Make sure to check vim.org_ for the latest updates.
|
||||||
|
|
||||||
|
.. _pyflakes.vim: http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
|
||||||
|
+.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
|
||||||
|
|
||||||
|
Quick Installation
|
||||||
|
------------------
|
||||||
|
@@ -57,12 +59,10 @@ Hacking
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
* signs_ support (show warning and error icons to left of the buffer area)
|
||||||
|
- * quickfix_ support (allow jumping forward and back through the error list)
|
||||||
|
* configuration variables
|
||||||
|
* parse or intercept useful output from the warnings module
|
||||||
|
|
||||||
|
.. _signs: http://www.vim.org/htmldoc/sign.html
|
||||||
|
-.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html
|
||||||
|
|
||||||
|
Changelog
|
||||||
|
---------
|
||||||
|
diff --git a/pyflakes.vim b/pyflakes.vim
|
||||||
|
index 8aa508b..d6699bc 100644
|
||||||
|
--- a/pyflakes.vim
|
||||||
|
+++ b/pyflakes.vim
|
||||||
|
@@ -159,6 +159,42 @@ if !exists("*s:WideMsg")
|
||||||
|
endfun
|
||||||
|
endif
|
||||||
|
|
||||||
|
+if !exists("*s:GetQuickFixStackCount")
|
||||||
|
+ function s:GetQuickFixStackCount()
|
||||||
|
+ let l:stack_count = 0
|
||||||
|
+ try
|
||||||
|
+ silent colder 9
|
||||||
|
+ catch /E380:/
|
||||||
|
+ endtry
|
||||||
|
+
|
||||||
|
+ try
|
||||||
|
+ for i in range(9)
|
||||||
|
+ silent cnewer
|
||||||
|
+ let l:stack_count = l:stack_count + 1
|
||||||
|
+ endfor
|
||||||
|
+ catch /E381:/
|
||||||
|
+ return l:stack_count
|
||||||
|
+ endtry
|
||||||
|
+ endfunction
|
||||||
|
+endif
|
||||||
|
+
|
||||||
|
+if !exists("*s:ActivatePyflakesQuickFixWindow")
|
||||||
|
+ function s:ActivatePyflakesQuickFixWindow()
|
||||||
|
+ try
|
||||||
|
+ silent colder 9 " go to the bottom of quickfix stack
|
||||||
|
+ catch /E380:/
|
||||||
|
+ endtry
|
||||||
|
+
|
||||||
|
+ if s:pyflakes_qf > 0
|
||||||
|
+ try
|
||||||
|
+ exe "silent cnewer " . s:pyflakes_qf
|
||||||
|
+ catch /E381:/
|
||||||
|
+ echoerr "Could not activate Pyflakes Quickfix Window."
|
||||||
|
+ endtry
|
||||||
|
+ endif
|
||||||
|
+ endfunction
|
||||||
|
+endif
|
||||||
|
+
|
||||||
|
if !exists("*s:RunPyflakes")
|
||||||
|
function s:RunPyflakes()
|
||||||
|
highlight link PyFlakes SpellBad
|
||||||
|
@@ -174,12 +210,23 @@ if !exists("*s:RunPyflakes")
|
||||||
|
|
||||||
|
let b:matched = []
|
||||||
|
let b:matchedlines = {}
|
||||||
|
+
|
||||||
|
+ let b:qf_list = []
|
||||||
|
+ let b:qf_window_count = -1
|
||||||
|
+
|
||||||
|
python << EOF
|
||||||
|
for w in check(vim.current.buffer):
|
||||||
|
vim.command('let s:matchDict = {}')
|
||||||
|
vim.command("let s:matchDict['lineNum'] = " + str(w.lineno))
|
||||||
|
vim.command("let s:matchDict['message'] = '%s'" % vim_quote(w.message % w.message_args))
|
||||||
|
vim.command("let b:matchedlines[" + str(w.lineno) + "] = s:matchDict")
|
||||||
|
+
|
||||||
|
+ vim.command("let l:qf_item = {}")
|
||||||
|
+ vim.command("let l:qf_item.bufnr = bufnr('%')")
|
||||||
|
+ vim.command("let l:qf_item.filename = expand('%')")
|
||||||
|
+ vim.command("let l:qf_item.lnum = %s" % str(w.lineno))
|
||||||
|
+ vim.command("let l:qf_item.text = '%s'" % vim_quote(w.message % w.message_args))
|
||||||
|
+ vim.command("let l:qf_item.type = 'E'")
|
||||||
|
|
||||||
|
if w.col is None or isinstance(w, SyntaxError):
|
||||||
|
# without column information, just highlight the whole line
|
||||||
|
@@ -189,8 +236,21 @@ for w in check(vim.current.buffer):
|
||||||
|
# with a column number, highlight the first keyword there
|
||||||
|
vim.command(r"let s:mID = matchadd('PyFlakes', '^\%" + str(w.lineno) + r"l\_.\{-}\zs\k\+\k\@!\%>" + str(w.col) + r"c')")
|
||||||
|
|
||||||
|
+ vim.command("let l:qf_item.vcol = 1")
|
||||||
|
+ vim.command("let l:qf_item.col = %s" % str(w.col + 1))
|
||||||
|
+
|
||||||
|
vim.command("call add(b:matched, s:matchDict)")
|
||||||
|
+ vim.command("call add(b:qf_list, l:qf_item)")
|
||||||
|
EOF
|
||||||
|
+ if exists("s:pyflakes_qf")
|
||||||
|
+ " if pyflakes quickfix window is already created, reuse it
|
||||||
|
+ call s:ActivatePyflakesQuickFixWindow()
|
||||||
|
+ call setqflist(b:qf_list, 'r')
|
||||||
|
+ else
|
||||||
|
+ " one pyflakes quickfix window for all buffer
|
||||||
|
+ call setqflist(b:qf_list, '')
|
||||||
|
+ let s:pyflakes_qf = s:GetQuickFixStackCount()
|
||||||
|
+ endif
|
||||||
|
let b:cleared = 0
|
||||||
|
endfunction
|
||||||
|
end
|
|
@ -3,8 +3,8 @@
|
||||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||||
" @Created: 2007-05-01.
|
" @Created: 2007-05-01.
|
||||||
" @Last Change: 2013-09-26.
|
" @Last Change: 2013-12-03.
|
||||||
" @Revision: 0.1.1297
|
" @Revision: 0.1.1310
|
||||||
|
|
||||||
" :filedoc:
|
" :filedoc:
|
||||||
" A prototype used by |tlib#input#List|.
|
" A prototype used by |tlib#input#List|.
|
||||||
|
@ -161,12 +161,14 @@ else
|
||||||
let self.width_filename = min([
|
let self.width_filename = min([
|
||||||
\ get(self, 'width_filename', &co),
|
\ get(self, 'width_filename', &co),
|
||||||
\ empty(g:tlib#input#filename_max_width) ? &co : eval(g:tlib#input#filename_max_width),
|
\ empty(g:tlib#input#filename_max_width) ? &co : eval(g:tlib#input#filename_max_width),
|
||||||
\ max(map(copy(self.base), 'strwidth(fnamemodify(v:val, ":t"))'))
|
\ max(map(copy(self.base), 'strwidth(matchstr(v:val, "[^\\/]*$"))'))
|
||||||
\ ])
|
\ ])
|
||||||
" TLogVAR self.width_filename
|
" TLogVAR self.width_filename
|
||||||
exec 'syntax match TLibFilename /[^\/]\+$/ contained containedin=TLibDir'
|
|
||||||
exec 'syntax match TLibDir /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \zs\(\(\a:\|\.\.\|\.\.\..\{-}\)\?[\/][^&<>*|]\{-}\)\?[^\/]\+$/ contained containedin=TLibMarker contains=TLibFilename'
|
exec 'syntax match TLibDir /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \zs\(\(\a:\|\.\.\|\.\.\..\{-}\)\?[\/][^&<>*|]\{-}\)\?[^\/]\+$/ contained containedin=TLibMarker contains=TLibFilename'
|
||||||
exec 'syntax match TLibMarker /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \S.*$/ contains=TLibDir'
|
exec 'syntax match TLibMarker /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \S.*$/ contains=TLibDir'
|
||||||
|
" exec 'syntax match TLibDir /\(|\|\[.\{-}\]\) \zs\(\(\a:\|\.\.\|\.\.\..\{-}\)\?[\/][^&<>*|]\{-}\)\?[^\/]\+$/ contained containedin=TLibMarker contains=TLibFilename'
|
||||||
|
" exec 'syntax match TLibMarker /\(|\|\[.\{-}\]\) \S.*$/ contains=TLibDir'
|
||||||
|
exec 'syntax match TLibFilename /[^\/]\+$/ contained containedin=TLibDir'
|
||||||
hi def link TLibMarker Special
|
hi def link TLibMarker Special
|
||||||
hi def link TLibDir Directory
|
hi def link TLibDir Directory
|
||||||
hi def link TLibFilename NonText
|
hi def link TLibFilename NonText
|
||||||
|
@ -206,8 +208,9 @@ else
|
||||||
" TLogVAR use_indicators
|
" TLogVAR use_indicators
|
||||||
if use_indicators
|
if use_indicators
|
||||||
call insert(marker, '[')
|
call insert(marker, '[')
|
||||||
|
if g:tlib_inputlist_filename_indicators
|
||||||
let bnr = bufnr(a:file)
|
let bnr = bufnr(a:file)
|
||||||
" TLogVAR a:file, bnr, self.bufnr
|
TLogVAR a:file, bnr, self.bufnr
|
||||||
if bnr != -1
|
if bnr != -1
|
||||||
if bnr == self.bufnr
|
if bnr == self.bufnr
|
||||||
call add(marker, '%')
|
call add(marker, '%')
|
||||||
|
@ -225,6 +228,7 @@ else
|
||||||
" endif
|
" endif
|
||||||
" echom "DBG" a:file string(get(self,'filename_indicators'))
|
" echom "DBG" a:file string(get(self,'filename_indicators'))
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
if has_key(self, 'filename_indicators') && has_key(self.filename_indicators, a:file)
|
if has_key(self, 'filename_indicators') && has_key(self.filename_indicators, a:file)
|
||||||
if len(marker) > 1
|
if len(marker) > 1
|
||||||
call add(marker, '|')
|
call add(marker, '|')
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||||
" @Created: 2007-06-24.
|
" @Created: 2007-06-24.
|
||||||
" @Last Change: 2013-09-26.
|
" @Last Change: 2013-11-05.
|
||||||
" @Revision: 0.1.240
|
" @Revision: 0.1.242
|
||||||
|
|
||||||
|
|
||||||
" :filedoc:
|
" :filedoc:
|
||||||
|
@ -444,6 +444,7 @@ endf
|
||||||
|
|
||||||
|
|
||||||
function! tlib#agent#EditFileInTab(world, selected) "{{{3
|
function! tlib#agent#EditFileInTab(world, selected) "{{{3
|
||||||
|
" TLogVAR a:selected
|
||||||
call a:world.CloseScratch()
|
call a:world.CloseScratch()
|
||||||
call tlib#file#With('tabedit', 'tab sbuffer', a:selected, a:world)
|
call tlib#file#With('tabedit', 'tab sbuffer', a:selected, a:world)
|
||||||
return tlib#agent#Exit(a:world, a:selected)
|
return tlib#agent#Exit(a:world, a:selected)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||||
" @Created: 2007-06-30.
|
" @Created: 2007-06-30.
|
||||||
" @Last Change: 2013-09-25.
|
" @Last Change: 2013-09-25.
|
||||||
" @Revision: 0.0.141
|
" @Revision: 0.0.142
|
||||||
|
|
||||||
if &cp || exists("loaded_tlib_file_autoload")
|
if &cp || exists("loaded_tlib_file_autoload")
|
||||||
finish
|
finish
|
||||||
|
@ -36,12 +36,12 @@ function! tlib#file#Split(filename) "{{{3
|
||||||
endf
|
endf
|
||||||
|
|
||||||
|
|
||||||
" :display: tlib#file#Join(filename_parts, ?strip_slashes=0)
|
" :display: tlib#file#Join(filename_parts, ?strip_slashes=1)
|
||||||
" EXAMPLES: >
|
" EXAMPLES: >
|
||||||
" tlib#file#Join(['foo', 'bar', 'filename.txt'])
|
" tlib#file#Join(['foo', 'bar', 'filename.txt'])
|
||||||
" => 'foo/bar/filename.txt'
|
" => 'foo/bar/filename.txt'
|
||||||
function! tlib#file#Join(filename_parts, ...) "{{{3
|
function! tlib#file#Join(filename_parts, ...) "{{{3
|
||||||
TVarArg 'strip_slashes'
|
TVarArg ['strip_slashes', 1]
|
||||||
" TLogVAR a:filename_parts, strip_slashes
|
" TLogVAR a:filename_parts, strip_slashes
|
||||||
if strip_slashes
|
if strip_slashes
|
||||||
" let rx = tlib#rx#Escape(g:tlib#dir#sep) .'$'
|
" let rx = tlib#rx#Escape(g:tlib#dir#sep) .'$'
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||||
" @Created: 2007-07-18.
|
" @Created: 2007-07-18.
|
||||||
" @Last Change: 2013-10-16.
|
" @Last Change: 2013-11-11.
|
||||||
" @Revision: 0.0.242
|
" @Revision: 0.0.251
|
||||||
|
|
||||||
if &cp || exists("loaded_tlib_scratch_autoload")
|
if &cp || exists("loaded_tlib_scratch_autoload")
|
||||||
finish
|
finish
|
||||||
|
@ -65,7 +65,7 @@ function! tlib#scratch#UseScratch(...) "{{{3
|
||||||
else
|
else
|
||||||
let cmd = 'buffer!'
|
let cmd = 'buffer!'
|
||||||
endif
|
endif
|
||||||
" TLogVAR cmd
|
" TLogVAR cmd, bn
|
||||||
silent exec 'noautocmd keepalt keepj' cmd bn
|
silent exec 'noautocmd keepalt keepj' cmd bn
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
|
@ -77,7 +77,7 @@ function! tlib#scratch#UseScratch(...) "{{{3
|
||||||
else
|
else
|
||||||
let cmd = 'edit'
|
let cmd = 'edit'
|
||||||
endif
|
endif
|
||||||
" TLogVAR cmd
|
" TLogVAR cmd, id
|
||||||
silent exec 'noautocmd keepalt keepj' cmd escape(id, '%#\ ')
|
silent exec 'noautocmd keepalt keepj' cmd escape(id, '%#\ ')
|
||||||
" silent exec 'split '. id
|
" silent exec 'split '. id
|
||||||
endif
|
endif
|
||||||
|
@ -100,7 +100,7 @@ function! tlib#scratch#UseScratch(...) "{{{3
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
let keyargs.scratch = bufnr('%')
|
let keyargs.scratch = bufnr('%')
|
||||||
" TLogVAR 2, winnr(), bufnr('%'), bufname("%")
|
" TLogVAR 2, winnr(), bufnr('%'), bufname("%"), keyargs.scratch
|
||||||
return keyargs.scratch
|
return keyargs.scratch
|
||||||
endf
|
endf
|
||||||
|
|
||||||
|
|
|
@ -1495,7 +1495,7 @@ tlib#file#Split(filename)
|
||||||
<
|
<
|
||||||
|
|
||||||
*tlib#file#Join()*
|
*tlib#file#Join()*
|
||||||
tlib#file#Join(filename_parts, ?strip_slashes=0)
|
tlib#file#Join(filename_parts, ?strip_slashes=1)
|
||||||
EXAMPLES: >
|
EXAMPLES: >
|
||||||
tlib#file#Join(['foo', 'bar', 'filename.txt'])
|
tlib#file#Join(['foo', 'bar', 'filename.txt'])
|
||||||
=> 'foo/bar/filename.txt'
|
=> 'foo/bar/filename.txt'
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||||
" @Created: 2007-04-10.
|
" @Created: 2007-04-10.
|
||||||
" @Last Change: 2013-09-25.
|
" @Last Change: 2013-09-25.
|
||||||
" @Revision: 746
|
" @Revision: 748
|
||||||
" GetLatestVimScripts: 1863 1 tlib.vim
|
" GetLatestVimScripts: 1863 1 tlib.vim
|
||||||
|
|
||||||
if &cp || exists("loaded_tlib")
|
if &cp || exists("loaded_tlib")
|
||||||
|
@ -14,7 +14,7 @@ if v:version < 700 "{{{2
|
||||||
echoerr "tlib requires Vim >= 7"
|
echoerr "tlib requires Vim >= 7"
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
let loaded_tlib = 106
|
let loaded_tlib = 107
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
let s:save_cpo = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2013 Bailey Ling
|
Copyright (C) 2013-2014 Bailey Ling
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the "Software"),
|
a copy of this software and associated documentation files (the "Software"),
|
||||||
|
|
|
@ -70,6 +70,9 @@ vim-airline integrates with a variety of plugins out of the box. These extensio
|
||||||
#### [tmuxline][35]
|
#### [tmuxline][35]
|
||||||
![image](https://f.cloud.github.com/assets/1532071/1559276/4c28fbac-4fc7-11e3-90ef-7e833d980f98.gif)
|
![image](https://f.cloud.github.com/assets/1532071/1559276/4c28fbac-4fc7-11e3-90ef-7e833d980f98.gif)
|
||||||
|
|
||||||
|
#### [promptline][36]
|
||||||
|
![airline-promptline-sc](https://f.cloud.github.com/assets/1532071/1871900/7d4b28a0-789d-11e3-90e4-16f37269981b.gif)
|
||||||
|
|
||||||
## Extras
|
## Extras
|
||||||
|
|
||||||
vim-airline also supplies some supplementary stand-alone extensions. In addition to the tabline extension mentioned earlier, there is also:
|
vim-airline also supplies some supplementary stand-alone extensions. In addition to the tabline extension mentioned earlier, there is also:
|
||||||
|
@ -164,7 +167,7 @@ Contributions and pull requests are welcome. Please take note of the following
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
MIT License. Copyright (c) 2013 Bailey Ling.
|
MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
|
|
||||||
|
|
||||||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/bling/vim-airline/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/bling/vim-airline/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
||||||
|
@ -204,3 +207,4 @@ MIT License. Copyright (c) 2013 Bailey Ling.
|
||||||
[33]: https://github.com/bling/vim-airline/wiki/Test-Plan
|
[33]: https://github.com/bling/vim-airline/wiki/Test-Plan
|
||||||
[34]: http://eclim.org
|
[34]: http://eclim.org
|
||||||
[35]: https://github.com/edkolev/tmuxline.vim
|
[35]: https://github.com/edkolev/tmuxline.vim
|
||||||
|
[36]: https://github.com/edkolev/promptline.vim
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let g:airline_statusline_funcrefs = get(g:, 'airline_statusline_funcrefs', [])
|
let g:airline_statusline_funcrefs = get(g:, 'airline_statusline_funcrefs', [])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:prototype = {}
|
let s:prototype = {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
function! airline#debug#profile1()
|
function! airline#debug#profile1()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
function! airline#deprecation#check()
|
function! airline#deprecation#check()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:ext = {}
|
let s:ext = {}
|
||||||
|
@ -20,7 +20,6 @@ endfunction
|
||||||
let s:script_path = tolower(resolve(expand('<sfile>:p:h')))
|
let s:script_path = tolower(resolve(expand('<sfile>:p:h')))
|
||||||
|
|
||||||
let s:filetype_overrides = {
|
let s:filetype_overrides = {
|
||||||
\ 'netrw': [ 'netrw', '%f' ],
|
|
||||||
\ 'nerdtree': [ 'NERD', '' ],
|
\ 'nerdtree': [ 'NERD', '' ],
|
||||||
\ 'gundo': [ 'Gundo', '' ],
|
\ 'gundo': [ 'Gundo', '' ],
|
||||||
\ 'diff': [ 'diff', '' ],
|
\ 'diff': [ 'diff', '' ],
|
||||||
|
@ -128,6 +127,10 @@ function! airline#extensions#load()
|
||||||
call airline#extensions#unite#init(s:ext)
|
call airline#extensions#unite#init(s:ext)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if exists(':NetrwSettings')
|
||||||
|
call airline#extensions#netrw#init(s:ext)
|
||||||
|
endif
|
||||||
|
|
||||||
if get(g:, 'loaded_vimfiler', 0)
|
if get(g:, 'loaded_vimfiler', 0)
|
||||||
let g:vimfiler_force_overwrite_statusline = 0
|
let g:vimfiler_force_overwrite_statusline = 0
|
||||||
endif
|
endif
|
||||||
|
@ -199,6 +202,10 @@ function! airline#extensions#load()
|
||||||
call airline#extensions#tmuxline#init(s:ext)
|
call airline#extensions#tmuxline#init(s:ext)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get(g:, 'airline#extensions#promptline#enabled', 1) && exists(':PromptlineSnapshot') && len(get(g:, 'airline#extensions#promptline#snapshot_file', ''))
|
||||||
|
call airline#extensions#promptline#init(s:ext)
|
||||||
|
endif
|
||||||
|
|
||||||
" load all other extensions not part of the default distribution
|
" load all other extensions not part of the default distribution
|
||||||
for file in split(globpath(&rtp, "autoload/airline/extensions/*.vim"), "\n")
|
for file in split(globpath(&rtp, "autoload/airline/extensions/*.vim"), "\n")
|
||||||
" we have to check both resolved and unresolved paths, since it's possible
|
" we have to check both resolved and unresolved paths, since it's possible
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:has_fugitive = exists('*fugitive#head')
|
let s:has_fugitive = exists('*fugitive#head')
|
||||||
|
@ -10,10 +10,6 @@ if !s:has_fugitive && !s:has_lawrencium && !s:has_vcscommand
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let s:empty_message = get(g:, 'airline#extensions#branch#empty_message',
|
|
||||||
\ get(g:, 'airline_branch_empty_message', ''))
|
|
||||||
let s:symbol = get(g:, 'airline#extensions#branch#symbol', g:airline_symbols.branch)
|
|
||||||
|
|
||||||
function! airline#extensions#branch#head()
|
function! airline#extensions#branch#head()
|
||||||
let head = ''
|
let head = ''
|
||||||
|
|
||||||
|
@ -48,9 +44,12 @@ endfunction
|
||||||
|
|
||||||
function! airline#extensions#branch#get_head()
|
function! airline#extensions#branch#get_head()
|
||||||
let head = airline#extensions#branch#head()
|
let head = airline#extensions#branch#head()
|
||||||
|
let empty_message = get(g:, 'airline#extensions#branch#empty_message',
|
||||||
|
\ get(g:, 'airline_branch_empty_message', ''))
|
||||||
|
let symbol = get(g:, 'airline#extensions#branch#symbol', g:airline_symbols.branch)
|
||||||
return empty(head)
|
return empty(head)
|
||||||
\ ? s:empty_message
|
\ ? empty_message
|
||||||
\ : printf('%s%s', empty(s:symbol) ? '' : s:symbol.(g:airline_symbols.space), head)
|
\ : printf('%s%s', empty(symbol) ? '' : symbol.(g:airline_symbols.space), head)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:check_in_path()
|
function! s:check_in_path()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !exists('*bufferline#get_status_string')
|
if !exists('*bufferline#get_status_string')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !get(g:, 'command_t_loaded', 0)
|
if !get(g:, 'command_t_loaded', 0)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !get(g:, 'loaded_csv', 0) && !exists(':Table')
|
if !get(g:, 'loaded_csv', 0) && !exists(':Table')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !get(g:, 'loaded_ctrlp', 0)
|
if !get(g:, 'loaded_ctrlp', 0)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:section_truncate_width = get(g:, 'airline#extensions#default#section_truncate_width', {
|
let s:section_truncate_width = get(g:, 'airline#extensions#default#section_truncate_width', {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !exists(':ProjectCreate')
|
if !exists(':ProjectCreate')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
" we don't actually want this loaded :P
|
" we don't actually want this loaded :P
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !get(g:, 'loaded_signify', 0) && !get(g:, 'loaded_gitgutter', 0)
|
if !get(g:, 'loaded_signify', 0) && !get(g:, 'loaded_gitgutter', 0)
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
|
if !exists(':NetrwSettings')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! airline#extensions#netrw#apply(...)
|
||||||
|
if &ft == 'netrw'
|
||||||
|
let spc = g:airline_symbols.space
|
||||||
|
|
||||||
|
call a:1.add_section('airline_a', spc.'netrw'.spc)
|
||||||
|
if exists('*airline#extensions#branch#get_head')
|
||||||
|
call a:1.add_section('airline_b', spc.'%{airline#extensions#branch#get_head()}'.spc)
|
||||||
|
endif
|
||||||
|
call a:1.add_section('airline_c', spc.'%f'.spc)
|
||||||
|
call a:1.split()
|
||||||
|
call a:1.add_section('airline_y', spc.'%{airline#extensions#netrw#sortstring()}'.spc)
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! airline#extensions#netrw#init(ext)
|
||||||
|
let g:netrw_force_overwrite_statusline = 0
|
||||||
|
call a:ext.add_statusline_func('airline#extensions#netrw#apply')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function! airline#extensions#netrw#sortstring()
|
||||||
|
let order = (g:netrw_sort_direction =~ 'n') ? '+' : '-'
|
||||||
|
return g:netrw_sort_by . (g:airline_symbols.space) . '[' . order . ']'
|
||||||
|
endfunction
|
|
@ -0,0 +1,33 @@
|
||||||
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
|
if !exists(':PromptlineSnapshot')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('airline#extensions#promptline#snapshot_file') || !len('airline#extensions#promptline#snapshot_file')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:prompt_snapshot_file = get(g:, 'airline#extensions#promptline#snapshot_file', '')
|
||||||
|
let s:color_template = get(g:, 'airline#extensions#promptline#color_template', 'normal')
|
||||||
|
|
||||||
|
function! airline#extensions#promptline#init(ext)
|
||||||
|
call a:ext.add_theme_func('airline#extensions#promptline#set_prompt_colors')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! airline#extensions#promptline#set_prompt_colors(palette)
|
||||||
|
let color_template = has_key(a:palette, s:color_template) ? s:color_template : 'normal'
|
||||||
|
let mode_palette = a:palette[color_template]
|
||||||
|
|
||||||
|
if !has_key(g:, 'promptline_symbols')
|
||||||
|
let g:promptline_symbols = {
|
||||||
|
\ 'left' : g:airline_left_sep,
|
||||||
|
\ 'right' : g:airline_right_sep,
|
||||||
|
\ 'left_alt' : g:airline_left_alt_sep,
|
||||||
|
\ 'right_alt' : g:airline_right_alt_sep}
|
||||||
|
endif
|
||||||
|
|
||||||
|
let promptline_theme = promptline#api#create_theme_from_airline(mode_palette)
|
||||||
|
call promptline#api#create_snapshot_with_theme(s:prompt_snapshot_file, promptline_theme)
|
||||||
|
endfunction
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let g:airline#extensions#quickfix#quickfix_text = 'Quickfix'
|
let g:airline#extensions#quickfix#quickfix_text = 'Quickfix'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !exists(':SyntasticCheck')
|
if !exists(':SyntasticCheck')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:formatter = get(g:, 'airline#extensions#tabline#formatter', 'default')
|
let s:formatter = get(g:, 'airline#extensions#tabline#formatter', 'default')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:fmod = get(g:, 'airline#extensions#tabline#fnamemod', ':~:.')
|
let s:fmod = get(g:, 'airline#extensions#tabline#fnamemod', ':~:.')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
function! airline#extensions#tabline#unique_tail#format(bufnr, buffers)
|
function! airline#extensions#tabline#unique_tail#format(bufnr, buffers)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:skip_symbol = '…'
|
let s:skip_symbol = '…'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !exists(':TagbarToggle')
|
if !exists(':TagbarToggle')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !exists(':Tmuxline')
|
if !exists(':Tmuxline')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !exists(':UndotreeToggle')
|
if !exists(':UndotreeToggle')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !get(g:, 'loaded_unite', 0)
|
if !get(g:, 'loaded_unite', 0)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if !get(g:, 'virtualenv_loaded', 0)
|
if !get(g:, 'virtualenv_loaded', 0)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
" http://got-ravings.blogspot.com/2008/10/vim-pr0n-statusline-whitespace-flags.html
|
" http://got-ravings.blogspot.com/2008/10/vim-pr0n-statusline-whitespace-flags.html
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:is_win32term = (has('win32') || has('win64')) && !has('gui_running')
|
let s:is_win32term = (has('win32') || has('win64')) && !has('gui_running')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
function! s:check_defined(variable, default)
|
function! s:check_defined(variable, default)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
let s:parts = {}
|
let s:parts = {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
call airline#init#bootstrap()
|
call airline#init#bootstrap()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
" generates a dictionary which defines the colors for each highlight group
|
" generates a dictionary which defines the colors for each highlight group
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
"
|
||||||
|
" Colorscheme: Kalisi for airline. Inspired by powerline.
|
||||||
|
" 06.02.2014 Arthur Jaron
|
||||||
|
" hifreeo@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
" Insert mode
|
||||||
|
let s:I1 = [ '#ffffff' , '#e80000' , 23 , 231 ]
|
||||||
|
let s:I2 = [ '#c5c5c5' , '#901010' , 74 , 31 ]
|
||||||
|
let s:I3 = [ '#c5c5c5' , '#500000' , 117 , 24 ]
|
||||||
|
|
||||||
|
" Visual mode
|
||||||
|
let s:V1 = [ '#005f5f' , '#ffffff' , 23 , 231 ]
|
||||||
|
let s:V2 = [ '#5fafd7' , '#0087af' , 74 , 31 ]
|
||||||
|
let s:V3 = [ '#87d7ff' , '#005f87' , 117 , 24 ]
|
||||||
|
|
||||||
|
" Replace mode
|
||||||
|
let s:R1 = [ '#8e00da' , '#ffffff' , 23 , 231 ]
|
||||||
|
let s:R2 = [ '#8e00da' , '#ce99ff' , 74 , 31 ]
|
||||||
|
let s:R3 = [ '#ce99ff' , '#8e00da' , 117 , 24 ]
|
||||||
|
|
||||||
|
let g:airline#themes#kalisi#palette = {}
|
||||||
|
|
||||||
|
function! airline#themes#kalisi#refresh()
|
||||||
|
|
||||||
|
" Normal mode
|
||||||
|
let s:N1 = [ '#005f00' , '#afd700' , 22 , 148 ]
|
||||||
|
let s:N2 = [ '#afd700' , '#005f00' , 247 , 236 ]
|
||||||
|
let s:N3 = airline#themes#get_highlight('StatusLine')
|
||||||
|
|
||||||
|
" Tabline Plugin
|
||||||
|
let g:airline#themes#kalisi#palette.tabline = {
|
||||||
|
\ 'airline_tab': ['#A6DB29', '#005f00', 231, 29, ''],
|
||||||
|
\ 'airline_tabsel': ['#404042', '#A6DB29', 231, 36, ''],
|
||||||
|
\ 'airline_tabtype': ['#afd700', '#005f00', 231, 36, ''],
|
||||||
|
\ 'airline_tabfill': ['#ffffff', '#000000', 231, 23, ''],
|
||||||
|
\ 'airline_tabhid': ['#c5c5c5', '#404042', 231, 88, ''],
|
||||||
|
\ 'airline_tabmod': ['#ffffff', '#F1266F', 231, 88, ''],
|
||||||
|
\ }
|
||||||
|
|
||||||
|
let g:airline#themes#kalisi#palette.normal = airline#themes#generate_color_map(s:N1, s:N2, s:N3)
|
||||||
|
let g:airline#themes#kalisi#palette.visual = airline#themes#generate_color_map(s:V1, s:V2, s:V3)
|
||||||
|
let g:airline#themes#kalisi#palette.insert = airline#themes#generate_color_map(s:I1, s:I2, s:I3)
|
||||||
|
let g:airline#themes#kalisi#palette.replace = airline#themes#generate_color_map(s:R1, s:R2, s:R3)
|
||||||
|
|
||||||
|
" Inactive Mode
|
||||||
|
" let s:IA = [ '#c5c5c5' , '#505052' , 239 , 234 , '' ]
|
||||||
|
let s:IA = airline#themes#get_highlight('StatusLineNC')
|
||||||
|
let g:airline#themes#kalisi#palette.inactive = airline#themes#generate_color_map(s:IA, s:IA, s:IA)
|
||||||
|
let g:airline#themes#kalisi#palette.inactive_modified = {
|
||||||
|
\ 'statusline': [ '#F1266F' , '' , '53' , '' , '' ] ,
|
||||||
|
\ }
|
||||||
|
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call airline#themes#kalisi#refresh()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
call airline#init#bootstrap()
|
call airline#init#bootstrap()
|
||||||
|
|
|
@ -450,6 +450,26 @@ tmuxline <https://github.com/edkolev/tmuxline.vim>
|
||||||
startup >
|
startup >
|
||||||
airline#extensions#tmuxline#snapshot_file = "~/.tmux-statusline-colors.conf"
|
airline#extensions#tmuxline#snapshot_file = "~/.tmux-statusline-colors.conf"
|
||||||
<
|
<
|
||||||
|
------------------------------------- *airline-promptline*
|
||||||
|
promptline <https://github.com/edkolev/promptline.vim>
|
||||||
|
|
||||||
|
* configure the path to the snapshot .sh file. Mandatory option. The created
|
||||||
|
file should be sourced by the shell on login >
|
||||||
|
" in .vimrc
|
||||||
|
airline#extensions#promptline#snapshot_file = "~/.shell_prompt.sh"
|
||||||
|
|
||||||
|
" in .bashrc/.zshrc
|
||||||
|
[ -f ~/.shell_prompt.sh ] && source ~/.shell_prompt.sh
|
||||||
|
<
|
||||||
|
* enable/disable promptline integration >
|
||||||
|
let g:airline#extensions#promptline#enabled = 0
|
||||||
|
<
|
||||||
|
* configure which mode colors should be used in prompt >
|
||||||
|
let airline#extensions#promptline#color_template = 'normal' (default)
|
||||||
|
let airline#extensions#promptline#color_template = 'insert'
|
||||||
|
let airline#extensions#promptline#color_template = 'visual'
|
||||||
|
let airline#extensions#promptline#color_template = 'replace'
|
||||||
|
<
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
ADVANCED CUSTOMIZATION *airline-advanced-customization*
|
ADVANCED CUSTOMIZATION *airline-advanced-customization*
|
||||||
|
@ -699,7 +719,7 @@ Contributions and pull requests are welcome.
|
||||||
==============================================================================
|
==============================================================================
|
||||||
LICENSE *airline-license*
|
LICENSE *airline-license*
|
||||||
|
|
||||||
MIT License. Copyright © 2013 Bailey Ling.
|
MIT License. Copyright © 2013-2014 Bailey Ling.
|
||||||
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
vim:tw=78:ts=8:ft=help:norl:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
" MIT License. Copyright (c) 2013 Bailey Ling.
|
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
|
||||||
" vim: et ts=2 sts=2 sw=2
|
" vim: et ts=2 sts=2 sw=2
|
||||||
|
|
||||||
if &cp || v:version < 702 || (exists('g:loaded_airline') && g:loaded_airline)
|
if &cp || v:version < 702 || (exists('g:loaded_airline') && g:loaded_airline)
|
||||||
|
|
|
@ -136,6 +136,9 @@ function! fugitive#extract_git_dir(path) abort
|
||||||
" checking for them since such checks are extremely slow.
|
" checking for them since such checks are extremely slow.
|
||||||
break
|
break
|
||||||
endif
|
endif
|
||||||
|
if index(split($GIT_CEILING_DIRECTORIES, ':'), root) >= 0
|
||||||
|
break
|
||||||
|
endif
|
||||||
let dir = s:sub(root, '[\/]$', '') . '/.git'
|
let dir = s:sub(root, '[\/]$', '') . '/.git'
|
||||||
let type = getftype(dir)
|
let type = getftype(dir)
|
||||||
if type ==# 'dir' && fugitive#is_git_dir(dir)
|
if type ==# 'dir' && fugitive#is_git_dir(dir)
|
||||||
|
|
|
@ -14,6 +14,7 @@ additional contributions from:
|
||||||
* [bpugh](https://github.com/bpugh)
|
* [bpugh](https://github.com/bpugh)
|
||||||
* [bruno-](https://github.com/bruno-)
|
* [bruno-](https://github.com/bruno-)
|
||||||
* [darkwise](https://github.com/darkwise)
|
* [darkwise](https://github.com/darkwise)
|
||||||
|
* [fish-face](https://github.com/fish-face)
|
||||||
* [henrik](https://github.com/henrik)
|
* [henrik](https://github.com/henrik)
|
||||||
* [holizz](https://github.com/holizz)
|
* [holizz](https://github.com/holizz)
|
||||||
* [honza](https://github.com/honza)
|
* [honza](https://github.com/honza)
|
||||||
|
|
|
@ -22,6 +22,8 @@ dependencies. SnipMate depends on [vim-addon-mw-utils][mw-utils] and
|
||||||
[tlib][tlib]. Since SnipMate does not ship with any snippets, we suggest
|
[tlib][tlib]. Since SnipMate does not ship with any snippets, we suggest
|
||||||
looking at the [vim-snippets][vim-snippets] repository.
|
looking at the [vim-snippets][vim-snippets] repository.
|
||||||
|
|
||||||
|
* Using [VAM][vam], add `vim-snippets` to the list of packages to be installed.
|
||||||
|
|
||||||
* Using [Pathogen][pathogen], run the following commands:
|
* Using [Pathogen][pathogen], run the following commands:
|
||||||
|
|
||||||
% cd ~/.vim/bundle
|
% cd ~/.vim/bundle
|
||||||
|
@ -32,8 +34,6 @@ looking at the [vim-snippets][vim-snippets] repository.
|
||||||
# Optional:
|
# Optional:
|
||||||
% git clone https://github.com/honza/vim-snippets.git
|
% git clone https://github.com/honza/vim-snippets.git
|
||||||
|
|
||||||
* Using [VAM][vam], add `vim-snippets` to the list of packages to be installed.
|
|
||||||
|
|
||||||
* Using [Vundle][vundle], add the following to your `vimrc` then run
|
* Using [Vundle][vundle], add the following to your `vimrc` then run
|
||||||
`:BundleInstall`
|
`:BundleInstall`
|
||||||
|
|
||||||
|
@ -46,6 +46,11 @@ looking at the [vim-snippets][vim-snippets] repository.
|
||||||
|
|
||||||
## Release Notes ##
|
## Release Notes ##
|
||||||
|
|
||||||
|
### Master ###
|
||||||
|
|
||||||
|
* Fix bug with mirrors in the first column
|
||||||
|
* Fix bug with tabs in indents ([#143][143])
|
||||||
|
|
||||||
### 0.87 - 2014-01-04 ###
|
### 0.87 - 2014-01-04 ###
|
||||||
|
|
||||||
* Stop indenting empty lines when expanding snippets
|
* Stop indenting empty lines when expanding snippets
|
||||||
|
@ -68,3 +73,5 @@ looking at the [vim-snippets][vim-snippets] repository.
|
||||||
[vam]: https://github.com/marcweber/vim-addon-manager
|
[vam]: https://github.com/marcweber/vim-addon-manager
|
||||||
[pathogen]: https://github.com/tpope/vim-pathogen
|
[pathogen]: https://github.com/tpope/vim-pathogen
|
||||||
[vundle]: https://github.com/gmarik/vundle
|
[vundle]: https://github.com/gmarik/vundle
|
||||||
|
|
||||||
|
[143]: https://github.com/garbas/vim-snipmate/issues/143
|
||||||
|
|
|
@ -79,7 +79,7 @@ fun! snipMate#expandSnip(snip, col)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Insert snippet with proper indentation
|
" Insert snippet with proper indentation
|
||||||
let indent = indent(lnum) + 1
|
let indent = match(line, '\S\|$') + 1
|
||||||
call setline(lnum, line . snipLines[0])
|
call setline(lnum, line . snipLines[0])
|
||||||
call append(lnum, map(snipLines[1:], "empty(v:val) ? v:val : '" . strpart(line, 0, indent - 1) . "' . v:val"))
|
call append(lnum, map(snipLines[1:], "empty(v:val) ? v:val : '" . strpart(line, 0, indent - 1) . "' . v:val"))
|
||||||
|
|
||||||
|
@ -375,10 +375,14 @@ function! s:state_proto.update_vars(change)
|
||||||
let i += 1
|
let i += 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Split the line into three parts: the mirror, what's before it, and
|
||||||
|
" what's after it. Then combine them using the new mirror string.
|
||||||
|
" Subtract one to go from column index to byte index
|
||||||
let theline = getline(lnum)
|
let theline = getline(lnum)
|
||||||
" subtract -1 to go from column byte index to string byte index
|
let update = strpart(theline, 0, col - 1)
|
||||||
" subtract another -1 to exclude the col'th element
|
let update .= newWord
|
||||||
call setline(lnum, theline[0:(col-2)] . newWord . theline[(col+self.end_col-self.start_col-a:change-1):])
|
let update .= strpart(theline, col + self.end_col - self.start_col - a:change - 1)
|
||||||
|
call setline(lnum, update)
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
" Reposition the cursor in case a var updates on the same line but before
|
" Reposition the cursor in case a var updates on the same line but before
|
||||||
|
|
|
@ -51,6 +51,32 @@ If you have VimL only (vim without python support) your best option is using
|
||||||
garbas/vim-snipmate and cope with the minor bugs found in the engine.
|
garbas/vim-snipmate and cope with the minor bugs found in the engine.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
First be aware that there are many options, see "Snippet engines" above.
|
||||||
|
Second be aware than there are [tons of plugin managers](http://vim-wiki.mawercer.de/wiki/topic/vim%20plugin%20managment.html)
|
||||||
|
which is why Marc Weber thinks that it doesn't make sense to repeat the same
|
||||||
|
repetitive information everywhere.
|
||||||
|
|
||||||
|
*Recommended way:*
|
||||||
|
[vim-addon-manager](vim-addon-manager) (because Marc Weber wrote it for exactly
|
||||||
|
this reason, it supports simple dependency management). Eg you're done by this
|
||||||
|
line in your .vimrc:
|
||||||
|
|
||||||
|
```
|
||||||
|
" assuming you want to use snipmate snippet engine
|
||||||
|
ActivateAddons vim-snippets snipmate
|
||||||
|
```
|
||||||
|
|
||||||
|
[vim-pi](https://bitbucket.org/vimcommunity/vim-pi/issue/90/we-really-need-a-web-interface)
|
||||||
|
Is the place to discuss plugin managers and repository resources.
|
||||||
|
|
||||||
|
About how to install snipate see [snipmate@garbas](https://github.com/garbas/vim-snipmate)
|
||||||
|
|
||||||
|
(Bundle, Pathogen, git clone - keywords to make people find this link by ctrl-f search)
|
||||||
|
I know that I should be reading the docs of the snippet engine, just let me copy paste into my .vmirc:
|
||||||
|
(See this pull request)[https://github.com/honza/vim-snippets/pull/307/files].
|
||||||
|
|
||||||
Policies / for contributors
|
Policies / for contributors
|
||||||
===========================
|
===========================
|
||||||
Some snippets are useful for almost all languages, so let's try to have the same
|
Some snippets are useful for almost all languages, so let's try to have the same
|
||||||
|
|
|
@ -90,7 +90,7 @@ snippet class
|
||||||
${0}
|
${0}
|
||||||
}
|
}
|
||||||
snippet node
|
snippet node
|
||||||
node "${1:`vim_snippets#Filename('', 'fqdn')`}" {
|
node '${1:`vim_snippets#Filename('', 'fqdn')`}' {
|
||||||
${0}
|
${0}
|
||||||
}
|
}
|
||||||
snippet case
|
snippet case
|
||||||
|
@ -122,99 +122,99 @@ snippet [
|
||||||
snippet >
|
snippet >
|
||||||
${1} => ${0}
|
${1} => ${0}
|
||||||
snippet p:
|
snippet p:
|
||||||
"puppet://puppet/${1:module name}/${0:file name}"
|
'puppet://puppet/${1:module name}/${0:file name}'
|
||||||
#
|
#
|
||||||
# Functions
|
# Functions
|
||||||
snippet alert
|
snippet alert
|
||||||
alert("${1:message}")
|
alert('${1:message}')
|
||||||
snippet crit
|
snippet crit
|
||||||
crit("${1:message}")
|
crit('${1:message}')
|
||||||
snippet debug
|
snippet debug
|
||||||
debug("${1:message}")
|
debug('${1:message}')
|
||||||
snippet defined
|
snippet defined
|
||||||
defined(${1:Resource}["${2:name}"])
|
defined(${1:Resource}['${2:name}'])
|
||||||
snippet emerg
|
snippet emerg
|
||||||
emerg("${1:message}")
|
emerg('${1:message}')
|
||||||
snippet extlookup Simple extlookup
|
snippet extlookup Simple extlookup
|
||||||
extlookup("${1:variable}")
|
extlookup('${1:variable}')
|
||||||
snippet extlookup Extlookup with defaults
|
snippet extlookup Extlookup with defaults
|
||||||
extlookup("${1:variable}", "${2:default}")
|
extlookup('${1:variable}', '${2:default}')
|
||||||
snippet extlookup Extlookup with defaults and custom data file
|
snippet extlookup Extlookup with defaults and custom data file
|
||||||
extlookup("${1:variable}", "${2:default}", "${3:data source}")
|
extlookup('${1:variable}', '${2:default}', '${3:data source}')
|
||||||
snippet fail
|
snippet fail
|
||||||
fail("${1:message}")
|
fail('${1:message}')
|
||||||
snippet info
|
snippet info
|
||||||
info("${1:message}")
|
info('${1:message}')
|
||||||
snippet inline_template
|
snippet inline_template
|
||||||
inline_template("<%= ${1} %>")
|
inline_template('<%= ${1} %>')
|
||||||
snippet notice
|
snippet notice
|
||||||
notice("${1:message}")
|
notice('${1:message}')
|
||||||
snippet realize
|
snippet realize
|
||||||
realize(${1:Resource}[${2:name}])
|
realize(${1:Resource}[${2:name}])
|
||||||
snippet regsubst
|
snippet regsubst
|
||||||
regsubst(${1:hay stack}, ${2:needle}, "${3:replacement}")
|
regsubst(${1:hay stack}, ${2:needle}, '${3:replacement}')
|
||||||
snippet inc
|
snippet inc
|
||||||
include ${1:classname}
|
include ${1:classname}
|
||||||
snippet split
|
snippet split
|
||||||
split(${1:hay stack}, "${2:patten}")
|
split(${1:hay stack}, '${2:patten}')
|
||||||
snippet versioncmp
|
snippet versioncmp
|
||||||
versioncmp("${1:version}", "${2:version}")
|
versioncmp('${1:version}', '${2:version}')
|
||||||
snippet warning
|
snippet warning
|
||||||
warning("${1:message}")
|
warning('${1:message}')
|
||||||
#
|
#
|
||||||
# Types
|
# Types
|
||||||
snippet cron
|
snippet cron
|
||||||
cron{ "${1:name}":
|
cron { '${1:name}':
|
||||||
command => "${2}",
|
command => '${2}',
|
||||||
user => "${3:root}",
|
user => '${3:root}',
|
||||||
${4} => ${0}
|
${4} => ${0},
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet exec
|
snippet exec
|
||||||
exec{ "${1:name}":
|
exec { '${1:name}':
|
||||||
command => "${2:$1}",
|
command => '${2:$1}',
|
||||||
user => "${3:root}",
|
user => '${3:root}',
|
||||||
${4} => ${0}
|
${4} => ${0},
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet user
|
snippet user
|
||||||
user{ "${1:user}":
|
user { '${1:user}':
|
||||||
comment => "${2:$1}",
|
|
||||||
ensure => present,
|
ensure => present,
|
||||||
|
comment => '${2:$1}',
|
||||||
managehome => true,
|
managehome => true,
|
||||||
home => "${0:/home/$1}"
|
home => '${0:/home/$1}',
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet group
|
snippet group
|
||||||
group{ "${1:group}":
|
group { '${1:group}':
|
||||||
ensure => ${0:present}
|
ensure => ${0:present},
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet host
|
snippet host
|
||||||
host{ "${1:hostname}":
|
host { '${1:hostname}':
|
||||||
ip => ${0:127.0.0.1}
|
ip => ${0:127.0.0.1},
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet mailalias
|
snippet mailalias
|
||||||
mailalias{ "${1:localpart}":
|
mailalias { '${1:localpart}':
|
||||||
recipient => "${0:recipient}"
|
recipient => '${0:recipient}',
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet mount
|
snippet mount
|
||||||
mount{ "${1:destination path}":
|
mount { '${1:destination path}':
|
||||||
ensure => ${2:mounted},
|
ensure => ${2:mounted},
|
||||||
device => "${0:device name or path}"
|
device => '${0:device name or path}',
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet package
|
snippet package
|
||||||
package{ "${1:package name}":
|
package { '${1:package name}':
|
||||||
ensure => ${0:present}
|
ensure => ${0:present},
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet yumrepo
|
snippet yumrepo
|
||||||
yumrepo{ "${1:repo name}":
|
yumrepo { '${1:repo name}':
|
||||||
descr => "${2:$1}",
|
Descr => '${2:$1}',
|
||||||
enabled => ${0:1}
|
enabled => ${0:1},
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet define
|
snippet define
|
||||||
|
@ -227,7 +227,7 @@ snippet service
|
||||||
ensure => running,
|
ensure => running,
|
||||||
enable => true,
|
enable => true,
|
||||||
require => [ Package['${2:package}'], File['${3:file}'], ],
|
require => [ Package['${2:package}'], File['${3:file}'], ],
|
||||||
subscribe => [ File['${4:configfile1}'], File['${5:configfile2}'], Package['${6:package}'], ]
|
subscribe => [ File['${4:configfile1}'], File['${5:configfile2}'], Package['${6:package}'], ],
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet file
|
snippet file
|
||||||
|
|
|
@ -35,6 +35,7 @@ vim-fugitive https://github.com/tpope/vim-fugitive
|
||||||
vim-airline https://github.com/bling/vim-airline
|
vim-airline https://github.com/bling/vim-airline
|
||||||
goyo.vim https://github.com/junegunn/goyo.vim
|
goyo.vim https://github.com/junegunn/goyo.vim
|
||||||
vim-zenroom2 https://github.com/amix/vim-zenroom2
|
vim-zenroom2 https://github.com/amix/vim-zenroom2
|
||||||
|
pyflakes-pathogen https://github.com/mitechie/pyflakes-pathogen
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|
||||||
GITHUB_ZIP = '%s/archive/master.zip'
|
GITHUB_ZIP = '%s/archive/master.zip'
|
||||||
|
|
|
@ -293,23 +293,21 @@ autocmd BufWrite *.coffee :call DeleteTrailingWS()
|
||||||
|
|
||||||
|
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
" => vimgrep searching and cope displaying
|
" => Ack searching and cope displaying
|
||||||
|
" requires ack.vim - it's much better than vimgrep/grep
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
" When you press gv you vimgrep after the selected text
|
" When you press gv you Ack after the selected text
|
||||||
vnoremap <silent> gv :call VisualSelection('gv', '')<CR>
|
vnoremap <silent> gv :call VisualSelection('gv', '')<CR>
|
||||||
|
|
||||||
" Open vimgrep and put the cursor in the right position
|
" Open Ack and put the cursor in the right position
|
||||||
map <leader>g :vimgrep // **/*.<left><left><left><left><left><left><left>
|
map <leader>g :Ack
|
||||||
|
|
||||||
" Vimgreps in the current file
|
|
||||||
map <leader><space> :vimgrep // <C-R>%<C-A><right><right><right><right><right><right><right><right><right>
|
|
||||||
|
|
||||||
" When you press <leader>r you can search and replace the selected text
|
" When you press <leader>r you can search and replace the selected text
|
||||||
vnoremap <silent> <leader>r :call VisualSelection('replace', '')<CR>
|
vnoremap <silent> <leader>r :call VisualSelection('replace', '')<CR>
|
||||||
|
|
||||||
" Do :help cope if you are unsure what cope is. It's super useful!
|
" Do :help cope if you are unsure what cope is. It's super useful!
|
||||||
"
|
"
|
||||||
" When you search with vimgrep, display your results in cope by doing:
|
" When you search with Ack, display your results in cope by doing:
|
||||||
" <leader>cc
|
" <leader>cc
|
||||||
"
|
"
|
||||||
" To go to the next search result do:
|
" To go to the next search result do:
|
||||||
|
@ -373,7 +371,7 @@ function! VisualSelection(direction, extra_filter) range
|
||||||
if a:direction == 'b'
|
if a:direction == 'b'
|
||||||
execute "normal ?" . l:pattern . "^M"
|
execute "normal ?" . l:pattern . "^M"
|
||||||
elseif a:direction == 'gv'
|
elseif a:direction == 'gv'
|
||||||
call CmdLine("vimgrep " . '/'. l:pattern . '/' . ' **/*.' . a:extra_filter)
|
call CmdLine("Ack \"" . l:pattern . "\" " )
|
||||||
elseif a:direction == 'replace'
|
elseif a:direction == 'replace'
|
||||||
call CmdLine("%s" . '/'. l:pattern . '/')
|
call CmdLine("%s" . '/'. l:pattern . '/')
|
||||||
elseif a:direction == 'f'
|
elseif a:direction == 'f'
|
||||||
|
|
Loading…
Reference in a new issue