├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── .travis.yml ├── AUTHORS ├── COPYING ├── Changelog.rst ├── Gemfile ├── Makefile ├── README ├── README.rst ├── Rakefile ├── after ├── ftplugin │ ├── pyrex.vim │ └── python.vim └── indent │ ├── pyrex.vim │ └── python.vim ├── autoload ├── pymode.vim └── pymode │ ├── breakpoint.vim │ ├── doc.vim │ ├── folding.vim │ ├── indent.vim │ ├── lint.vim │ ├── motion.vim │ ├── rope.vim │ ├── run.vim │ ├── tools │ ├── loclist.vim │ └── signs.vim │ ├── troubleshooting.vim │ └── virtualenv.vim ├── doc └── pymode.txt ├── ftplugin ├── debug.vim ├── pyrex.vim └── python │ └── pymode.vim ├── logo.png ├── plugin └── pymode.vim ├── pylama.ini ├── pymode ├── __init__.py ├── _compat.py ├── async.py ├── autopep8.py ├── environment.py ├── libs │ └── pylama │ │ ├── __init__.py │ │ ├── config.py │ │ ├── core.py │ │ ├── errors.py │ │ ├── hook.py │ │ ├── libs │ │ ├── __init__.py │ │ ├── importlib.py │ │ └── inirama.py │ │ ├── lint │ │ ├── __init__.py │ │ ├── extensions.py │ │ ├── pylama_mccabe │ │ │ ├── __init__.py │ │ │ └── mccabe.py │ │ ├── pylama_pep257 │ │ │ ├── __init__.py │ │ │ └── pep257.py │ │ ├── pylama_pep8 │ │ │ ├── __init__.py │ │ │ └── pep8.py │ │ ├── pylama_pyflakes │ │ │ ├── __init__.py │ │ │ └── pyflakes │ │ │ │ ├── __init__.py │ │ │ │ ├── checker.py │ │ │ │ └── messages.py │ │ └── pylama_pylint │ │ │ ├── __init__.py │ │ │ ├── astroid │ │ │ ├── __init__.py │ │ │ ├── __pkginfo__.py │ │ │ ├── as_string.py │ │ │ ├── bases.py │ │ │ ├── brain │ │ │ │ ├── py2gi.py │ │ │ │ ├── py2mechanize.py │ │ │ │ ├── py2qt4.py │ │ │ │ └── py2stdlib.py │ │ │ ├── builder.py │ │ │ ├── exceptions.py │ │ │ ├── inference.py │ │ │ ├── manager.py │ │ │ ├── mixins.py │ │ │ ├── node_classes.py │ │ │ ├── nodes.py │ │ │ ├── protocols.py │ │ │ ├── raw_building.py │ │ │ ├── rebuilder.py │ │ │ ├── scoped_nodes.py │ │ │ └── utils.py │ │ │ ├── logilab │ │ │ ├── __init__.py │ │ │ └── common │ │ │ │ ├── __init__.py │ │ │ │ ├── __pkginfo__.py │ │ │ │ ├── changelog.py │ │ │ │ ├── compat.py │ │ │ │ ├── configuration.py │ │ │ │ ├── decorators.py │ │ │ │ ├── deprecation.py │ │ │ │ ├── graph.py │ │ │ │ ├── interface.py │ │ │ │ ├── modutils.py │ │ │ │ ├── optik_ext.py │ │ │ │ ├── textutils.py │ │ │ │ ├── tree.py │ │ │ │ ├── ureports │ │ │ │ ├── __init__.py │ │ │ │ ├── docbook_writer.py │ │ │ │ ├── html_writer.py │ │ │ │ ├── nodes.py │ │ │ │ └── text_writer.py │ │ │ │ └── visitor.py │ │ │ ├── main.py │ │ │ ├── pylint.rc │ │ │ └── pylint │ │ │ ├── __init__.py │ │ │ ├── __pkginfo__.py │ │ │ ├── checkers │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── classes.py │ │ │ ├── design_analysis.py │ │ │ ├── exceptions.py │ │ │ ├── format.py │ │ │ ├── imports.py │ │ │ ├── logging.py │ │ │ ├── misc.py │ │ │ ├── newstyle.py │ │ │ ├── raw_metrics.py │ │ │ ├── similar.py │ │ │ ├── stdlib.py │ │ │ ├── strings.py │ │ │ ├── typecheck.py │ │ │ ├── utils.py │ │ │ └── variables.py │ │ │ ├── config.py │ │ │ ├── interfaces.py │ │ │ ├── lint.py │ │ │ ├── reporters │ │ │ ├── __init__.py │ │ │ ├── guireporter.py │ │ │ ├── html.py │ │ │ └── text.py │ │ │ └── utils.py │ │ ├── main.py │ │ ├── pytest.py │ │ └── tasks.py ├── libs2 │ └── rope │ │ ├── __init__.py │ │ ├── base │ │ ├── __init__.py │ │ ├── arguments.py │ │ ├── ast.py │ │ ├── astutils.py │ │ ├── builtins.py │ │ ├── change.py │ │ ├── codeanalyze.py │ │ ├── default_config.py │ │ ├── evaluate.py │ │ ├── exceptions.py │ │ ├── fscommands.py │ │ ├── history.py │ │ ├── libutils.py │ │ ├── oi │ │ │ ├── __init__.py │ │ │ ├── doa.py │ │ │ ├── memorydb.py │ │ │ ├── objectdb.py │ │ │ ├── objectinfo.py │ │ │ ├── runmod.py │ │ │ ├── soa.py │ │ │ ├── soi.py │ │ │ └── transform.py │ │ ├── prefs.py │ │ ├── project.py │ │ ├── pycore.py │ │ ├── pynames.py │ │ ├── pynamesdef.py │ │ ├── pyobjects.py │ │ ├── pyobjectsdef.py │ │ ├── pyscopes.py │ │ ├── resourceobserver.py │ │ ├── resources.py │ │ ├── simplify.py │ │ ├── stdmods.py │ │ ├── taskhandle.py │ │ ├── utils.py │ │ └── worder.py │ │ ├── contrib │ │ ├── __init__.py │ │ ├── autoimport.py │ │ ├── changestack.py │ │ ├── codeassist.py │ │ ├── finderrors.py │ │ ├── findit.py │ │ ├── fixmodnames.py │ │ ├── fixsyntax.py │ │ └── generate.py │ │ └── refactor │ │ ├── __init__.py │ │ ├── change_signature.py │ │ ├── encapsulate_field.py │ │ ├── extract.py │ │ ├── functionutils.py │ │ ├── importutils │ │ ├── __init__.py │ │ ├── actions.py │ │ ├── importinfo.py │ │ └── module_imports.py │ │ ├── inline.py │ │ ├── introduce_factory.py │ │ ├── introduce_parameter.py │ │ ├── localtofield.py │ │ ├── method_object.py │ │ ├── move.py │ │ ├── multiproject.py │ │ ├── occurrences.py │ │ ├── patchedast.py │ │ ├── rename.py │ │ ├── restructure.py │ │ ├── similarfinder.py │ │ ├── sourceutils.py │ │ ├── suites.py │ │ ├── topackage.py │ │ ├── usefunction.py │ │ └── wildcards.py ├── libs3 │ └── rope │ │ ├── __init__.py │ │ ├── base │ │ ├── __init__.py │ │ ├── arguments.py │ │ ├── ast.py │ │ ├── astutils.py │ │ ├── builtins.py │ │ ├── change.py │ │ ├── codeanalyze.py │ │ ├── default_config.py │ │ ├── evaluate.py │ │ ├── exceptions.py │ │ ├── fscommands.py │ │ ├── history.py │ │ ├── libutils.py │ │ ├── oi │ │ │ ├── __init__.py │ │ │ ├── doa.py │ │ │ ├── memorydb.py │ │ │ ├── objectdb.py │ │ │ ├── objectinfo.py │ │ │ ├── runmod.py │ │ │ ├── soa.py │ │ │ ├── soi.py │ │ │ └── transform.py │ │ ├── prefs.py │ │ ├── project.py │ │ ├── pycore.py │ │ ├── pynames.py │ │ ├── pynamesdef.py │ │ ├── pyobjects.py │ │ ├── pyobjectsdef.py │ │ ├── pyscopes.py │ │ ├── resourceobserver.py │ │ ├── resources.py │ │ ├── simplify.py │ │ ├── stdmods.py │ │ ├── taskhandle.py │ │ ├── utils.py │ │ └── worder.py │ │ ├── contrib │ │ ├── __init__.py │ │ ├── autoimport.py │ │ ├── changestack.py │ │ ├── codeassist.py │ │ ├── finderrors.py │ │ ├── findit.py │ │ ├── fixmodnames.py │ │ ├── fixsyntax.py │ │ └── generate.py │ │ └── refactor │ │ ├── __init__.py │ │ ├── change_signature.py │ │ ├── encapsulate_field.py │ │ ├── extract.py │ │ ├── functionutils.py │ │ ├── importutils │ │ ├── __init__.py │ │ ├── actions.py │ │ ├── importinfo.py │ │ └── module_imports.py │ │ ├── inline.py │ │ ├── introduce_factory.py │ │ ├── introduce_parameter.py │ │ ├── localtofield.py │ │ ├── method_object.py │ │ ├── move.py │ │ ├── multiproject.py │ │ ├── occurrences.py │ │ ├── patchedast.py │ │ ├── rename.py │ │ ├── restructure.py │ │ ├── similarfinder.py │ │ ├── sourceutils.py │ │ ├── suites.py │ │ ├── topackage.py │ │ ├── usefunction.py │ │ └── wildcards.py ├── lint.py ├── rope.py ├── run.py ├── utils.py └── virtualenv.py ├── python-mode.yaml ├── syntax ├── pyrex.vim └── python.vim └── t ├── docs.vim ├── ftplugin.vim ├── indent.vim ├── lint.vim ├── plugin.vim ├── rope.vim ├── syntax.vim ├── test.py └── trouble.vim /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | *.sw? 3 | *~ 4 | .DS_Store 5 | .bundle 6 | .ropeproject 7 | .vim-flavor 8 | .vimrc 9 | Gemfile.lock 10 | VimFlavor.lock 11 | _ 12 | build 13 | tags 14 | test.py 15 | todo.txt 16 | vendor 17 | vim.py 18 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | vim-flavor 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-1.9.3 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | python: "2.7" 3 | rvm: 4 | - 1.9.3 5 | script: 6 | - make travis 7 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Maintainer: 2 | 3 | * Kirill Klenov 4 | 5 | 6 | Contributors: 7 | 8 | * Alvin Francis (http://github.com/alvinfrancis); 9 | * Anler Hp (http://github.com/ikame); 10 | * Anton Parkhomenko (http://github.com/chuwy); 11 | * Ashley Hewson (http://github.com/ashleyh); 12 | * Benjamin Ruston (http://github.com/bruston); 13 | * Boris Filippov (http://github.com/frenzykryger); 14 | * Brad Mease (http://github.com/bmease) 15 | * Daniel Hahler (http://github.com/blueyed) 16 | * David Vogt (http://github.com/winged); 17 | * Denis Kasak (http://github.com/dkasak); 18 | * Dirk Wallenstein (http://github.com/dirkwallenstein); 19 | * Florent Xicluna (http://github.com/florentx); 20 | * Fredrik Henrysson (http://github.com/fhenrysson); 21 | * Igor Guerrero (http://github.com/igorgue); 22 | * Jason Harvey (http://github.com/alienth) 23 | * Jay Rainey (https://github.com/jawrainey) 24 | * Jonathan McCall (http://github.com/Jonnymcc); 25 | * Kevin Deldycke (http://github.com/kdeldycke); 26 | * Lowe Thiderman (http://github.com/thiderman); 27 | * Martin Brochhaus (http://github.com/mbrochh); 28 | * Matthew Moses (http://github.com/mlmoses); 29 | * Mel Boyce (http://github.com/syngin) 30 | * Mohammed (http://github.com/mbadran); 31 | * Naoya Inada (http://github.com/naoina); 32 | * Pedro Algarvio (http://github.com/s0undt3ch); 33 | * Phillip Cloud (http://github.com/cpcloud); 34 | * Piet Delport (http://github.com/pjdelport); 35 | * Robert David Grant (http://github.com/bgrant); 36 | * Ronald Andreu Kaiser (http://github.com/cathoderay); 37 | * Sorin Ionescu (sorin-ionescu); 38 | * Steve Losh (http://github.com/sjl); 39 | * bendavis78 (http://github.com/bendavis78) 40 | * fwuzju (http://github.com/fwuzju) 41 | * lawrenceakka; 42 | * lee (loyalpartner); 43 | * nixon; 44 | * tramchamploo; 45 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'vim-flavor', '~> 1.1' 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PYMODE = $(CURDIR)/pymode 2 | LIBS = $(PYMODE)/libs 3 | PYLAMA = $(LIBS)/pylama 4 | 5 | .PHONY: clean 6 | clean: 7 | find $(CURDIR) -name "*.pyc" -delete 8 | rm -rf $(CURDIR)/build 9 | rm -rf *.deb 10 | 11 | # Temporary disable rope tests on Travis 12 | .PHONY: travis 13 | travis: 14 | rake test 15 | 16 | .PHONY: test t 17 | test: 18 | bundle install 19 | rm -rf $(CURDIR)/.ropeproject 20 | rake test 21 | t: test 22 | 23 | .PHONY: pylama 24 | pylama: 25 | rm -rf $(PYLAMA) 26 | make $(PYLAMA) 27 | make $(PYLAMA)/lint/pylama_pylint 28 | 29 | $(PYLAMA): 30 | cp -r ~/Dropbox/projects/pylama/pylama $(PYLAMA) 31 | 32 | $(PYLAMA)/lint/pylama_pylint: 33 | cp -r ~/Dropbox/projects/pylama/plugins/pylama_pylint/pylama_pylint/ $(PYLAMA)/lint/pylama_pylint 34 | 35 | $(CURDIR)/build: 36 | mkdir -p $(CURDIR)/build/usr/share/vim/addons 37 | mkdir -p $(CURDIR)/build/usr/share/vim/registry 38 | cp -r after autoload doc ftplugin plugin pymode syntax $(CURDIR)/build/usr/share/vim/addons/. 39 | cp -r python-mode.yaml $(CURDIR)/build/usr/share/vim/registry/. 40 | 41 | PACKAGE_VERSION?=$(shell git describe --tags `git rev-list master --tags --max-count=1`) 42 | PACKAGE_NAME="vim-python-mode" 43 | PACKAGE_MAINTAINER="Kirill Klenov " 44 | PACKAGE_URL=http://github.com/klen/python-mode 45 | deb: clean $(CURDIR)/build 46 | @fpm -s dir -t deb -a all \ 47 | -n $(PACKAGE_NAME) \ 48 | -v $(PACKAGE_VERSION) \ 49 | -m $(PACKAGE_MAINTAINER) \ 50 | --url $(PACKAGE_URL) \ 51 | --license "GNU lesser general public license" \ 52 | --description "Vim-Swissknife for python" \ 53 | --deb-user root \ 54 | --deb-group root \ 55 | -C $(CURDIR)/build \ 56 | -d "python2.7" \ 57 | -d "vim-addon-manager" \ 58 | usr 59 | @mv *.deb ~/Dropbox/projects/deb/load 60 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a mirror of http://www.vim.org/scripts/script.php?script_id=3770 2 | 3 | Python-mode is a vim plugin that allows you to use the pylint, rope, pydoc library in vim to provide features like python code looking for bugs, refactoring and some other usefull things. 4 | 5 | This plugin allow you create python code in vim very easily. There is no need to install the pylint or rope library on your system. 6 | 7 | See screencast here: http://t.co/3b0bzeXA (sory for quality, this my first screencasting) 8 | 9 | Python-mode on github: https://github.com/klen/python-mode 10 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | task :ci => [:dump, :test] 4 | 5 | task :dump do 6 | sh 'vim --version' 7 | end 8 | 9 | task :test do 10 | sh 'bundle exec vim-flavor test' 11 | end 12 | -------------------------------------------------------------------------------- /after/ftplugin/pyrex.vim: -------------------------------------------------------------------------------- 1 | runtime after/ftplugin/python.vim 2 | -------------------------------------------------------------------------------- /after/ftplugin/python.vim: -------------------------------------------------------------------------------- 1 | if !g:pymode 2 | finish 3 | endif 4 | 5 | if g:pymode_motion 6 | 7 | if !&magic 8 | if g:pymode_warning 9 | call pymode#error("Pymode motion requires `&magic` option. Enable them or disable g:pymode_motion") 10 | endif 11 | finish 12 | endif 13 | 14 | nnoremap ]] :call pymode#motion#move('v^(classdef)s', '') 15 | nnoremap [[ :call pymode#motion#move('v^(classdef)s', 'b') 16 | nnoremap ]C :call pymode#motion#move('v^(classdef)s', '') 17 | nnoremap [C :call pymode#motion#move('v^(classdef)s', 'b') 18 | nnoremap ]M :call pymode#motion#move('^s*defs', '') 19 | nnoremap [M :call pymode#motion#move('^s*defs', 'b') 20 | 21 | onoremap ]] :call pymode#motion#move('v^(classdef)s', '') 22 | onoremap [[ :call pymode#motion#move('v^(classdef)s', 'b') 23 | onoremap ]C :call pymode#motion#move('v^(classdef)s', '') 24 | onoremap [C :call pymode#motion#move('v^(classdef)s', 'b') 25 | onoremap ]M :call pymode#motion#move('^s*defs', '') 26 | onoremap [M :call pymode#motion#move('^s*defs', 'b') 27 | 28 | vnoremap ]] :call pymode#motion#vmove('v^(classdef)s', '') 29 | vnoremap [[ :call pymode#motion#vmove('v^(classdef)s', 'b') 30 | vnoremap ]M :call pymode#motion#vmove('^s*defs', '') 31 | vnoremap [M :call pymode#motion#vmove('^s*defs', 'b') 32 | 33 | onoremap C :call pymode#motion#select('^s*classs', 0) 34 | onoremap aC :call pymode#motion#select('^s*classs', 0) 35 | onoremap iC :call pymode#motion#select('^s*classs', 1) 36 | vnoremap aC :call pymode#motion#select('^s*classs', 0) 37 | vnoremap iC :call pymode#motion#select('^s*classs', 1) 38 | 39 | onoremap M :call pymode#motion#select('^s*defs', 0) 40 | onoremap aM :call pymode#motion#select('^s*defs', 0) 41 | onoremap iM :call pymode#motion#select('^s*defs', 1) 42 | vnoremap aM :call pymode#motion#select('^s*defs', 0) 43 | vnoremap iM :call pymode#motion#select('^s*defs', 1) 44 | 45 | endif 46 | 47 | if g:pymode_rope && g:pymode_rope_completion 48 | 49 | setlocal omnifunc=pymode#rope#completions 50 | 51 | if g:pymode_rope_completion_bind != "" 52 | exe "inoremap " . g:pymode_rope_completion_bind . " =pymode#rope#complete(0)" 53 | if tolower(g:pymode_rope_completion_bind) == '' 54 | exe "inoremap =pymode#rope#complete(0)" 55 | endif 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /after/indent/pyrex.vim: -------------------------------------------------------------------------------- 1 | runtime after/indent/python.vim 2 | -------------------------------------------------------------------------------- /after/indent/python.vim: -------------------------------------------------------------------------------- 1 | if !g:pymode || !g:pymode_indent 2 | finish 3 | endif 4 | 5 | 6 | setlocal nolisp 7 | setlocal tabstop=4 8 | setlocal softtabstop=4 9 | setlocal shiftwidth=4 10 | setlocal shiftround 11 | setlocal expandtab 12 | setlocal autoindent 13 | setlocal indentexpr=pymode#indent#get_indent(v:lnum) 14 | setlocal indentkeys=!^F,o,O,<:>,0),0],0},=elif,=except 15 | -------------------------------------------------------------------------------- /autoload/pymode/breakpoint.vim: -------------------------------------------------------------------------------- 1 | fun! pymode#breakpoint#init() "{{{ 2 | 3 | if !g:pymode_breakpoint 4 | return 5 | endif 6 | 7 | if g:pymode_breakpoint_cmd == '' 8 | let g:pymode_breakpoint_cmd = 'import pdb; pdb.set_trace() # XXX BREAKPOINT' 9 | 10 | if g:pymode_python == 'disable' 11 | return 12 | endif 13 | 14 | endif 15 | 16 | PymodePython << EOF 17 | 18 | from imp import find_module 19 | 20 | for module in ('pudb', 'ipdb'): 21 | try: 22 | find_module(module) 23 | vim.command('let g:pymode_breakpoint_cmd = "import %s; %s.set_trace() # XXX BREAKPOINT"' % (module, module)) 24 | break 25 | except ImportError: 26 | continue 27 | 28 | EOF 29 | 30 | endfunction "}}} 31 | 32 | fun! pymode#breakpoint#operate(lnum) "{{{ 33 | let line = getline(a:lnum) 34 | if strridx(line, g:pymode_breakpoint_cmd) != -1 35 | normal dd 36 | else 37 | let plnum = prevnonblank(a:lnum) 38 | call append(line('.')-1, repeat(' ', indent(plnum)).g:pymode_breakpoint_cmd) 39 | normal k 40 | endif 41 | 42 | " Save file without any events 43 | call pymode#save() 44 | 45 | endfunction "}}} 46 | -------------------------------------------------------------------------------- /autoload/pymode/doc.vim: -------------------------------------------------------------------------------- 1 | " Python-mode search by documentation 2 | " 3 | PymodePython import pymode 4 | 5 | fun! pymode#doc#find() "{{{ 6 | " Extract the 'word' at the cursor, expanding leftwards across identifiers 7 | " and the . operator, and rightwards across the identifier only. 8 | " 9 | " For example: 10 | " import xml.dom.minidom 11 | " ^ ! 12 | " 13 | " With the cursor at ^ this returns 'xml'; at ! it returns 'xml.dom'. 14 | let l:line = getline(".") 15 | let l:pre = l:line[:col(".") - 1] 16 | let l:suf = l:line[col("."):] 17 | let word = matchstr(pre, "[A-Za-z0-9_.]*$") . matchstr(suf, "^[A-Za-z0-9_]*") 18 | call pymode#doc#show(word) 19 | endfunction "}}} 20 | 21 | fun! pymode#doc#show(word) "{{{ 22 | if a:word == '' 23 | call pymode#error("No name/symbol under cursor!") 24 | return 0 25 | endif 26 | 27 | call pymode#tempbuffer_open('__doc__') 28 | PymodePython pymode.get_documentation() 29 | setlocal nomodifiable 30 | setlocal nomodified 31 | setlocal filetype=rst 32 | wincmd p 33 | 34 | endfunction "}}} 35 | -------------------------------------------------------------------------------- /autoload/pymode/folding.vim: -------------------------------------------------------------------------------- 1 | " Python-mode folding functions 2 | 3 | 4 | let s:def_regex = g:pymode_folding_regex 5 | let s:blank_regex = '^\s*$' 6 | let s:decorator_regex = '^\s*@' 7 | let s:doc_begin_regex = '^\s*\%("""\|''''''\)' 8 | let s:doc_end_regex = '\%("""\|''''''\)\s*$' 9 | let s:doc_line_regex = '^\s*\("""\|''''''\).\+\1\s*$' 10 | let s:symbol = matchstr(&fillchars, 'fold:\zs.') " handles multibyte characters 11 | if s:symbol == '' 12 | let s:symbol = ' ' 13 | endif 14 | 15 | 16 | fun! pymode#folding#text() " {{{ 17 | let fs = v:foldstart 18 | while getline(fs) =~ '\%(^\s*@\)\|\%(^\s*\%("""\|''''''\)\s*$\)' 19 | let fs = nextnonblank(fs + 1) 20 | endwhile 21 | let line = getline(fs) 22 | 23 | let nucolwidth = &fdc + &number * &numberwidth 24 | let windowwidth = winwidth(0) - nucolwidth - 6 25 | let foldedlinecount = v:foldend - v:foldstart 26 | 27 | " expand tabs into spaces 28 | let onetab = strpart(' ', 0, &tabstop) 29 | let line = substitute(line, '\t', onetab, 'g') 30 | 31 | let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount)) 32 | let line = substitute(line, '\%("""\|''''''\)', '', '') 33 | let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + 1 34 | return line . ' ' . repeat(s:symbol, fillcharcount) . ' ' . foldedlinecount 35 | endfunction "}}} 36 | 37 | 38 | fun! pymode#folding#expr(lnum) "{{{ 39 | 40 | let line = getline(a:lnum) 41 | let indent = indent(a:lnum) 42 | let prev_line = getline(a:lnum - 1) 43 | 44 | if line =~ s:def_regex || line =~ s:decorator_regex 45 | if prev_line =~ s:decorator_regex 46 | return '=' 47 | else 48 | return ">".(indent / &shiftwidth + 1) 49 | endif 50 | endif 51 | 52 | if line =~ s:doc_begin_regex && line !~ s:doc_line_regex && prev_line =~ s:def_regex 53 | return ">".(indent / &shiftwidth + 1) 54 | endif 55 | 56 | if line =~ s:doc_end_regex && line !~ s:doc_line_regex 57 | return "<".(indent / &shiftwidth + 1) 58 | endif 59 | 60 | if line =~ s:blank_regex 61 | if prev_line =~ s:blank_regex 62 | if indent(a:lnum + 1) == 0 && getline(a:lnum + 1) !~ s:blank_regex 63 | return 0 64 | endif 65 | return -1 66 | else 67 | return '=' 68 | endif 69 | endif 70 | 71 | if indent == 0 72 | return 0 73 | endif 74 | 75 | return '=' 76 | 77 | endfunction "}}} 78 | 79 | 80 | " vim: fdm=marker:fdl=0 81 | -------------------------------------------------------------------------------- /autoload/pymode/lint.vim: -------------------------------------------------------------------------------- 1 | PymodePython from pymode.lint import code_check 2 | 3 | call pymode#tools#signs#init() 4 | call pymode#tools#loclist#init() 5 | 6 | 7 | fun! pymode#lint#auto() "{{{ 8 | if !pymode#save() 9 | return 0 10 | endif 11 | PymodePython from pymode import auto 12 | PymodePython auto() 13 | cclose 14 | call g:PymodeSigns.clear() 15 | edit 16 | call pymode#wide_message("AutoPep8 done.") 17 | endfunction "}}} 18 | 19 | 20 | fun! pymode#lint#show_errormessage() "{{{ 21 | let loclist = g:PymodeLocList.current() 22 | if loclist.is_empty() 23 | return 24 | endif 25 | 26 | let l = line('.') 27 | if l == b:pymode_error_line 28 | return 29 | endif 30 | let b:pymode_error_line = l 31 | if has_key(loclist._messages, l) 32 | call pymode#wide_message(loclist._messages[l]) 33 | else 34 | echo 35 | endif 36 | endfunction "}}} 37 | 38 | 39 | fun! pymode#lint#toggle() "{{{ 40 | let g:pymode_lint = g:pymode_lint ? 0 : 1 41 | if g:pymode_lint 42 | call pymode#wide_message("Code checking is enabled.") 43 | else 44 | call pymode#wide_message("Code checking is disabled.") 45 | end 46 | endfunction "}}} 47 | 48 | 49 | fun! pymode#lint#check() "{{{ 50 | " DESC: Run checkers on current file. 51 | " 52 | let loclist = g:PymodeLocList.current() 53 | 54 | let b:pymode_error_line = -1 55 | 56 | call loclist.clear() 57 | 58 | call pymode#wide_message('Code checking is running ...') 59 | 60 | PymodePython code_check() 61 | 62 | if loclist.is_empty() 63 | call pymode#wide_message('Code checking is completed. No errors found.') 64 | endif 65 | 66 | call g:PymodeSigns.refresh(loclist) 67 | 68 | if g:pymode_lint_cwindow 69 | call loclist.show() 70 | endif 71 | 72 | call pymode#lint#show_errormessage() 73 | call pymode#wide_message('Found errors and warnings: ' . len(loclist._loclist)) 74 | 75 | endfunction " }}} 76 | 77 | 78 | fun! pymode#lint#tick_queue() "{{{ 79 | 80 | python import time 81 | python print time.time() 82 | 83 | if mode() == 'i' 84 | if col('.') == 1 85 | call feedkeys("\\", "n") 86 | else 87 | call feedkeys("\\", "n") 88 | endif 89 | else 90 | call feedkeys("f\e", "n") 91 | endif 92 | endfunction "}}} 93 | 94 | 95 | fun! pymode#lint#stop() "{{{ 96 | au! pymode CursorHold 97 | endfunction "}}} 98 | 99 | 100 | fun! pymode#lint#start() "{{{ 101 | au! pymode CursorHold call pymode#lint#tick_queue() 102 | call pymode#lint#tick_queue() 103 | endfunction "}}} 104 | -------------------------------------------------------------------------------- /autoload/pymode/motion.vim: -------------------------------------------------------------------------------- 1 | " Python-mode motion functions 2 | 3 | 4 | fun! pymode#motion#move(pattern, flags, ...) "{{{ 5 | let cnt = v:count1 - 1 6 | let [line, column] = searchpos(a:pattern, a:flags . 'sW') 7 | let indent = indent(line) 8 | while cnt && line 9 | let [line, column] = searchpos(a:pattern, a:flags . 'W') 10 | if indent(line) == indent 11 | let cnt = cnt - 1 12 | endif 13 | endwhile 14 | return [line, column] 15 | endfunction "}}} 16 | 17 | 18 | fun! pymode#motion#vmove(pattern, flags) range "{{{ 19 | call cursor(a:lastline, 0) 20 | let end = pymode#motion#move(a:pattern, a:flags) 21 | call cursor(a:firstline, 0) 22 | normal! v 23 | call cursor(end) 24 | endfunction "}}} 25 | 26 | 27 | fun! pymode#motion#pos_le(pos1, pos2) "{{{ 28 | return ((a:pos1[0] < a:pos2[0]) || (a:pos1[0] == a:pos2[0] && a:pos1[1] <= a:pos2[1])) 29 | endfunction "}}} 30 | 31 | 32 | fun! pymode#motion#select(pattern, inner) "{{{ 33 | let cnt = v:count1 - 1 34 | let orig = getpos('.')[1:2] 35 | let snum = s:BlockStart(orig[0], a:pattern) 36 | if getline(snum) !~ a:pattern 37 | return 0 38 | endif 39 | let enum = s:BlockEnd(snum, indent(snum)) 40 | while cnt 41 | let lnum = search(a:pattern, 'nW') 42 | if lnum 43 | let enum = s:BlockEnd(lnum, indent(lnum)) 44 | call cursor(enum, 1) 45 | endif 46 | let cnt = cnt - 1 47 | endwhile 48 | if pymode#motion#pos_le([snum, 0], orig) && pymode#motion#pos_le(orig, [enum, 1]) 49 | if a:inner 50 | let snum = snum + 1 51 | let enum = prevnonblank(enum) 52 | endif 53 | 54 | call cursor(snum, 1) 55 | normal! v 56 | call cursor(enum, len(getline(enum))) 57 | endif 58 | endfunction "}}} 59 | 60 | 61 | fun! s:BlockStart(lnum, ...) "{{{ 62 | let pattern = a:0 ? a:1 : '^\s*\(@\|class\s.*:\|def\s\)' 63 | let lnum = a:lnum + 1 64 | let indent = 100 65 | while lnum 66 | let lnum = prevnonblank(lnum - 1) 67 | let test = indent(lnum) 68 | let line = getline(lnum) 69 | if line =~ '^\s*#' " Skip comments 70 | continue 71 | elseif !test " Zero-level regular line 72 | return lnum 73 | elseif test >= indent " Skip deeper or equal lines 74 | continue 75 | " Indent is strictly less at this point: check for def/class 76 | elseif line =~ pattern && line !~ '^\s*@' 77 | return lnum 78 | endif 79 | let indent = indent(lnum) 80 | endwhile 81 | return 0 82 | endfunction "}}} 83 | 84 | 85 | fun! s:BlockEnd(lnum, ...) "{{{ 86 | let indent = a:0 ? a:1 : indent(a:lnum) 87 | let lnum = a:lnum 88 | while lnum 89 | let lnum = nextnonblank(lnum + 1) 90 | if getline(lnum) =~ '^\s*#' | continue 91 | elseif lnum && indent(lnum) <= indent 92 | return lnum - 1 93 | endif 94 | endwhile 95 | return line('$') 96 | endfunction "}}} 97 | " vim: fdm=marker:fdl=0 98 | -------------------------------------------------------------------------------- /autoload/pymode/run.vim: -------------------------------------------------------------------------------- 1 | " The following lines set Vim's errorformat variable, to allow the 2 | " quickfix window to show Python tracebacks properly. It is much 3 | " easier to use let than set, because set requires many more 4 | " characters to be escaped. This is much easier to read and 5 | " maintain. % escapes are still needed however before any regex meta 6 | " characters. Hence \S (non-whitespace) becomes %\S etc. Note that 7 | " * becomes %#, so .* (match any character) becomes %.%# Commas must 8 | " also be escaped, with a backslash (\,). See the Vim help on 9 | " quickfix for details. 10 | " 11 | " Python errors are multi-lined. They often start with 'Traceback', so 12 | " we want to capture that (with +G) and show it in the quickfix window 13 | " because it explains the order of error messages. 14 | let s:efm = '%+GTraceback%.%#,' 15 | 16 | " The error message itself starts with a line with 'File' in it. There 17 | " are a couple of variations, and we need to process a line beginning 18 | " with whitespace followed by File, the filename in "", a line number, 19 | " and optional further text. %E here indicates the start of a multi-line 20 | " error message. The %\C at the end means that a case-sensitive search is 21 | " required. 22 | let s:efm .= '%E File "%f"\, line %l\,%m%\C,' 23 | let s:efm .= '%E File "%f"\, line %l%\C,' 24 | 25 | " The possible continutation lines are idenitifed to Vim by %C. We deal 26 | " with these in order of most to least specific to ensure a proper 27 | " match. A pointer (^) identifies the column in which the error occurs 28 | " (but will not be entirely accurate due to indention of Python code). 29 | let s:efm .= '%C%p^,' 30 | 31 | " Any text, indented by more than two spaces contain useful information. 32 | " We want this to appear in the quickfix window, hence %+. 33 | let s:efm .= '%+C %.%#,' 34 | let s:efm .= '%+C %.%#,' 35 | 36 | " The last line (%Z) does not begin with any whitespace. We use a zero 37 | " width lookahead (\&) to check this. The line contains the error 38 | " message itself (%m) 39 | let s:efm .= '%Z%\S%\&%m,' 40 | 41 | " We can ignore any other lines (%-G) 42 | let s:efm .= '%-G%.%#' 43 | 44 | PymodePython from pymode.run import run_code 45 | 46 | call pymode#tools#loclist#init() 47 | 48 | 49 | " DESC: Run python code 50 | fun! pymode#run#code_run(line1, line2) "{{{ 51 | 52 | let l:output = [] 53 | let l:traceback = [] 54 | call setqflist([]) 55 | 56 | call pymode#wide_message("Code running ...") 57 | 58 | try 59 | 60 | PymodePython run_code() 61 | 62 | if len(l:output) 63 | call pymode#tempbuffer_open('__run__') 64 | call append(line('$'), l:output) 65 | normal dd 66 | wincmd p 67 | else 68 | call pymode#wide_message("No output.") 69 | endif 70 | 71 | cexpr "" 72 | 73 | let l:_efm = &efm 74 | 75 | let &efm = s:efm 76 | 77 | cgetexpr(l:traceback) 78 | 79 | " If a range is run (starting other than at line 1), fix the reported error line numbers for 80 | " the current buffer 81 | if a:line1 > 1 82 | let qflist = getqflist() 83 | for i in qflist 84 | if i.bufnr == bufnr("") 85 | let i.lnum = i.lnum - 1 + a:line1 86 | endif 87 | endfor 88 | call setqflist(qflist) 89 | endif 90 | 91 | let loclist = g:PymodeLocList.current() 92 | let loclist._loclist = getqflist() 93 | let loclist._title = "Run errors" 94 | call loclist.show() 95 | 96 | let &efm = l:_efm 97 | 98 | catch /E234/ 99 | 100 | echohl Error | echo "Run-time error." | echohl none 101 | 102 | endtry 103 | 104 | endfunction "}}} 105 | -------------------------------------------------------------------------------- /autoload/pymode/tools/loclist.vim: -------------------------------------------------------------------------------- 1 | let g:PymodeLocList= {} 2 | 3 | 4 | fun! pymode#tools#loclist#init() "{{{ 5 | return 6 | endfunction "}}} 7 | 8 | 9 | fun! g:PymodeLocList.init(raw_list) "{{{ 10 | let obj = copy(self) 11 | let loc_list = filter(copy(a:raw_list), 'v:val["valid"] == 1') 12 | call obj.clear() 13 | let obj._title = 'CodeCheck' 14 | return obj 15 | endfunction "}}} 16 | 17 | 18 | fun! g:PymodeLocList.current() "{{{ 19 | if !exists("b:pymode_loclist") 20 | let b:pymode_loclist = g:PymodeLocList.init([]) 21 | endif 22 | return b:pymode_loclist 23 | endfunction "}}} 24 | 25 | 26 | fun! g:PymodeLocList.is_empty() "{{{ 27 | return empty(self._loclist) 28 | endfunction "}}} 29 | 30 | 31 | fun! g:PymodeLocList.clear() "{{{ 32 | let self._loclist = [] 33 | let self._messages = {} 34 | let self._name = expand('%:t') 35 | endfunction "}}} 36 | 37 | 38 | fun! g:PymodeLocList.extend(raw_list) "{{{ 39 | call extend(self._loclist, a:raw_list) 40 | for issue in a:raw_list 41 | let self._messages[issue.lnum] = issue.text 42 | endfor 43 | return self 44 | endfunction "}}} 45 | 46 | 47 | fun! g:PymodeLocList.filter(filters) "{{{ 48 | let loclist = [] 49 | for error in self._loclist 50 | let passes_filters = 1 51 | for key in keys(a:filters) 52 | if get(error, key, '') !=? a:filters[key] 53 | let passes_filters = 0 54 | break 55 | endif 56 | endfor 57 | 58 | if passes_filters 59 | call add(loclist, error) 60 | endif 61 | 62 | endfor 63 | return loclist 64 | endfunction "}}} 65 | 66 | 67 | fun! g:PymodeLocList.show() "{{{ 68 | call setloclist(0, self._loclist) 69 | if self.is_empty() 70 | lclose 71 | else 72 | let num = winnr() 73 | lopen 74 | execute max([min([line("$"), g:pymode_quickfix_maxheight]), g:pymode_quickfix_minheight]) . "wincmd _" 75 | if num != winnr() 76 | call setwinvar(winnr(), 'quickfix_title', self._title . ' <' . self._name . '>') 77 | exe num . "wincmd w" 78 | endif 79 | end 80 | endfunction "}}} 81 | -------------------------------------------------------------------------------- /autoload/pymode/tools/signs.vim: -------------------------------------------------------------------------------- 1 | let g:PymodeSigns = {} 2 | 3 | 4 | fun! pymode#tools#signs#init() "{{{ 5 | call g:PymodeSigns.setup() 6 | endfunction "}}} 7 | 8 | 9 | fun! g:PymodeSigns.enabled() "{{{ 10 | return (g:pymode_lint_signs && has('signs')) 11 | endfunction "}}} 12 | 13 | 14 | fun! g:PymodeSigns.setup() "{{{ 15 | if self.enabled() 16 | execute 'sign define PymodeW text=' . g:pymode_lint_todo_symbol . " texthl=Todo" 17 | execute 'sign define PymodeD text=' . g:pymode_lint_docs_symbol . " texthl=String" 18 | execute 'sign define PymodeC text=' . g:pymode_lint_comment_symbol . " texthl=Comment" 19 | execute 'sign define PymodeR text=' . g:pymode_lint_visual_symbol . " texthl=Visual" 20 | execute 'sign define PymodeE text=' . g:pymode_lint_error_symbol . " texthl=Error" 21 | execute 'sign define PymodeI text=' . g:pymode_lint_info_symbol . " texthl=Info" 22 | execute 'sign define PymodeF text=' . g:pymode_lint_pyflakes_symbol . " texthl=Info" 23 | endif 24 | let self._sign_ids = [] 25 | let self._next_id = 10000 26 | let self._messages = {} 27 | endfunction "}}} 28 | 29 | 30 | fun! g:PymodeSigns.refresh(loclist) "{{{ 31 | if self.enabled() 32 | call self.clear() 33 | call self.place(a:loclist) 34 | endif 35 | endfunction "}}} 36 | 37 | 38 | fun! g:PymodeSigns.clear() "{{{ 39 | let ids = copy(self._sign_ids) 40 | for i in ids 41 | execute "sign unplace " . i 42 | call remove(self._sign_ids, index(self._sign_ids, i)) 43 | endfor 44 | endfunction "}}} 45 | 46 | 47 | fun! g:PymodeSigns.place(loclist) "{{{ 48 | let seen = {} 49 | for issue in a:loclist._loclist 50 | if !has_key(seen, issue.lnum) 51 | let seen[issue.lnum] = 1 52 | call add(self._sign_ids, self._next_id) 53 | execute printf('sign place %d line=%d name=%s buffer=%d', self._next_id, issue.lnum, "Pymode".issue.type[0], issue.bufnr) 54 | let self._next_id += 1 55 | endif 56 | endfor 57 | endfunction "}}} 58 | -------------------------------------------------------------------------------- /autoload/pymode/virtualenv.vim: -------------------------------------------------------------------------------- 1 | " Support virtualenv 2 | " 3 | PymodePython from pymode.virtualenv import enable_virtualenv 4 | 5 | fun! pymode#virtualenv#init() "{{{ 6 | if !g:pymode_virtualenv || g:pymode_virtualenv_path == "" 7 | return 8 | endif 9 | 10 | PymodePython enable_virtualenv() 11 | 12 | endfunction "}}} 13 | 14 | fun! pymode#virtualenv#activate(relpath) "{{{ 15 | let g:pymode_virtualenv_path = getcwd() . '/' . a:relpath 16 | call pymode#virtualenv#init() 17 | endfunction "}}} 18 | -------------------------------------------------------------------------------- /ftplugin/debug.vim: -------------------------------------------------------------------------------- 1 | " Use this settings for testing the plugin. 2 | " Run vim with command 3 | " 4 | " $ vim -u debug.py 5 | " 6 | " Only python-mode will be loaded. 7 | 8 | 9 | execute('set rtp+='. expand(':p:h')) 10 | set rtp -=$HOME/.vim 11 | set rtp -=$HOME/.vim/after 12 | set nocp 13 | syntax enable 14 | -------------------------------------------------------------------------------- /ftplugin/pyrex.vim: -------------------------------------------------------------------------------- 1 | runtime ftplugin/python/pymode.vim 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vim-scripts/Python-mode-klen/1986bbd280cf7410b404e3253a572e6aa7ca65f6/logo.png -------------------------------------------------------------------------------- /pylama.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | ignore = R0201,R0922,E1103 3 | skip = pymode/autopep8.py 4 | -------------------------------------------------------------------------------- /pymode/__init__.py: -------------------------------------------------------------------------------- 1 | """ Pymode support functions. """ 2 | 3 | from __future__ import absolute_import 4 | 5 | import sys 6 | import vim # noqa 7 | 8 | 9 | def auto(): 10 | """ Fix PEP8 erorrs in current buffer. """ 11 | from .autopep8 import fix_file 12 | 13 | class Options(object): 14 | aggressive = 2 15 | diff = False 16 | experimental = True 17 | ignore = vim.eval('g:pymode_lint_ignore') 18 | in_place = True 19 | indent_size = int(vim.eval('&tabstop')) 20 | line_range = None 21 | max_line_length = 79 22 | pep8_passes = 100 23 | recursive = False 24 | select = vim.eval('g:pymode_lint_select') 25 | verbose = 0 26 | 27 | fix_file(vim.current.buffer.name, Options) 28 | 29 | 30 | def get_documentation(): 31 | """ Search documentation and append to current buffer. """ 32 | from ._compat import StringIO 33 | 34 | sys.stdout, _ = StringIO(), sys.stdout 35 | help(vim.eval('a:word')) 36 | sys.stdout, out = _, sys.stdout.getvalue() 37 | vim.current.buffer.append(str(out).splitlines(), 0) 38 | -------------------------------------------------------------------------------- /pymode/_compat.py: -------------------------------------------------------------------------------- 1 | """ Compatibility. 2 | 3 | Some py2/py3 compatibility support based on a stripped down 4 | version of six so we don't have to depend on a specific version 5 | of it. 6 | 7 | :copyright: (c) 2014 by Armin Ronacher. 8 | :license: BSD 9 | """ 10 | import sys 11 | 12 | PY2 = sys.version_info[0] == 2 13 | _identity = lambda x: x 14 | 15 | 16 | if not PY2: 17 | text_type = str 18 | string_types = (str,) 19 | integer_types = (int, ) 20 | 21 | iterkeys = lambda d: iter(d.keys()) 22 | itervalues = lambda d: iter(d.values()) 23 | iteritems = lambda d: iter(d.items()) 24 | 25 | from io import StringIO 26 | from queue import Queue # noqa 27 | 28 | def reraise(tp, value, tb=None): 29 | if value.__traceback__ is not tb: 30 | raise value.with_traceback(tb) 31 | raise value 32 | 33 | implements_to_string = _identity 34 | 35 | else: 36 | text_type = unicode 37 | string_types = (str, unicode) 38 | integer_types = (int, long) 39 | 40 | iterkeys = lambda d: d.iterkeys() 41 | itervalues = lambda d: d.itervalues() 42 | iteritems = lambda d: d.iteritems() 43 | 44 | from cStringIO import StringIO 45 | from Queue import Queue 46 | 47 | exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') 48 | 49 | def implements_to_string(cls): 50 | cls.__unicode__ = cls.__str__ 51 | cls.__str__ = lambda x: x.__unicode__().encode('utf-8') 52 | return cls 53 | 54 | 55 | def with_metaclass(meta, *bases): 56 | # This requires a bit of explanation: the basic idea is to make a 57 | # dummy metaclass for one level of class instantiation that replaces 58 | # itself with the actual metaclass. Because of internal type checks 59 | # we also need to make sure that we downgrade the custom metaclass 60 | # for one level to something closer to type (that's why __call__ and 61 | # __init__ comes back from type etc.). 62 | # 63 | # This has the advantage over six.with_metaclass in that it does not 64 | # introduce dummy classes into the final MRO. 65 | class metaclass(meta): 66 | __call__ = type.__call__ 67 | __init__ = type.__init__ 68 | def __new__(cls, name, this_bases, d): 69 | if this_bases is None: 70 | return type.__new__(cls, name, (), d) 71 | return meta(name, bases, d) 72 | return metaclass('temporary_class', None, {}) 73 | 74 | 75 | # Certain versions of pypy have a bug where clearing the exception stack 76 | # breaks the __exit__ function in a very peculiar way. This is currently 77 | # true for pypy 2.2.1 for instance. The second level of exception blocks 78 | # is necessary because pypy seems to forget to check if an exception 79 | # happend until the next bytecode instruction? 80 | BROKEN_PYPY_CTXMGR_EXIT = False 81 | if hasattr(sys, 'pypy_version_info'): 82 | class _Mgr(object): 83 | def __enter__(self): 84 | return self 85 | def __exit__(self, *args): 86 | sys.exc_clear() 87 | try: 88 | try: 89 | with _Mgr(): 90 | raise AssertionError() 91 | except: 92 | raise 93 | except TypeError: 94 | BROKEN_PYPY_CTXMGR_EXIT = True 95 | except AssertionError: 96 | pass 97 | 98 | # pylama:skip=1 99 | -------------------------------------------------------------------------------- /pymode/async.py: -------------------------------------------------------------------------------- 1 | """ Python-mode async support. """ 2 | 3 | from ._compat import Queue 4 | 5 | 6 | RESULTS = Queue() 7 | -------------------------------------------------------------------------------- /pymode/libs/pylama/__init__.py: -------------------------------------------------------------------------------- 1 | """ Code audit tool for python. 2 | 3 | :copyright: 2013 by Kirill Klenov. 4 | :license: BSD, see LICENSE for more details. 5 | 6 | """ 7 | 8 | __version__ = "5.0.1" 9 | __project__ = "pylama" 10 | __author__ = "Kirill Klenov " 11 | __license__ = "GNU LGPL" 12 | -------------------------------------------------------------------------------- /pymode/libs/pylama/errors.py: -------------------------------------------------------------------------------- 1 | """ Dont duplicate errors same type. """ 2 | 3 | DUPLICATES = ( 4 | 5 | # multiple statements on one line 6 | [('pep8', 'E701'), ('pylint', 'C0321')], 7 | 8 | # missing whitespace around operator 9 | [('pep8', 'E225'), ('pylint', 'C0326')], 10 | 11 | # unused variable 12 | [('pylint', 'W0612'), ('pyflakes', 'W0612')], 13 | 14 | # undefined variable 15 | [('pylint', 'E0602'), ('pyflakes', 'E0602')], 16 | 17 | # unused import 18 | [('pylint', 'W0611'), ('pyflakes', 'W0611')], 19 | 20 | # unexpected spaces 21 | [('pylint', 'C0326'), ('pep8', 'E251')], 22 | 23 | # long lines 24 | [('pylint', 'C0301'), ('pep8', 'E501')], 25 | 26 | # whitespace before '(' 27 | [('pylint', 'C0326'), ('pep8', 'E211')], 28 | 29 | # statement ends with a semicolon 30 | [('pylint', 'W0301'), ('pep8', 'E703')], 31 | 32 | # multiple statements on one line 33 | [('pylint', 'C0321'), ('pep8', 'E702')], 34 | 35 | # bad indentation 36 | [('pylint', 'W0311'), ('pep8', 'E111')], 37 | 38 | ) 39 | 40 | DUPLICATES = dict((key, values) for values in DUPLICATES for key in values) 41 | 42 | 43 | class Error(object): 44 | 45 | """ Store error information. """ 46 | 47 | def __init__(self, linter="", col=1, lnum=1, type="E", 48 | text="unknown error", filename="", **kwargs): 49 | """ Init error information with default values. """ 50 | text = ' '.join(str(text).strip().split('\n')) 51 | if linter: 52 | text = "%s [%s]" % (text, linter) 53 | number = text.split(' ', 1)[0] 54 | self._info = dict(linter=linter, col=col, lnum=lnum, type=type, 55 | text=text, filename=filename, number=number) 56 | 57 | def __getattr__(self, name): 58 | return self._info[name] 59 | 60 | def __getitem__(self, name): 61 | return self._info[name] 62 | 63 | def get(self, name, default=None): 64 | """ Implement dictionary `get` method. """ 65 | return self._info.get(name, default) 66 | 67 | def __repr__(self): 68 | return "" % (self.number, self.linter) 69 | 70 | # pylama:ignore=W0622,D 71 | -------------------------------------------------------------------------------- /pymode/libs/pylama/hook.py: -------------------------------------------------------------------------------- 1 | """ SCM hooks. Integration with git and mercurial. """ 2 | 3 | from __future__ import absolute_import 4 | 5 | import sys 6 | from os import path as op, chmod 7 | from subprocess import Popen, PIPE 8 | 9 | from .main import LOGGER 10 | from .config import parse_options, setup_logger 11 | 12 | 13 | try: 14 | from configparser import ConfigParser # noqa 15 | except ImportError: # Python 2 16 | from ConfigParser import ConfigParser 17 | 18 | 19 | def run(command): 20 | """ Run a shell command. 21 | 22 | :return str: Stdout 23 | 24 | """ 25 | p = Popen(command.split(), stdout=PIPE, stderr=PIPE) 26 | (stdout, stderr) = p.communicate() 27 | return (p.returncode, [line.strip() for line in stdout.splitlines()], 28 | [line.strip() for line in stderr.splitlines()]) 29 | 30 | 31 | def git_hook(): 32 | """ Run pylama after git commit. """ 33 | from .main import check_files 34 | 35 | _, files_modified, _ = run("git diff-index --cached --name-only HEAD") 36 | 37 | options = parse_options() 38 | setup_logger(options) 39 | check_files([f for f in map(str, files_modified)], options) 40 | 41 | 42 | def hg_hook(ui, repo, node=None, **kwargs): 43 | """ Run pylama after mercurial commit. """ 44 | from .main import check_files 45 | seen = set() 46 | paths = [] 47 | if len(repo): 48 | for rev in range(repo[node], len(repo)): 49 | for file_ in repo[rev].files(): 50 | file_ = op.join(repo.root, file_) 51 | if file_ in seen or not op.exists(file_): 52 | continue 53 | seen.add(file_) 54 | paths.append(file_) 55 | 56 | options = parse_options() 57 | setup_logger(options) 58 | check_files(paths, options) 59 | 60 | 61 | def install_git(path): 62 | """ Install hook in Git repository. """ 63 | hook = op.join(path, 'pre-commit') 64 | with open(hook, 'w') as fd: 65 | fd.write("""#!/usr/bin/env python 66 | import sys 67 | from pylama.hook import git_hook 68 | 69 | if __name__ == '__main__': 70 | sys.exit(git_hook()) 71 | """) 72 | chmod(hook, 484) 73 | 74 | 75 | def install_hg(path): 76 | """ Install hook in Mercurial repository. """ 77 | hook = op.join(path, 'hgrc') 78 | if not op.isfile(hook): 79 | open(hook, 'w+').close() 80 | 81 | c = ConfigParser() 82 | c.readfp(open(path, 'r')) 83 | if not c.has_section('hooks'): 84 | c.add_section('hooks') 85 | 86 | if not c.has_option('hooks', 'commit'): 87 | c.set('hooks', 'commit', 'python:pylama.hooks.hg_hook') 88 | 89 | if not c.has_option('hooks', 'qrefresh'): 90 | c.set('hooks', 'qrefresh', 'python:pylama.hooks.hg_hook') 91 | 92 | c.write(open(path, 'w+')) 93 | 94 | 95 | def install_hook(path): 96 | """ Auto definition of SCM and hook installation. """ 97 | git = op.join(path, '.git', 'hooks') 98 | hg = op.join(path, '.hg') 99 | if op.exists(git): 100 | install_git(git) 101 | LOGGER.warn('Git hook has been installed.') 102 | 103 | elif op.exists(hg): 104 | install_hg(git) 105 | LOGGER.warn('Mercurial hook has been installed.') 106 | 107 | else: 108 | LOGGER.error('VCS has not found. Check your path.') 109 | sys.exit(1) 110 | 111 | # lint_ignore=F0401,E1103 112 | -------------------------------------------------------------------------------- /pymode/libs/pylama/libs/__init__.py: -------------------------------------------------------------------------------- 1 | """ Support libs. """ 2 | -------------------------------------------------------------------------------- /pymode/libs/pylama/libs/importlib.py: -------------------------------------------------------------------------------- 1 | """Backport of importlib.import_module from 3.x.""" 2 | # While not critical (and in no way guaranteed!), it would be nice to keep this 3 | # code compatible with Python 2.3. 4 | import sys 5 | 6 | def _resolve_name(name, package, level): 7 | """Return the absolute name of the module to be imported.""" 8 | if not hasattr(package, 'rindex'): 9 | raise ValueError("'package' not set to a string") 10 | dot = len(package) 11 | for x in xrange(level, 1, -1): 12 | try: 13 | dot = package.rindex('.', 0, dot) 14 | except ValueError: 15 | raise ValueError("attempted relative import beyond top-level " 16 | "package") 17 | return "%s.%s" % (package[:dot], name) 18 | 19 | 20 | def import_module(name, package=None): 21 | """Import a module. 22 | 23 | The 'package' argument is required when performing a relative import. It 24 | specifies the package to use as the anchor point from which to resolve the 25 | relative import to an absolute import. 26 | 27 | """ 28 | if name.startswith('.'): 29 | if not package: 30 | raise TypeError("relative imports require the 'package' argument") 31 | level = 0 32 | for character in name: 33 | if character != '.': 34 | break 35 | level += 1 36 | name = _resolve_name(name[level:], package, level) 37 | __import__(name) 38 | return sys.modules[name] 39 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/__init__.py: -------------------------------------------------------------------------------- 1 | """ Custom module loader. """ 2 | 3 | 4 | class Linter(object): # noqa 5 | 6 | """ Abstract class for linter plugin. """ 7 | 8 | @staticmethod 9 | def allow(path): 10 | """ Check path is relevant for linter. 11 | 12 | :return bool: 13 | 14 | """ 15 | 16 | return path.endswith('.py') 17 | 18 | @staticmethod 19 | def run(path, **meta): 20 | """ Method 'run' should be defined. """ 21 | 22 | raise NotImplementedError(__doc__) 23 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/extensions.py: -------------------------------------------------------------------------------- 1 | """ Load extensions. """ 2 | 3 | from os import listdir, path as op 4 | 5 | 6 | CURDIR = op.dirname(__file__) 7 | LINTERS = dict() 8 | PREFIX = 'pylama_' 9 | 10 | try: 11 | from importlib import import_module 12 | except ImportError: 13 | from ..libs.importlib import import_module 14 | 15 | for p in listdir(CURDIR): 16 | if p.startswith(PREFIX) and op.isdir(op.join(CURDIR, p)): 17 | name = p[len(PREFIX):] 18 | try: 19 | module = import_module('.lint.%s%s' % (PREFIX, name), 'pylama') 20 | LINTERS[name] = getattr(module, 'Linter')() 21 | except ImportError: 22 | continue 23 | 24 | try: 25 | from pkg_resources import iter_entry_points 26 | 27 | for entry in iter_entry_points('pylama.linter'): 28 | LINTERS[entry.name] = entry.load()() 29 | except ImportError: 30 | pass 31 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_mccabe/__init__.py: -------------------------------------------------------------------------------- 1 | """ Check complexity. """ 2 | 3 | from .. import Linter as BaseLinter 4 | 5 | 6 | class Linter(BaseLinter): 7 | 8 | """ Mccabe code complexity. """ 9 | 10 | @staticmethod 11 | def run(path, code=None, complexity=10, **meta): 12 | """ MCCabe code checking. 13 | 14 | :return list: List of errors. 15 | 16 | """ 17 | from .mccabe import get_code_complexity 18 | 19 | return get_code_complexity(code, complexity, filename=path) or [] 20 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pep257/__init__.py: -------------------------------------------------------------------------------- 1 | """ Check PEP257. """ 2 | 3 | from .. import Linter as BaseLinter 4 | 5 | 6 | class Linter(BaseLinter): 7 | 8 | """ Mccabe code complexity. """ 9 | 10 | @staticmethod 11 | def run(path, code=None, **meta): 12 | """ PEP257 code checking. 13 | 14 | :return list: List of errors. 15 | 16 | """ 17 | from .pep257 import PEP257Checker 18 | 19 | errors = [] 20 | for er in PEP257Checker().check_source(code, path): 21 | errors.append(dict( 22 | lnum=er.line, 23 | text=er.message, 24 | type='D', 25 | )) 26 | return errors 27 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pep8/__init__.py: -------------------------------------------------------------------------------- 1 | """ Check PEP8. """ 2 | from .. import Linter as BaseLinter 3 | from .pep8 import BaseReport, StyleGuide 4 | 5 | try: 6 | from StringIO import StringIO 7 | except ImportError: 8 | from io import StringIO 9 | 10 | 11 | class Linter(BaseLinter): 12 | 13 | """ PEP8 code check. """ 14 | 15 | @staticmethod 16 | def run(path, code=None, **options): 17 | """ PEP8 code checking. 18 | 19 | :return list: List of errors. 20 | 21 | """ 22 | P8Style = StyleGuide(reporter=_PEP8Report, **options) 23 | buf = StringIO(code) 24 | return P8Style.input_file(path, lines=buf.readlines()) 25 | 26 | 27 | class _PEP8Report(BaseReport): 28 | 29 | def __init__(self, *args, **kwargs): 30 | super(_PEP8Report, self).__init__(*args, **kwargs) 31 | self.errors = [] 32 | 33 | def init_file(self, filename, lines, expected, line_offset): 34 | """ Prepare storage for errors. """ 35 | super(_PEP8Report, self).init_file( 36 | filename, lines, expected, line_offset) 37 | self.errors = [] 38 | 39 | def error(self, line_number, offset, text, check): 40 | """ Save errors. """ 41 | code = super(_PEP8Report, self).error( 42 | line_number, offset, text, check) 43 | 44 | if code: 45 | self.errors.append(dict( 46 | text=text, 47 | type=code.replace('E', 'C'), 48 | col=offset + 1, 49 | lnum=line_number, 50 | )) 51 | 52 | def get_file_results(self): 53 | """ Get errors. 54 | 55 | :return list: List of errors. 56 | 57 | """ 58 | return self.errors 59 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pyflakes/__init__.py: -------------------------------------------------------------------------------- 1 | """ Check Pyflakes. """ 2 | import sys 3 | from os import path as op 4 | 5 | from .. import Linter as BaseLinter 6 | 7 | 8 | # Use local version of pyflakes 9 | path = op.dirname(op.abspath(__file__)) 10 | sys.path.insert(0, path) 11 | 12 | from pyflakes import checker 13 | 14 | 15 | class Linter(BaseLinter): 16 | 17 | """ Pyflakes code check. """ 18 | 19 | def __init__(self): 20 | if checker.messages.UndefinedName.message != "E0602 undefined name %r": 21 | monkey_patch_messages(checker.messages) 22 | 23 | @staticmethod 24 | def run(path, code=None, builtins="", **meta): 25 | """ Pyflake code checking. 26 | 27 | :return list: List of errors. 28 | 29 | """ 30 | import _ast 31 | import os 32 | 33 | os.environ.setdefault('PYFLAKES_BUILTINS', builtins) 34 | 35 | errors = [] 36 | tree = compile(code, path, "exec", _ast.PyCF_ONLY_AST) 37 | w = checker.Checker(tree, path) 38 | w.messages = sorted(w.messages, key=lambda m: m.lineno) 39 | for w in w.messages: 40 | errors.append(dict( 41 | lnum=w.lineno, 42 | text=w.message % w.message_args, 43 | )) 44 | return errors 45 | 46 | 47 | def monkey_patch_messages(messages): 48 | """ Patch pyflakes messages. """ 49 | 50 | messages.LateFutureImport.message = "W0410 future import(s) %r after other statements" 51 | messages.ImportStarUsed.message = "W0401 'from %s import *' used; unable to detect undefined names" 52 | messages.RedefinedWhileUnused.message = "W0404 redefinition of unused %r from line %r" 53 | messages.DoctestSyntaxError.message = "W0511 syntax error in doctest" 54 | messages.UnusedImport.message = "W0611 %r imported but unused" 55 | messages.UnusedVariable.message = "W0612 local variable %r is assigned to but never used" 56 | messages.RedefinedInListComp.message = "W0621 list comprehension redefines %r from line %r" 57 | messages.Redefined.message = "W0621 redefinition of %r from line %r" 58 | messages.ImportShadowedByLoopVar.message = "W0621 import %r from line %r shadowed by loop variable" 59 | messages.ReturnWithArgsInsideGenerator.message = "E0106 'return' with argument inside generator" 60 | messages.UndefinedName.message = "E0602 undefined name %r" 61 | messages.UndefinedLocal.message = "E0602 local variable %r (defined in enclosing scope on line %r) referenced before assignment" 62 | messages.UndefinedExport.message = "E0603 undefined name %r in __all__" 63 | messages.DuplicateArgument.message = "E1122 duplicate argument %r in function definition" 64 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pyflakes/pyflakes/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __version__ = '0.8.2a0' 3 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/__init__.py: -------------------------------------------------------------------------------- 1 | """ Description. """ 2 | 3 | # Module information 4 | # ================== 5 | 6 | 7 | __version__ = "0.2.1" 8 | __project__ = "pylama_pylint" 9 | __author__ = "horneds " 10 | __license__ = "BSD" 11 | 12 | import sys 13 | if sys.version_info >= (3, 0, 0): 14 | raise ImportError("pylama_pylint doesnt support python3") 15 | 16 | from .main import Linter 17 | assert Linter 18 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/astroid/__pkginfo__.py: -------------------------------------------------------------------------------- 1 | # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 2 | # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This file is part of astroid. 5 | # 6 | # astroid is free software: you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as published by the 8 | # Free Software Foundation, either version 2.1 of the License, or (at your 9 | # option) any later version. 10 | # 11 | # astroid is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 | # for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License along 17 | # with astroid. If not, see . 18 | """astroid packaging information""" 19 | 20 | distname = 'astroid' 21 | 22 | modname = 'astroid' 23 | 24 | numversion = (1, 1, 1) 25 | version = '.'.join([str(num) for num in numversion]) 26 | 27 | install_requires = ['logilab-common >= 0.60.0'] 28 | 29 | license = 'LGPL' 30 | 31 | author = 'Logilab' 32 | author_email = 'python-projects@lists.logilab.org' 33 | mailinglist = "mailto://%s" % author_email 34 | web = 'http://bitbucket.org/logilab/astroid' 35 | 36 | description = "rebuild a new abstract syntax tree from Python's ast" 37 | 38 | from os.path import join 39 | include_dirs = ['brain', 40 | join('test', 'regrtest_data'), 41 | join('test', 'data'), join('test', 'data2')] 42 | 43 | classifiers = ["Topic :: Software Development :: Libraries :: Python Modules", 44 | "Topic :: Software Development :: Quality Assurance", 45 | "Programming Language :: Python", 46 | "Programming Language :: Python :: 2", 47 | "Programming Language :: Python :: 3", 48 | ] 49 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/astroid/brain/py2mechanize.py: -------------------------------------------------------------------------------- 1 | from astroid import MANAGER 2 | from astroid.builder import AstroidBuilder 3 | 4 | def mechanize_transform(module): 5 | fake = AstroidBuilder(MANAGER).string_build(''' 6 | 7 | class Browser(object): 8 | def open(self, url, data=None, timeout=None): 9 | return None 10 | def open_novisit(self, url, data=None, timeout=None): 11 | return None 12 | def open_local_file(self, filename): 13 | return None 14 | 15 | ''') 16 | module.locals['Browser'] = fake.locals['Browser'] 17 | 18 | import py2stdlib 19 | py2stdlib.MODULE_TRANSFORMS['mechanize'] = mechanize_transform 20 | 21 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/astroid/brain/py2qt4.py: -------------------------------------------------------------------------------- 1 | """Astroid hooks for the Python 2 qt4 module. 2 | 3 | Currently help understanding of : 4 | 5 | * PyQT4.QtCore 6 | """ 7 | 8 | from astroid import MANAGER 9 | from astroid.builder import AstroidBuilder 10 | 11 | 12 | def pyqt4_qtcore_transform(module): 13 | fake = AstroidBuilder(MANAGER).string_build(''' 14 | 15 | def SIGNAL(signal_name): pass 16 | 17 | class QObject(object): 18 | def emit(self, signal): pass 19 | ''') 20 | for klass in ('QObject',): 21 | module.locals[klass] = fake.locals[klass] 22 | 23 | 24 | import py2stdlib 25 | py2stdlib.MODULE_TRANSFORMS['PyQt4.QtCore'] = pyqt4_qtcore_transform 26 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/astroid/exceptions.py: -------------------------------------------------------------------------------- 1 | # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 2 | # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This file is part of astroid. 5 | # 6 | # astroid is free software: you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as published by the 8 | # Free Software Foundation, either version 2.1 of the License, or (at your 9 | # option) any later version. 10 | # 11 | # astroid is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 | # for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License along 17 | # with astroid. If not, see . 18 | """this module contains exceptions used in the astroid library 19 | 20 | """ 21 | 22 | __doctype__ = "restructuredtext en" 23 | 24 | class AstroidError(Exception): 25 | """base exception class for all astroid related exceptions""" 26 | 27 | class AstroidBuildingException(AstroidError): 28 | """exception class when we are unable to build an astroid representation""" 29 | 30 | class ResolveError(AstroidError): 31 | """base class of astroid resolution/inference error""" 32 | 33 | class NotFoundError(ResolveError): 34 | """raised when we are unable to resolve a name""" 35 | 36 | class InferenceError(ResolveError): 37 | """raised when we are unable to infer a node""" 38 | 39 | class UseInferenceDefault(Exception): 40 | """exception to be raised in custom inference function to indicate that it 41 | should go back to the default behaviour 42 | """ 43 | 44 | class UnresolvableName(InferenceError): 45 | """raised when we are unable to resolve a name""" 46 | 47 | class NoDefault(AstroidError): 48 | """raised by function's `default_value` method when an argument has 49 | no default value 50 | """ 51 | 52 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/astroid/nodes.py: -------------------------------------------------------------------------------- 1 | # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 2 | # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This file is part of astroid. 5 | # 6 | # astroid is free software: you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as published by the 8 | # Free Software Foundation, either version 2.1 of the License, or (at your 9 | # option) any later version. 10 | # 11 | # astroid is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 | # for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License along 17 | # with astroid. If not, see . 18 | """ 19 | on all nodes : 20 | .is_statement, returning true if the node should be considered as a 21 | statement node 22 | .root(), returning the root node of the tree (i.e. a Module) 23 | .previous_sibling(), returning previous sibling statement node 24 | .next_sibling(), returning next sibling statement node 25 | .statement(), returning the first parent node marked as statement node 26 | .frame(), returning the first node defining a new local scope (i.e. 27 | Module, Function or Class) 28 | .set_local(name, node), define an identifier on the first parent frame, 29 | with the node defining it. This is used by the astroid builder and should not 30 | be used from out there. 31 | 32 | on From and Import : 33 | .real_name(name), 34 | 35 | 36 | """ 37 | 38 | __docformat__ = "restructuredtext en" 39 | 40 | from astroid.node_classes import Arguments, AssAttr, Assert, Assign, \ 41 | AssName, AugAssign, Backquote, BinOp, BoolOp, Break, CallFunc, Compare, \ 42 | Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete, \ 43 | Dict, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, For, \ 44 | From, Getattr, Global, If, IfExp, Import, Index, Keyword, \ 45 | List, Name, Nonlocal, Pass, Print, Raise, Return, Set, Slice, Starred, Subscript, \ 46 | TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, YieldFrom, \ 47 | const_factory 48 | from astroid.scoped_nodes import Module, GenExpr, Lambda, DictComp, \ 49 | ListComp, SetComp, Function, Class 50 | 51 | ALL_NODE_CLASSES = ( 52 | Arguments, AssAttr, Assert, Assign, AssName, AugAssign, 53 | Backquote, BinOp, BoolOp, Break, 54 | CallFunc, Class, Compare, Comprehension, Const, Continue, 55 | Decorators, DelAttr, DelName, Delete, 56 | Dict, DictComp, Discard, 57 | Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, 58 | For, From, Function, 59 | Getattr, GenExpr, Global, 60 | If, IfExp, Import, Index, 61 | Keyword, 62 | Lambda, List, ListComp, 63 | Name, Nonlocal, 64 | Module, 65 | Pass, Print, 66 | Raise, Return, 67 | Set, SetComp, Slice, Starred, Subscript, 68 | TryExcept, TryFinally, Tuple, 69 | UnaryOp, 70 | While, With, 71 | Yield, YieldFrom 72 | ) 73 | 74 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/logilab/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vim-scripts/Python-mode-klen/1986bbd280cf7410b404e3253a572e6aa7ca65f6/pymode/libs/pylama/lint/pylama_pylint/logilab/__init__.py -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/logilab/common/__pkginfo__.py: -------------------------------------------------------------------------------- 1 | # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 2 | # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This file is part of logilab-common. 5 | # 6 | # logilab-common is free software: you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License as published by the Free 8 | # Software Foundation, either version 2.1 of the License, or (at your option) any 9 | # later version. 10 | # 11 | # logilab-common is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | # details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License along 17 | # with logilab-common. If not, see . 18 | """logilab.common packaging information""" 19 | __docformat__ = "restructuredtext en" 20 | import sys 21 | import os 22 | 23 | distname = 'logilab-common' 24 | modname = 'common' 25 | subpackage_of = 'logilab' 26 | subpackage_master = True 27 | 28 | numversion = (0, 61, 0) 29 | version = '.'.join([str(num) for num in numversion]) 30 | 31 | license = 'LGPL' # 2.1 or later 32 | description = "collection of low-level Python packages and modules used by Logilab projects" 33 | web = "http://www.logilab.org/project/%s" % distname 34 | mailinglist = "mailto://python-projects@lists.logilab.org" 35 | author = "Logilab" 36 | author_email = "contact@logilab.fr" 37 | 38 | 39 | from os.path import join 40 | scripts = [join('bin', 'pytest')] 41 | include_dirs = [join('test', 'data')] 42 | 43 | install_requires = [] 44 | if sys.version_info < (2, 7): 45 | install_requires.append('unittest2 >= 0.5.1') 46 | if os.name == 'nt': 47 | install_requires.append('colorama') 48 | 49 | classifiers = ["Topic :: Utilities", 50 | "Programming Language :: Python", 51 | "Programming Language :: Python :: 2", 52 | "Programming Language :: Python :: 3", 53 | ] 54 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/logilab/common/interface.py: -------------------------------------------------------------------------------- 1 | # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 2 | # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This file is part of logilab-common. 5 | # 6 | # logilab-common is free software: you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License as published by the Free 8 | # Software Foundation, either version 2.1 of the License, or (at your option) any 9 | # later version. 10 | # 11 | # logilab-common is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | # details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License along 17 | # with logilab-common. If not, see . 18 | """Bases class for interfaces to provide 'light' interface handling. 19 | 20 | TODO: 21 | _ implements a check method which check that an object implements the 22 | interface 23 | _ Attribute objects 24 | 25 | This module requires at least python 2.2 26 | """ 27 | __docformat__ = "restructuredtext en" 28 | 29 | 30 | class Interface(object): 31 | """Base class for interfaces.""" 32 | def is_implemented_by(cls, instance): 33 | return implements(instance, cls) 34 | is_implemented_by = classmethod(is_implemented_by) 35 | 36 | 37 | def implements(obj, interface): 38 | """Return true if the give object (maybe an instance or class) implements 39 | the interface. 40 | """ 41 | kimplements = getattr(obj, '__implements__', ()) 42 | if not isinstance(kimplements, (list, tuple)): 43 | kimplements = (kimplements,) 44 | for implementedinterface in kimplements: 45 | if issubclass(implementedinterface, interface): 46 | return True 47 | return False 48 | 49 | 50 | def extend(klass, interface, _recurs=False): 51 | """Add interface to klass'__implements__ if not already implemented in. 52 | 53 | If klass is subclassed, ensure subclasses __implements__ it as well. 54 | 55 | NOTE: klass should be e new class. 56 | """ 57 | if not implements(klass, interface): 58 | try: 59 | kimplements = klass.__implements__ 60 | kimplementsklass = type(kimplements) 61 | kimplements = list(kimplements) 62 | except AttributeError: 63 | kimplementsklass = tuple 64 | kimplements = [] 65 | kimplements.append(interface) 66 | klass.__implements__ = kimplementsklass(kimplements) 67 | for subklass in klass.__subclasses__(): 68 | extend(subklass, interface, _recurs=True) 69 | elif _recurs: 70 | for subklass in klass.__subclasses__(): 71 | extend(subklass, interface, _recurs=True) 72 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/main.py: -------------------------------------------------------------------------------- 1 | """ Pylint support. """ 2 | from os import path as op, environ 3 | import sys 4 | 5 | from pylama.lint import Linter as BaseLinter 6 | 7 | CURDIR = op.abspath(op.dirname(__file__)) 8 | sys.path.insert(0, CURDIR) 9 | 10 | from astroid import MANAGER 11 | from pylint.lint import Run 12 | from pylint.reporters import BaseReporter 13 | 14 | PYLINT_RC = op.abspath(op.join(CURDIR, 'pylint.rc')) 15 | 16 | 17 | class Linter(BaseLinter): 18 | 19 | """ Check code with pylint. """ 20 | 21 | @staticmethod 22 | def run(path, **meta): # noqa 23 | """ Pylint code checking. 24 | 25 | :return list: List of errors. 26 | 27 | """ 28 | 29 | MANAGER.astroid_cache.clear() 30 | 31 | class Reporter(BaseReporter): 32 | 33 | def __init__(self): 34 | self.errors = [] 35 | super(Reporter, self).__init__() 36 | 37 | def _display(self, layout): 38 | pass 39 | 40 | def add_message(self, msg_id, location, msg): 41 | _, _, line, col = location[1:] 42 | self.errors.append(dict( 43 | lnum=line, 44 | col=col, 45 | text="%s %s" % (msg_id, msg), 46 | type=msg_id[0] 47 | )) 48 | 49 | pylintrc = op.join(environ.get('HOME', ''), '.pylintrc') 50 | defattrs = '-r n' 51 | if not op.exists(pylintrc): 52 | defattrs += ' --rcfile={0}'.format(PYLINT_RC) 53 | attrs = meta.get('pylint', defattrs.split()) 54 | 55 | runner = Run( 56 | [path] + attrs, reporter=Reporter(), exit=False) 57 | return runner.linter.reporter.errors 58 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint.rc: -------------------------------------------------------------------------------- 1 | [MESSAGES CONTROL] 2 | # Disable the message(s) with the given id(s). 3 | # http://pylint-messages.wikidot.com/all-codes 4 | # 5 | # C0103: Invalid name "%s" (should match %s) 6 | # E1101: %s %r has no %r member 7 | # R0901: Too many ancestors (%s/%s) 8 | # R0902: Too many instance attributes (%s/%s) 9 | # R0903: Too few public methods (%s/%s) 10 | # R0904: Too many public methods (%s/%s) 11 | # R0913: Too many arguments (%s/%s) 12 | # R0915: Too many statements (%s/%s) 13 | # W0141: Used builtin function %r 14 | # W0142: Used * or ** magic 15 | # W0221: Arguments number differs from %s method 16 | # W0232: Class has no __init__ method 17 | # W0613: Unused argument %r 18 | # W0631: Using possibly undefined loop variable %r 19 | # 20 | disable = C0103,E1101,R0901,R0902,R0903,R0904,R0913,R0915,W0141,W0142,W0221,W0232,W0613,W0631 21 | 22 | [TYPECHECK] 23 | generated-members = REQUEST,acl_users,aq_parent,objects,DoesNotExist,_meta,status_code,content,context 24 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003-2012 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | import sys 17 | 18 | def run_pylint(): 19 | """run pylint""" 20 | from pylint.lint import Run 21 | Run(sys.argv[1:]) 22 | 23 | def run_pylint_gui(): 24 | """run pylint-gui""" 25 | try: 26 | from pylint.gui import Run 27 | Run(sys.argv[1:]) 28 | except ImportError: 29 | sys.exit('tkinter is not available') 30 | 31 | def run_epylint(): 32 | """run pylint""" 33 | from pylint.epylint import Run 34 | Run() 35 | 36 | def run_pyreverse(): 37 | """run pyreverse""" 38 | from pylint.pyreverse.main import Run 39 | Run(sys.argv[1:]) 40 | 41 | def run_symilar(): 42 | """run symilar""" 43 | from pylint.checkers.similar import Run 44 | Run(sys.argv[1:]) 45 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/__pkginfo__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=W0622,C0103 2 | # Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE). 3 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 4 | # 5 | # This program is free software; you can redistribute it and/or modify it under 6 | # the terms of the GNU General Public License as published by the Free Software 7 | # Foundation; either version 2 of the License, or (at your option) any later 8 | # version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | """pylint packaging information""" 18 | import sys 19 | 20 | modname = distname = 'pylint' 21 | 22 | numversion = (1, 2, 1) 23 | version = '.'.join([str(num) for num in numversion]) 24 | 25 | if sys.version_info < (2, 6): 26 | install_requires = ['logilab-common >= 0.53.0', 'astroid >= 1.1', 27 | 'StringFormat'] 28 | else: 29 | install_requires = ['logilab-common >= 0.53.0', 'astroid >= 1.1'] 30 | 31 | license = 'GPL' 32 | description = "python code static checker" 33 | web = 'http://www.pylint.org' 34 | mailinglist = "mailto://code-quality@python.org" 35 | author = 'Logilab' 36 | author_email = 'python-projects@lists.logilab.org' 37 | 38 | classifiers = ['Development Status :: 4 - Beta', 39 | 'Environment :: Console', 40 | 'Intended Audience :: Developers', 41 | 'License :: OSI Approved :: GNU General Public License (GPL)', 42 | 'Operating System :: OS Independent', 43 | 'Programming Language :: Python', 44 | 'Programming Language :: Python :: 2', 45 | 'Programming Language :: Python :: 3', 46 | 'Topic :: Software Development :: Debuggers', 47 | 'Topic :: Software Development :: Quality Assurance', 48 | 'Topic :: Software Development :: Testing' 49 | ] 50 | 51 | 52 | long_desc = """\ 53 | Pylint is a Python source code analyzer which looks for programming 54 | errors, helps enforcing a coding standard and sniffs for some code 55 | smells (as defined in Martin Fowler's Refactoring book) 56 | . 57 | Pylint can be seen as another PyChecker since nearly all tests you 58 | can do with PyChecker can also be done with Pylint. However, Pylint 59 | offers some more features, like checking length of lines of code, 60 | checking if variable names are well-formed according to your coding 61 | standard, or checking if declared interfaces are truly implemented, 62 | and much more. 63 | . 64 | Additionally, it is possible to write plugins to add your own checks. 65 | . 66 | Pylint is shipped with "pylint-gui", "pyreverse" (UML diagram generator) 67 | and "symilar" (an independent similarities checker).""" 68 | 69 | from os.path import join 70 | scripts = [join('bin', filename) 71 | for filename in ('pylint', 'pylint-gui', "symilar", "epylint", 72 | "pyreverse")] 73 | 74 | include_dirs = ['test'] 75 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/misc.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=W0511 2 | # This program is free software; you can redistribute it and/or modify it under 3 | # the terms of the GNU General Public License as published by the Free Software 4 | # Foundation; either version 2 of the License, or (at your option) any later 5 | # version. 6 | # 7 | # This program is distributed in the hope that it will be useful, but WITHOUT 8 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License along with 12 | # this program; if not, write to the Free Software Foundation, Inc., 13 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 | """ Copyright (c) 2000-2010 LOGILAB S.A. (Paris, FRANCE). 15 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 16 | 17 | Check source code is ascii only or has an encoding declaration (PEP 263) 18 | """ 19 | 20 | import re 21 | 22 | from pylint.interfaces import IRawChecker 23 | from pylint.checkers import BaseChecker 24 | 25 | 26 | MSGS = { 27 | 'W0511': ('%s', 28 | 'fixme', 29 | 'Used when a warning note as FIXME or XXX is detected.'), 30 | 'W0512': ('Cannot decode using encoding "%s", unexpected byte at position %d', 31 | 'invalid-encoded-data', 32 | 'Used when a source line cannot be decoded using the specified ' 33 | 'source file encoding.', 34 | {'maxversion': (3, 0)}), 35 | } 36 | 37 | 38 | class EncodingChecker(BaseChecker): 39 | """checks for: 40 | * warning notes in the code like FIXME, XXX 41 | * encoding issues. 42 | """ 43 | __implements__ = IRawChecker 44 | 45 | # configuration section name 46 | name = 'miscellaneous' 47 | msgs = MSGS 48 | 49 | options = (('notes', 50 | {'type' : 'csv', 'metavar' : '', 51 | 'default' : ('FIXME', 'XXX', 'TODO'), 52 | 'help' : 'List of note tags to take in consideration, \ 53 | separated by a comma.' 54 | }), 55 | ) 56 | 57 | def _check_note(self, notes, lineno, line): 58 | match = notes.search(line) 59 | if match: 60 | self.add_message('fixme', args=line[match.start():-1], line=lineno) 61 | 62 | def _check_encoding(self, lineno, line, file_encoding): 63 | try: 64 | return unicode(line, file_encoding) 65 | except UnicodeDecodeError, ex: 66 | self.add_message('invalid-encoded-data', line=lineno, 67 | args=(file_encoding, ex.args[2])) 68 | 69 | def process_module(self, module): 70 | """inspect the source file to find encoding problem or fixmes like 71 | notes 72 | """ 73 | stream = module.file_stream 74 | stream.seek(0) # XXX may be removed with astroid > 0.23 75 | if self.config.notes: 76 | notes = re.compile('|'.join(self.config.notes)) 77 | else: 78 | notes = None 79 | if module.file_encoding: 80 | encoding = module.file_encoding 81 | else: 82 | encoding = 'ascii' 83 | for lineno, line in enumerate(stream): 84 | line = self._check_encoding(lineno+1, line, encoding) 85 | if line is not None and notes: 86 | self._check_note(notes, lineno+1, line) 87 | 88 | def register(linter): 89 | """required method to auto register this checker""" 90 | linter.register_checker(EncodingChecker(linter)) 91 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/checkers/stdlib.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Google Inc. 2 | # 3 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | """Checkers for various standard library functions.""" 17 | 18 | import re 19 | import sys 20 | 21 | import astroid 22 | 23 | from pylint.interfaces import IAstroidChecker 24 | from pylint.checkers import BaseChecker 25 | from pylint.checkers import utils 26 | 27 | _VALID_OPEN_MODE_REGEX = r'^(r?U|[rwa]\+?b?)$' 28 | 29 | if sys.version_info >= (3, 0): 30 | OPEN_MODULE = '_io' 31 | else: 32 | OPEN_MODULE = '__builtin__' 33 | 34 | class OpenModeChecker(BaseChecker): 35 | __implements__ = (IAstroidChecker,) 36 | name = 'open_mode' 37 | 38 | msgs = { 39 | 'W1501': ('"%s" is not a valid mode for open.', 40 | 'bad-open-mode', 41 | 'Python supports: r, w, a modes with b, +, and U options. ' 42 | 'See http://docs.python.org/2/library/functions.html#open'), 43 | } 44 | 45 | @utils.check_messages('bad-open-mode') 46 | def visit_callfunc(self, node): 47 | """Visit a CallFunc node.""" 48 | if hasattr(node, 'func'): 49 | infer = utils.safe_infer(node.func) 50 | if infer and infer.root().name == OPEN_MODULE: 51 | if getattr(node.func, 'name', None) in ('open', 'file'): 52 | self._check_open_mode(node) 53 | 54 | def _check_open_mode(self, node): 55 | """Check that the mode argument of an open or file call is valid.""" 56 | try: 57 | mode_arg = utils.get_argument_from_call(node, position=1, keyword='mode') 58 | if mode_arg: 59 | mode_arg = utils.safe_infer(mode_arg) 60 | if (isinstance(mode_arg, astroid.Const) 61 | and not re.match(_VALID_OPEN_MODE_REGEX, mode_arg.value)): 62 | self.add_message('bad-open-mode', node=node, args=(mode_arg.value)) 63 | except (utils.NoSuchArgumentError, TypeError): 64 | pass 65 | 66 | def register(linter): 67 | """required method to auto register this checker """ 68 | linter.register_checker(OpenModeChecker(linter)) 69 | 70 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/interfaces.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 13 | """Interfaces for PyLint objects""" 14 | 15 | from logilab.common.interface import Interface 16 | 17 | 18 | class IChecker(Interface): 19 | """This is an base interface, not designed to be used elsewhere than for 20 | sub interfaces definition. 21 | """ 22 | 23 | def open(self): 24 | """called before visiting project (i.e set of modules)""" 25 | 26 | def close(self): 27 | """called after visiting project (i.e set of modules)""" 28 | 29 | 30 | class IRawChecker(IChecker): 31 | """interface for checker which need to parse the raw file 32 | """ 33 | 34 | def process_module(self, astroid): 35 | """ process a module 36 | 37 | the module's content is accessible via astroid.file_stream 38 | """ 39 | 40 | 41 | class ITokenChecker(IChecker): 42 | """Interface for checkers that need access to the token list.""" 43 | def process_tokens(self, tokens): 44 | """Process a module. 45 | 46 | tokens is a list of all source code tokens in the file. 47 | """ 48 | 49 | 50 | class IAstroidChecker(IChecker): 51 | """ interface for checker which prefers receive events according to 52 | statement type 53 | """ 54 | 55 | 56 | class IReporter(Interface): 57 | """ reporter collect messages and display results encapsulated in a layout 58 | """ 59 | def add_message(self, msg_id, location, msg): 60 | """add a message of a given type 61 | 62 | msg_id is a message identifier 63 | location is a 3-uple (module, object, line) 64 | msg is the actual message 65 | """ 66 | 67 | def display_results(self, layout): 68 | """display results encapsulated in the layout tree 69 | """ 70 | 71 | 72 | __all__ = ('IRawChecker', 'IAstroidChecker', 'ITokenChecker', 'IReporter') 73 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/reporters/guireporter.py: -------------------------------------------------------------------------------- 1 | """ reporter used by gui.py """ 2 | 3 | import sys 4 | 5 | from pylint.interfaces import IReporter 6 | from pylint.reporters import BaseReporter, Message 7 | from logilab.common.ureports import TextWriter 8 | 9 | 10 | class GUIReporter(BaseReporter): 11 | """saves messages""" 12 | 13 | __implements__ = IReporter 14 | extension = '' 15 | 16 | def __init__(self, gui, output=sys.stdout): 17 | """init""" 18 | BaseReporter.__init__(self, output) 19 | self.gui = gui 20 | 21 | def add_message(self, msg_id, location, msg): 22 | """manage message of different type and in the context of path""" 23 | message = Message(self, msg_id, location, msg) 24 | self.gui.msg_queue.put(message) 25 | 26 | def _display(self, layout): 27 | """launch layouts display""" 28 | TextWriter().format(layout, self.out) 29 | -------------------------------------------------------------------------------- /pymode/libs/pylama/lint/pylama_pylint/pylint/reporters/html.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). 2 | # This program is free software; you can redistribute it and/or modify it under 3 | # the terms of the GNU General Public License as published by the Free Software 4 | # Foundation; either version 2 of the License, or (at your option) any later 5 | # version. 6 | # 7 | # This program is distributed in the hope that it will be useful, but WITHOUT 8 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License along with 12 | # this program; if not, write to the Free Software Foundation, Inc., 13 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 | """HTML reporter""" 15 | 16 | import sys 17 | from cgi import escape 18 | 19 | from logilab.common.ureports import HTMLWriter, Section, Table 20 | 21 | from pylint.interfaces import IReporter 22 | from pylint.reporters import BaseReporter, Message 23 | 24 | 25 | class HTMLReporter(BaseReporter): 26 | """report messages and layouts in HTML""" 27 | 28 | __implements__ = IReporter 29 | name = 'html' 30 | extension = 'html' 31 | 32 | def __init__(self, output=sys.stdout): 33 | BaseReporter.__init__(self, output) 34 | self.msgs = [] 35 | 36 | def add_message(self, msg_id, location, msg): 37 | """manage message of different type and in the context of path""" 38 | msg = Message(self, msg_id, location, msg) 39 | self.msgs += (msg.category, msg.module, msg.obj, 40 | str(msg.line), str(msg.column), escape(msg.msg)) 41 | 42 | def set_output(self, output=None): 43 | """set output stream 44 | 45 | messages buffered for old output is processed first""" 46 | if self.out and self.msgs: 47 | self._display(Section()) 48 | BaseReporter.set_output(self, output) 49 | 50 | def _display(self, layout): 51 | """launch layouts display 52 | 53 | overridden from BaseReporter to add insert the messages section 54 | (in add_message, message is not displayed, just collected so it 55 | can be displayed in an html table) 56 | """ 57 | if self.msgs: 58 | # add stored messages to the layout 59 | msgs = ['type', 'module', 'object', 'line', 'col_offset', 'message'] 60 | msgs += self.msgs 61 | sect = Section('Messages') 62 | layout.append(sect) 63 | sect.append(Table(cols=6, children=msgs, rheaders=1)) 64 | self.msgs = [] 65 | HTMLWriter().format(layout, self.out) 66 | 67 | 68 | def register(linter): 69 | """Register the reporter classes with the linter.""" 70 | linter.register_reporter(HTMLReporter) 71 | -------------------------------------------------------------------------------- /pymode/libs/pylama/main.py: -------------------------------------------------------------------------------- 1 | """ Pylama's shell support. """ 2 | 3 | from __future__ import absolute_import, with_statement 4 | 5 | import sys 6 | from os import walk, path as op 7 | 8 | from .config import parse_options, CURDIR, setup_logger 9 | from .core import LOGGER 10 | 11 | 12 | def shell(args=None, error=True): 13 | """ Endpoint for console. 14 | 15 | Parse a command arguments, configuration files and run a checkers. 16 | 17 | :return list: list of errors 18 | :raise SystemExit: 19 | 20 | """ 21 | if args is None: 22 | args = sys.argv[1:] 23 | 24 | options = parse_options(args) 25 | setup_logger(options) 26 | LOGGER.info(options) 27 | 28 | # Install VSC hook 29 | if options.hook: 30 | from .hook import install_hook 31 | return install_hook(options.path) 32 | 33 | paths = [options.path] 34 | 35 | if op.isdir(options.path): 36 | paths = [] 37 | for root, _, files in walk(options.path): 38 | paths += [op.relpath(op.join(root, f), CURDIR) for f in files] 39 | 40 | return check_files(paths, options, error=error) 41 | 42 | 43 | def check_files(paths, options, rootpath=None, error=True): 44 | """ Check files. 45 | 46 | :return list: list of errors 47 | :raise SystemExit: 48 | 49 | """ 50 | from .tasks import async_check_files 51 | 52 | if rootpath is None: 53 | rootpath = CURDIR 54 | 55 | pattern = "%(rel)s:%(lnum)s:%(col)s: %(text)s" 56 | if options.format == 'pylint': 57 | pattern = "%(rel)s:%(lnum)s: [%(type)s] %(text)s" 58 | 59 | work_paths = [] 60 | for path in paths: 61 | 62 | if not options.force and not any(l.allow(path) for _, l in options.linters): # noqa 63 | continue 64 | 65 | if not op.exists(path): 66 | continue 67 | 68 | if options.skip and any(p.match(path) for p in options.skip): 69 | LOGGER.info('Skip path: %s', path) 70 | continue 71 | work_paths.append(path) 72 | 73 | errors = async_check_files(work_paths, options, rootpath=rootpath) 74 | 75 | for er in errors: 76 | LOGGER.warning(pattern, er._info) 77 | 78 | if error: 79 | sys.exit(int(bool(errors))) 80 | 81 | return errors 82 | 83 | 84 | if __name__ == '__main__': 85 | shell() 86 | -------------------------------------------------------------------------------- /pymode/libs/pylama/pytest.py: -------------------------------------------------------------------------------- 1 | """ py.test plugin for checking files with pylama. """ 2 | from __future__ import absolute_import 3 | 4 | from os import path as op 5 | 6 | import py 7 | import pytest 8 | 9 | 10 | HISTKEY = "pylama/mtimes" 11 | 12 | 13 | def pytest_addoption(parser): 14 | group = parser.getgroup("general") 15 | group.addoption( 16 | '--pylama', action='store_true', 17 | help="perform some pylama code checks on .py files") 18 | 19 | 20 | def pytest_sessionstart(session): 21 | config = session.config 22 | if config.option.pylama and getattr(config, 'cache', None): 23 | config._pylamamtimes = config.cache.get(HISTKEY, {}) 24 | 25 | 26 | def pytest_sessionfinish(session): 27 | config = session.config 28 | if hasattr(config, "_pylamamtimes"): 29 | config.cache.set(HISTKEY, config._pylamamtimes) 30 | 31 | 32 | def pytest_collect_file(path, parent): 33 | config = parent.config 34 | if config.option.pylama and path.ext == '.py': 35 | return PylamaItem(path, parent) 36 | 37 | 38 | class PylamaError(Exception): 39 | """ indicates an error during pylama checks. """ 40 | 41 | 42 | class PylamaItem(pytest.Item, pytest.File): 43 | 44 | def __init__(self, path, parent): 45 | super(PylamaItem, self).__init__(path, parent) 46 | self.add_marker("pep8") 47 | self.cache = None 48 | self._pylamamtimes = None 49 | 50 | def setup(self): 51 | if not getattr(self.config, 'cache', None): 52 | return False 53 | 54 | self.cache = True 55 | self._pylamamtimes = self.fspath.mtime() 56 | pylamamtimes = self.config._pylamamtimes 57 | old = pylamamtimes.get(str(self.fspath), 0) 58 | if old == self._pylamamtimes: 59 | pytest.skip("file(s) previously passed Pylama checks") 60 | 61 | def runtest(self): 62 | call = py.io.StdCapture.call 63 | errors, out, err = call(check_file, self.fspath) 64 | # errors = check_file(self.fspath) 65 | if errors: 66 | raise PylamaError(out, err) 67 | # update mtime only if test passed 68 | # otherwise failures would not be re-run next time 69 | if self.cache: 70 | self.config._pylamamtimes[str(self.fspath)] = self._pylamamtimes 71 | 72 | def repr_failure(self, excinfo): 73 | if excinfo.errisinstance(PylamaError): 74 | return excinfo.value.args[0] 75 | return super(PylamaItem, self).repr_failure(excinfo) 76 | 77 | 78 | def check_file(path): 79 | from pylama.main import parse_options, check_files 80 | from pylama.config import CURDIR 81 | 82 | options = parse_options() 83 | path = op.relpath(str(path), CURDIR) 84 | return check_files([path], options, error=False) 85 | 86 | # pylama:ignore=D,E1002,W0212 87 | -------------------------------------------------------------------------------- /pymode/libs/pylama/tasks.py: -------------------------------------------------------------------------------- 1 | """ Support for asyncronious code checking. """ 2 | 3 | import logging 4 | import threading 5 | from os import path as op 6 | try: 7 | import Queue 8 | except ImportError: 9 | import queue as Queue 10 | 11 | from .core import run 12 | 13 | 14 | try: 15 | import multiprocessing 16 | 17 | CPU_COUNT = multiprocessing.cpu_count() 18 | 19 | except (ImportError, NotImplementedError): 20 | CPU_COUNT = 1 21 | 22 | LOGGER = logging.getLogger('pylama') 23 | 24 | 25 | class Worker(threading.Thread): 26 | 27 | """ Get tasks from queue and run. """ 28 | 29 | def __init__(self, path_queue, result_queue): 30 | """ Init worker. """ 31 | threading.Thread.__init__(self) 32 | self.path_queue = path_queue 33 | self.result_queue = result_queue 34 | 35 | def run(self): 36 | """ Run tasks from queue. """ 37 | while True: 38 | path, params = self.path_queue.get() 39 | errors = check_path(path, **params) 40 | self.result_queue.put(errors) 41 | self.path_queue.task_done() 42 | 43 | 44 | def async_check_files(paths, options, rootpath=None): 45 | """ Check paths. 46 | 47 | :return list: list of errors 48 | 49 | """ 50 | errors = [] 51 | 52 | # Disable async if pylint enabled 53 | async = options.async and 'pylint' not in options.linters 54 | 55 | if not async: 56 | for path in paths: 57 | errors += check_path(path, options=options, rootpath=rootpath) 58 | return errors 59 | 60 | LOGGER.info('Async code checking is enabled.') 61 | path_queue = Queue.Queue() 62 | result_queue = Queue.Queue() 63 | 64 | for _ in range(CPU_COUNT): 65 | worker = Worker(path_queue, result_queue) 66 | worker.setDaemon(True) 67 | worker.start() 68 | 69 | for path in paths: 70 | path_queue.put((path, dict(options=options, rootpath=rootpath))) 71 | 72 | path_queue.join() 73 | 74 | while True: 75 | try: 76 | errors += result_queue.get(False) 77 | except Queue.Empty: 78 | break 79 | 80 | return errors 81 | 82 | 83 | def check_path(path, options=None, rootpath=None, code=None): 84 | """ Check path. 85 | 86 | :return list: list of errors 87 | 88 | """ 89 | LOGGER.info("Parse file: %s", path) 90 | 91 | rootpath = rootpath or '.' 92 | errors = [] 93 | for error in run(path, code, options): 94 | try: 95 | error._info['rel'] = op.relpath(error.filename, rootpath) 96 | errors.append(error) 97 | except KeyError: 98 | continue 99 | 100 | return errors 101 | 102 | # pylama:ignore=W0212 103 | -------------------------------------------------------------------------------- /pymode/libs2/rope/__init__.py: -------------------------------------------------------------------------------- 1 | """rope, a python refactoring library""" 2 | 3 | INFO = __doc__ 4 | VERSION = '0.9.4' 5 | COPYRIGHT = """\ 6 | Copyright (C) 2006-2012 Ali Gholami Rudi 7 | Copyright (C) 2009-2012 Anton Gritsay 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of GNU General Public License as published by the 11 | Free Software Foundation; either version 2 of the license, or (at your 12 | opinion) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details.""" 18 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/__init__.py: -------------------------------------------------------------------------------- 1 | """Base rope package 2 | 3 | This package contains rope core modules that are used by other modules 4 | and packages. 5 | 6 | """ 7 | 8 | __all__ = ['project', 'libutils', 'exceptions'] 9 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/arguments.py: -------------------------------------------------------------------------------- 1 | import rope.base.evaluate 2 | from rope.base import ast 3 | 4 | 5 | class Arguments(object): 6 | """A class for evaluating parameters passed to a function 7 | 8 | You can use the `create_arguments` factory. It handles implicit 9 | first arguments. 10 | 11 | """ 12 | 13 | def __init__(self, args, scope): 14 | self.args = args 15 | self.scope = scope 16 | self.instance = None 17 | 18 | def get_arguments(self, parameters): 19 | result = [] 20 | for pyname in self.get_pynames(parameters): 21 | if pyname is None: 22 | result.append(None) 23 | else: 24 | result.append(pyname.get_object()) 25 | return result 26 | 27 | def get_pynames(self, parameters): 28 | result = [None] * max(len(parameters), len(self.args)) 29 | for index, arg in enumerate(self.args): 30 | if isinstance(arg, ast.keyword) and arg.arg in parameters: 31 | result[parameters.index(arg.arg)] = self._evaluate(arg.value) 32 | else: 33 | result[index] = self._evaluate(arg) 34 | return result 35 | 36 | def get_instance_pyname(self): 37 | if self.args: 38 | return self._evaluate(self.args[0]) 39 | 40 | def _evaluate(self, ast_node): 41 | return rope.base.evaluate.eval_node(self.scope, ast_node) 42 | 43 | 44 | def create_arguments(primary, pyfunction, call_node, scope): 45 | """A factory for creating `Arguments`""" 46 | args = list(call_node.args) 47 | args.extend(call_node.keywords) 48 | called = call_node.func 49 | # XXX: Handle constructors 50 | if _is_method_call(primary, pyfunction) and \ 51 | isinstance(called, ast.Attribute): 52 | args.insert(0, called.value) 53 | return Arguments(args, scope) 54 | 55 | 56 | class ObjectArguments(object): 57 | 58 | def __init__(self, pynames): 59 | self.pynames = pynames 60 | 61 | def get_arguments(self, parameters): 62 | result = [] 63 | for pyname in self.pynames: 64 | if pyname is None: 65 | result.append(None) 66 | else: 67 | result.append(pyname.get_object()) 68 | return result 69 | 70 | def get_pynames(self, parameters): 71 | return self.pynames 72 | 73 | def get_instance_pyname(self): 74 | return self.pynames[0] 75 | class MixedArguments(object): 76 | 77 | def __init__(self, pyname, arguments, scope): 78 | """`argumens` is an instance of `Arguments`""" 79 | self.pyname = pyname 80 | self.args = arguments 81 | 82 | def get_pynames(self, parameters): 83 | return [self.pyname] + self.args.get_pynames(parameters[1:]) 84 | 85 | def get_arguments(self, parameters): 86 | result = [] 87 | for pyname in self.get_pynames(parameters): 88 | if pyname is None: 89 | result.append(None) 90 | else: 91 | result.append(pyname.get_object()) 92 | return result 93 | 94 | def get_instance_pyname(self): 95 | return self.pyname 96 | 97 | 98 | def _is_method_call(primary, pyfunction): 99 | if primary is None: 100 | return False 101 | pyobject = primary.get_object() 102 | if isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) and \ 103 | isinstance(pyfunction, rope.base.pyobjects.PyFunction) and \ 104 | isinstance(pyfunction.parent, rope.base.pyobjects.PyClass): 105 | return True 106 | if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass) and \ 107 | isinstance(pyfunction, rope.base.builtins.BuiltinFunction): 108 | return True 109 | return False 110 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/ast.py: -------------------------------------------------------------------------------- 1 | import _ast 2 | from _ast import * 3 | 4 | from rope.base import fscommands 5 | 6 | 7 | def parse(source, filename=''): 8 | # NOTE: the raw string should be given to `compile` function 9 | if isinstance(source, unicode): 10 | source = fscommands.unicode_to_file_data(source) 11 | if '\r' in source: 12 | source = source.replace('\r\n', '\n').replace('\r', '\n') 13 | if not source.endswith('\n'): 14 | source += '\n' 15 | try: 16 | return compile(source, filename, 'exec', _ast.PyCF_ONLY_AST) 17 | except (TypeError, ValueError), e: 18 | error = SyntaxError() 19 | error.lineno = 1 20 | error.filename = filename 21 | error.msg = str(e) 22 | raise error 23 | 24 | 25 | def walk(node, walker): 26 | """Walk the syntax tree""" 27 | method_name = '_' + node.__class__.__name__ 28 | method = getattr(walker, method_name, None) 29 | if method is not None: 30 | if isinstance(node, _ast.ImportFrom) and node.module is None: 31 | # In python < 2.7 ``node.module == ''`` for relative imports 32 | # but for python 2.7 it is None. Generalizing it to ''. 33 | node.module = '' 34 | return method(node) 35 | for child in get_child_nodes(node): 36 | walk(child, walker) 37 | 38 | 39 | def get_child_nodes(node): 40 | if isinstance(node, _ast.Module): 41 | return node.body 42 | result = [] 43 | if node._fields is not None: 44 | for name in node._fields: 45 | child = getattr(node, name) 46 | if isinstance(child, list): 47 | for entry in child: 48 | if isinstance(entry, _ast.AST): 49 | result.append(entry) 50 | if isinstance(child, _ast.AST): 51 | result.append(child) 52 | return result 53 | 54 | 55 | def call_for_nodes(node, callback, recursive=False): 56 | """If callback returns `True` the child nodes are skipped""" 57 | result = callback(node) 58 | if recursive and not result: 59 | for child in get_child_nodes(node): 60 | call_for_nodes(child, callback, recursive) 61 | 62 | 63 | def get_children(node): 64 | result = [] 65 | if node._fields is not None: 66 | for name in node._fields: 67 | if name in ['lineno', 'col_offset']: 68 | continue 69 | child = getattr(node, name) 70 | result.append(child) 71 | return result 72 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/astutils.py: -------------------------------------------------------------------------------- 1 | from rope.base import ast 2 | 3 | 4 | def get_name_levels(node): 5 | """Return a list of ``(name, level)`` tuples for assigned names 6 | 7 | The `level` is `None` for simple assignments and is a list of 8 | numbers for tuple assignments for example in:: 9 | 10 | a, (b, c) = x 11 | 12 | The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for 13 | `c` is ``[1, 1]``. 14 | 15 | """ 16 | visitor = _NodeNameCollector() 17 | ast.walk(node, visitor) 18 | return visitor.names 19 | 20 | 21 | class _NodeNameCollector(object): 22 | 23 | def __init__(self, levels=None): 24 | self.names = [] 25 | self.levels = levels 26 | self.index = 0 27 | 28 | def _add_node(self, node): 29 | new_levels = [] 30 | if self.levels is not None: 31 | new_levels = list(self.levels) 32 | new_levels.append(self.index) 33 | self.index += 1 34 | self._added(node, new_levels) 35 | 36 | def _added(self, node, levels): 37 | if hasattr(node, 'id'): 38 | self.names.append((node.id, levels)) 39 | 40 | def _Name(self, node): 41 | self._add_node(node) 42 | 43 | def _Tuple(self, node): 44 | new_levels = [] 45 | if self.levels is not None: 46 | new_levels = list(self.levels) 47 | new_levels.append(self.index) 48 | self.index += 1 49 | visitor = _NodeNameCollector(new_levels) 50 | for child in ast.get_child_nodes(node): 51 | ast.walk(child, visitor) 52 | self.names.extend(visitor.names) 53 | 54 | def _Subscript(self, node): 55 | self._add_node(node) 56 | 57 | def _Attribute(self, node): 58 | self._add_node(node) 59 | 60 | def _Slice(self, node): 61 | self._add_node(node) 62 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/default_config.py: -------------------------------------------------------------------------------- 1 | # The default ``config.py`` 2 | 3 | 4 | def set_prefs(prefs): 5 | """This function is called before opening the project""" 6 | 7 | # Specify which files and folders to ignore in the project. 8 | # Changes to ignored resources are not added to the history and 9 | # VCSs. Also they are not returned in `Project.get_files()`. 10 | # Note that ``?`` and ``*`` match all characters but slashes. 11 | # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' 12 | # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' 13 | # '.svn': matches 'pkg/.svn' and all of its children 14 | # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' 15 | # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' 16 | prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', 17 | '.hg', '.svn', '_svn', '.git'] 18 | 19 | # Specifies which files should be considered python files. It is 20 | # useful when you have scripts inside your project. Only files 21 | # ending with ``.py`` are considered to be python files by 22 | # default. 23 | #prefs['python_files'] = ['*.py'] 24 | 25 | # Custom source folders: By default rope searches the project 26 | # for finding source folders (folders that should be searched 27 | # for finding modules). You can add paths to that list. Note 28 | # that rope guesses project source folders correctly most of the 29 | # time; use this if you have any problems. 30 | # The folders should be relative to project root and use '/' for 31 | # separating folders regardless of the platform rope is running on. 32 | # 'src/my_source_folder' for instance. 33 | #prefs.add('source_folders', 'src') 34 | 35 | # You can extend python path for looking up modules 36 | #prefs.add('python_path', '~/python/') 37 | 38 | # Should rope save object information or not. 39 | prefs['save_objectdb'] = True 40 | prefs['compress_objectdb'] = False 41 | 42 | # If `True`, rope analyzes each module when it is being saved. 43 | prefs['automatic_soa'] = True 44 | # The depth of calls to follow in static object analysis 45 | prefs['soa_followed_calls'] = 0 46 | 47 | # If `False` when running modules or unit tests "dynamic object 48 | # analysis" is turned off. This makes them much faster. 49 | prefs['perform_doa'] = True 50 | 51 | # Rope can check the validity of its object DB when running. 52 | prefs['validate_objectdb'] = True 53 | 54 | # How many undos to hold? 55 | prefs['max_history_items'] = 32 56 | 57 | # Shows whether to save history across sessions. 58 | prefs['save_history'] = True 59 | prefs['compress_history'] = False 60 | 61 | # Set the number spaces used for indenting. According to 62 | # :PEP:`8`, it is best to use 4 spaces. Since most of rope's 63 | # unit-tests use 4 spaces it is more reliable, too. 64 | prefs['indent_size'] = 4 65 | 66 | # Builtin and c-extension modules that are allowed to be imported 67 | # and inspected by rope. 68 | prefs['extension_modules'] = [] 69 | 70 | # Add all standard c-extensions to extension_modules list. 71 | prefs['import_dynload_stdmods'] = True 72 | 73 | # If `True` modules with syntax errors are considered to be empty. 74 | # The default value is `False`; When `False` syntax errors raise 75 | # `rope.base.exceptions.ModuleSyntaxError` exception. 76 | prefs['ignore_syntax_errors'] = False 77 | 78 | # If `True`, rope ignores unresolvable imports. Otherwise, they 79 | # appear in the importing namespace. 80 | prefs['ignore_bad_imports'] = False 81 | 82 | 83 | def project_opened(project): 84 | """This function is called after opening the project""" 85 | # Do whatever you like here! 86 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/exceptions.py: -------------------------------------------------------------------------------- 1 | class RopeError(Exception): 2 | """Base exception for rope""" 3 | 4 | 5 | class ResourceNotFoundError(RopeError): 6 | """Resource not found exception""" 7 | 8 | 9 | class RefactoringError(RopeError): 10 | """Errors for performing a refactoring""" 11 | 12 | 13 | class InterruptedTaskError(RopeError): 14 | """The task has been interrupted""" 15 | 16 | 17 | class HistoryError(RopeError): 18 | """Errors for history undo/redo operations""" 19 | 20 | 21 | class ModuleNotFoundError(RopeError): 22 | """Module not found exception""" 23 | 24 | 25 | class AttributeNotFoundError(RopeError): 26 | """Attribute not found exception""" 27 | 28 | 29 | class NameNotFoundError(RopeError): 30 | """Name not found exception""" 31 | 32 | 33 | class BadIdentifierError(RopeError): 34 | """The name cannot be resolved""" 35 | 36 | 37 | class ModuleSyntaxError(RopeError): 38 | """Module has syntax errors 39 | 40 | The `filename` and `lineno` fields indicate where the error has 41 | occurred. 42 | 43 | """ 44 | 45 | def __init__(self, filename, lineno, message): 46 | self.filename = filename 47 | self.lineno = lineno 48 | self.message_ = message 49 | super(ModuleSyntaxError, self).__init__( 50 | 'Syntax error in file <%s> line <%s>: %s' % 51 | (filename, lineno, message)) 52 | 53 | 54 | class ModuleDecodeError(RopeError): 55 | """Cannot decode module""" 56 | 57 | def __init__(self, filename, message): 58 | self.filename = filename 59 | self.message_ = message 60 | super(ModuleDecodeError, self).__init__( 61 | 'Cannot decode file <%s>: %s' % (filename, message)) 62 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/libutils.py: -------------------------------------------------------------------------------- 1 | """A few useful functions for using rope as a library""" 2 | import os.path 3 | 4 | import rope.base.project 5 | import rope.base.pycore 6 | from rope.base import taskhandle 7 | 8 | 9 | def path_to_resource(project, path, type=None): 10 | """Get the resource at path 11 | 12 | You only need to specify `type` if `path` does not exist. It can 13 | be either 'file' or 'folder'. If the type is `None` it is assumed 14 | that the resource already exists. 15 | 16 | Note that this function uses `Project.get_resource()`, 17 | `Project.get_file()`, and `Project.get_folder()` methods. 18 | 19 | """ 20 | project_path = relative(project.address, path) 21 | if project_path is None: 22 | project_path = rope.base.project._realpath(path) 23 | project = rope.base.project.get_no_project() 24 | if type is None: 25 | return project.get_resource(project_path) 26 | if type == 'file': 27 | return project.get_file(project_path) 28 | if type == 'folder': 29 | return project.get_folder(project_path) 30 | return None 31 | 32 | def relative(root, path): 33 | root = rope.base.project._realpath(root).replace(os.path.sep, '/') 34 | path = rope.base.project._realpath(path).replace(os.path.sep, '/') 35 | if path == root: 36 | return '' 37 | if path.startswith(root + '/'): 38 | return path[len(root) + 1:] 39 | 40 | def report_change(project, path, old_content): 41 | """Report that the contents of file at `path` was changed 42 | 43 | The new contents of file is retrieved by reading the file. 44 | 45 | """ 46 | resource = path_to_resource(project, path) 47 | if resource is None: 48 | return 49 | for observer in list(project.observers): 50 | observer.resource_changed(resource) 51 | if project.pycore.automatic_soa: 52 | rope.base.pycore.perform_soa_on_changed_scopes(project, resource, 53 | old_content) 54 | 55 | def analyze_modules(project, task_handle=taskhandle.NullTaskHandle()): 56 | """Perform static object analysis on all python files in the project 57 | 58 | Note that this might be really time consuming. 59 | """ 60 | resources = project.pycore.get_python_files() 61 | job_set = task_handle.create_jobset('Analyzing Modules', len(resources)) 62 | for resource in resources: 63 | job_set.started_job(resource.path) 64 | project.pycore.analyze_module(resource) 65 | job_set.finished_job() 66 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/oi/__init__.py: -------------------------------------------------------------------------------- 1 | """Rope object analysis and inference package 2 | 3 | Rope makes some simplifying assumptions about a python program. It 4 | assumes that a program only performs assignments and function calls. 5 | Tracking assignments is simple and `PyName` objects handle that. The 6 | main problem is function calls. Rope uses these two approaches for 7 | obtaining call information: 8 | 9 | * Static object analysis: `rope.base.pycore.PyCore.analyze_module()` 10 | 11 | It can analyze modules to obtain information about functions. This 12 | is done by analyzing function calls in a module or scope. Currently 13 | SOA analyzes the scopes that are changed while saving or when the 14 | user asks to analyze a module. That is mainly because static 15 | analysis is time-consuming. 16 | 17 | * Dynamic object analysis: `rope.base.pycore.PyCore.run_module()` 18 | 19 | When you run a module or your testsuite, when DOA is enabled, it 20 | collects information about parameters passed to and objects returned 21 | from functions. The main problem with this approach is that it is 22 | quite slow; Not when looking up the information but when collecting 23 | them. 24 | 25 | An instance of `rope.base.oi.objectinfo.ObjectInfoManager` can be used 26 | for accessing these information. It saves the data in a 27 | `rope.base.oi.objectdb.ObjectDB` internally. 28 | 29 | Now if our objectdb does not know anything about a function and we 30 | need the value returned by it, static object inference, SOI, comes 31 | into play. It analyzes function body and tries to infer the object 32 | that is returned from it (we usually need the returned value for the 33 | given parameter objects). 34 | 35 | Rope might collect and store information for other `PyName`\s, too. 36 | For instance rope stores the object builtin containers hold. 37 | 38 | """ 39 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/oi/memorydb.py: -------------------------------------------------------------------------------- 1 | from rope.base.oi import objectdb 2 | 3 | 4 | class MemoryDB(objectdb.FileDict): 5 | 6 | def __init__(self, project, persist=None): 7 | self.project = project 8 | self._persist = persist 9 | self.files = self 10 | self._load_files() 11 | self.project.data_files.add_write_hook(self.write) 12 | 13 | def _load_files(self): 14 | self._files = {} 15 | if self.persist: 16 | result = self.project.data_files.read_data( 17 | 'objectdb', compress=self.compress, import_=True) 18 | if result is not None: 19 | self._files = result 20 | 21 | def keys(self): 22 | return self._files.keys() 23 | 24 | def __contains__(self, key): 25 | return key in self._files 26 | 27 | def __getitem__(self, key): 28 | return FileInfo(self._files[key]) 29 | 30 | def create(self, path): 31 | self._files[path] = {} 32 | 33 | def rename(self, file, newfile): 34 | if file not in self._files: 35 | return 36 | self._files[newfile] = self._files[file] 37 | del self[file] 38 | 39 | def __delitem__(self, file): 40 | del self._files[file] 41 | 42 | def write(self): 43 | if self.persist: 44 | self.project.data_files.write_data('objectdb', self._files, 45 | self.compress) 46 | 47 | @property 48 | def compress(self): 49 | return self.project.prefs.get('compress_objectdb', False) 50 | 51 | @property 52 | def persist(self): 53 | if self._persist is not None: 54 | return self._persist 55 | else: 56 | return self.project.prefs.get('save_objectdb', False) 57 | 58 | 59 | class FileInfo(objectdb.FileInfo): 60 | 61 | def __init__(self, scopes): 62 | self.scopes = scopes 63 | 64 | def create_scope(self, key): 65 | self.scopes[key] = ScopeInfo() 66 | 67 | def keys(self): 68 | return self.scopes.keys() 69 | 70 | def __contains__(self, key): 71 | return key in self.scopes 72 | 73 | def __getitem__(self, key): 74 | return self.scopes[key] 75 | 76 | def __delitem__(self, key): 77 | del self.scopes[key] 78 | 79 | 80 | class ScopeInfo(objectdb.ScopeInfo): 81 | 82 | def __init__(self): 83 | self.call_info = {} 84 | self.per_name = {} 85 | 86 | def get_per_name(self, name): 87 | return self.per_name.get(name, None) 88 | 89 | def save_per_name(self, name, value): 90 | self.per_name[name] = value 91 | 92 | def get_returned(self, parameters): 93 | return self.call_info.get(parameters, None) 94 | 95 | def get_call_infos(self): 96 | for args, returned in self.call_info.items(): 97 | yield objectdb.CallInfo(args, returned) 98 | 99 | def add_call(self, parameters, returned): 100 | self.call_info[parameters] = returned 101 | 102 | def __getstate__(self): 103 | return (self.call_info, self.per_name) 104 | 105 | def __setstate__(self, data): 106 | self.call_info, self.per_name = data 107 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/prefs.py: -------------------------------------------------------------------------------- 1 | class Prefs(object): 2 | 3 | def __init__(self): 4 | self.prefs = {} 5 | self.callbacks = {} 6 | 7 | def set(self, key, value): 8 | """Set the value of `key` preference to `value`.""" 9 | if key in self.callbacks: 10 | self.callbacks[key](value) 11 | else: 12 | self.prefs[key] = value 13 | 14 | def add(self, key, value): 15 | """Add an entry to a list preference 16 | 17 | Add `value` to the list of entries for the `key` preference. 18 | 19 | """ 20 | if not key in self.prefs: 21 | self.prefs[key] = [] 22 | self.prefs[key].append(value) 23 | 24 | def get(self, key, default=None): 25 | """Get the value of the key preference""" 26 | return self.prefs.get(key, default) 27 | 28 | def add_callback(self, key, callback): 29 | """Add `key` preference with `callback` function 30 | 31 | Whenever `key` is set the callback is called with the 32 | given `value` as parameter. 33 | 34 | """ 35 | self.callbacks[key] = callback 36 | 37 | def __setitem__(self, key, value): 38 | self.set(key, value) 39 | 40 | def __getitem__(self, key): 41 | return self.get(key) 42 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/pynamesdef.py: -------------------------------------------------------------------------------- 1 | import rope.base.oi.soi 2 | from rope.base import pynames 3 | from rope.base.pynames import * 4 | 5 | 6 | class AssignedName(pynames.AssignedName): 7 | 8 | def __init__(self, lineno=None, module=None, pyobject=None): 9 | self.lineno = lineno 10 | self.module = module 11 | self.assignments = [] 12 | self.pyobject = _Inferred(self._get_inferred, 13 | pynames._get_concluded_data(module)) 14 | self.pyobject.set(pyobject) 15 | 16 | @utils.prevent_recursion(lambda: None) 17 | def _get_inferred(self): 18 | if self.module is not None: 19 | return rope.base.oi.soi.infer_assigned_object(self) 20 | 21 | def get_object(self): 22 | return self.pyobject.get() 23 | 24 | def get_definition_location(self): 25 | """Returns a (module, lineno) tuple""" 26 | if self.lineno is None and self.assignments: 27 | self.lineno = self.assignments[0].get_lineno() 28 | return (self.module, self.lineno) 29 | 30 | def invalidate(self): 31 | """Forget the `PyObject` this `PyName` holds""" 32 | self.pyobject.set(None) 33 | 34 | 35 | class ParameterName(pynames.ParameterName): 36 | 37 | def __init__(self, pyfunction, index): 38 | self.pyfunction = pyfunction 39 | self.index = index 40 | 41 | def get_object(self): 42 | result = self.pyfunction.get_parameter(self.index) 43 | if result is None: 44 | result = rope.base.pyobjects.get_unknown() 45 | return result 46 | 47 | def get_objects(self): 48 | """Returns the list of objects passed as this parameter""" 49 | return rope.base.oi.soi.get_passed_objects( 50 | self.pyfunction, self.index) 51 | 52 | def get_definition_location(self): 53 | return (self.pyfunction.get_module(), self.pyfunction.get_ast().lineno) 54 | 55 | _Inferred = pynames._Inferred 56 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/simplify.py: -------------------------------------------------------------------------------- 1 | """A module to ease code analysis 2 | 3 | This module is here to help source code analysis. 4 | """ 5 | import re 6 | 7 | from rope.base import codeanalyze, utils 8 | 9 | 10 | @utils.cached(7) 11 | def real_code(source): 12 | """Simplify `source` for analysis 13 | 14 | It replaces: 15 | 16 | * comments with spaces 17 | * strs with a new str filled with spaces 18 | * implicit and explicit continuations with spaces 19 | * tabs and semicolons with spaces 20 | 21 | The resulting code is a lot easier to analyze if we are interested 22 | only in offsets. 23 | """ 24 | collector = codeanalyze.ChangeCollector(source) 25 | for start, end in ignored_regions(source): 26 | if source[start] == '#': 27 | replacement = ' ' * (end - start) 28 | else: 29 | replacement = '"%s"' % (' ' * (end - start - 2)) 30 | collector.add_change(start, end, replacement) 31 | source = collector.get_changed() or source 32 | collector = codeanalyze.ChangeCollector(source) 33 | parens = 0 34 | for match in _parens.finditer(source): 35 | i = match.start() 36 | c = match.group() 37 | if c in '({[': 38 | parens += 1 39 | if c in ')}]': 40 | parens -= 1 41 | if c == '\n' and parens > 0: 42 | collector.add_change(i, i + 1, ' ') 43 | source = collector.get_changed() or source 44 | return source.replace('\\\n', ' ').replace('\t', ' ').replace(';', '\n') 45 | 46 | 47 | @utils.cached(7) 48 | def ignored_regions(source): 49 | """Return ignored regions like strings and comments in `source` """ 50 | return [(match.start(), match.end()) for match in _str.finditer(source)] 51 | 52 | 53 | _str = re.compile('%s|%s' % (codeanalyze.get_comment_pattern(), 54 | codeanalyze.get_string_pattern())) 55 | _parens = re.compile(r'[\({\[\]}\)\n]') 56 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/stdmods.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from rope.base import utils 5 | 6 | 7 | def _stdlib_path(): 8 | import distutils.sysconfig 9 | return distutils.sysconfig.get_python_lib(standard_lib=True) 10 | 11 | @utils.cached(1) 12 | def standard_modules(): 13 | return python_modules() | dynload_modules() 14 | 15 | @utils.cached(1) 16 | def python_modules(): 17 | result = set() 18 | lib_path = _stdlib_path() 19 | if os.path.exists(lib_path): 20 | for name in os.listdir(lib_path): 21 | path = os.path.join(lib_path, name) 22 | if os.path.isdir(path): 23 | if '-' not in name: 24 | result.add(name) 25 | else: 26 | if name.endswith('.py'): 27 | result.add(name[:-3]) 28 | return result 29 | 30 | @utils.cached(1) 31 | def dynload_modules(): 32 | result = set(sys.builtin_module_names) 33 | dynload_path = os.path.join(_stdlib_path(), 'lib-dynload') 34 | if os.path.exists(dynload_path): 35 | for name in os.listdir(dynload_path): 36 | path = os.path.join(dynload_path, name) 37 | if os.path.isfile(path): 38 | if name.endswith('.so') or name.endswith('.dll'): 39 | result.add(os.path.splitext(name)[0]) 40 | return result 41 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/taskhandle.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | from rope.base import exceptions 4 | 5 | 6 | class TaskHandle(object): 7 | 8 | def __init__(self, name='Task', interrupts=True): 9 | """Construct a TaskHandle 10 | 11 | If `interrupts` is `False` the task won't be interrupted by 12 | calling `TaskHandle.stop()`. 13 | 14 | """ 15 | self.name = name 16 | self.interrupts = interrupts 17 | self.stopped = False 18 | self.job_sets = [] 19 | self.observers = [] 20 | 21 | def stop(self): 22 | """Interrupts the refactoring""" 23 | if self.interrupts: 24 | self.stopped = True 25 | self._inform_observers() 26 | 27 | def current_jobset(self): 28 | """Return the current `JobSet`""" 29 | if self.job_sets: 30 | return self.job_sets[-1] 31 | 32 | def add_observer(self, observer): 33 | """Register an observer for this task handle 34 | 35 | The observer is notified whenever the task is stopped or 36 | a job gets finished. 37 | 38 | """ 39 | self.observers.append(observer) 40 | 41 | def is_stopped(self): 42 | return self.stopped 43 | 44 | def get_jobsets(self): 45 | return self.job_sets 46 | 47 | def create_jobset(self, name='JobSet', count=None): 48 | result = JobSet(self, name=name, count=count) 49 | self.job_sets.append(result) 50 | self._inform_observers() 51 | return result 52 | 53 | def _inform_observers(self): 54 | for observer in list(self.observers): 55 | observer() 56 | 57 | 58 | class JobSet(object): 59 | 60 | def __init__(self, handle, name, count): 61 | self.handle = handle 62 | self.name = name 63 | self.count = count 64 | self.done = 0 65 | self.job_name = None 66 | 67 | def started_job(self, name): 68 | self.check_status() 69 | self.job_name = name 70 | self.handle._inform_observers() 71 | 72 | def finished_job(self): 73 | self.check_status() 74 | self.done += 1 75 | self.handle._inform_observers() 76 | self.job_name = None 77 | 78 | def check_status(self): 79 | if self.handle.is_stopped(): 80 | raise exceptions.InterruptedTaskError() 81 | 82 | def get_active_job_name(self): 83 | return self.job_name 84 | 85 | def get_percent_done(self): 86 | if self.count is not None and self.count > 0: 87 | percent = self.done * 100 // self.count 88 | return min(percent, 100) 89 | 90 | def get_name(self): 91 | return self.name 92 | 93 | 94 | class NullTaskHandle(object): 95 | 96 | def __init__(self): 97 | pass 98 | 99 | def is_stopped(self): 100 | return False 101 | 102 | def stop(self): 103 | pass 104 | 105 | def create_jobset(self, *args, **kwds): 106 | return NullJobSet() 107 | 108 | def get_jobsets(self): 109 | return [] 110 | 111 | def add_observer(self, observer): 112 | pass 113 | 114 | 115 | class NullJobSet(object): 116 | 117 | def started_job(self, name): 118 | pass 119 | 120 | def finished_job(self): 121 | pass 122 | 123 | def check_status(self): 124 | pass 125 | 126 | def get_active_job_name(self): 127 | pass 128 | 129 | def get_percent_done(self): 130 | pass 131 | 132 | def get_name(self): 133 | pass 134 | -------------------------------------------------------------------------------- /pymode/libs2/rope/base/utils.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | def saveit(func): 5 | """A decorator that caches the return value of a function""" 6 | 7 | name = '_' + func.__name__ 8 | def _wrapper(self, *args, **kwds): 9 | if not hasattr(self, name): 10 | setattr(self, name, func(self, *args, **kwds)) 11 | return getattr(self, name) 12 | return _wrapper 13 | 14 | cacheit = saveit 15 | 16 | def prevent_recursion(default): 17 | """A decorator that returns the return value of `default` in recursions""" 18 | def decorator(func): 19 | name = '_calling_%s_' % func.__name__ 20 | def newfunc(self, *args, **kwds): 21 | if getattr(self, name, False): 22 | return default() 23 | setattr(self, name, True) 24 | try: 25 | return func(self, *args, **kwds) 26 | finally: 27 | setattr(self, name, False) 28 | return newfunc 29 | return decorator 30 | 31 | 32 | def ignore_exception(exception_class): 33 | """A decorator that ignores `exception_class` exceptions""" 34 | def _decorator(func): 35 | def newfunc(*args, **kwds): 36 | try: 37 | return func(*args, **kwds) 38 | except exception_class: 39 | pass 40 | return newfunc 41 | return _decorator 42 | 43 | 44 | def deprecated(message=None): 45 | """A decorator for deprecated functions""" 46 | def _decorator(func, message=message): 47 | if message is None: 48 | message = '%s is deprecated' % func.__name__ 49 | def newfunc(*args, **kwds): 50 | warnings.warn(message, DeprecationWarning, stacklevel=2) 51 | return func(*args, **kwds) 52 | return newfunc 53 | return _decorator 54 | 55 | 56 | def cached(count): 57 | """A caching decorator based on parameter objects""" 58 | def decorator(func): 59 | return _Cached(func, count) 60 | return decorator 61 | 62 | class _Cached(object): 63 | 64 | def __init__(self, func, count): 65 | self.func = func 66 | self.cache = [] 67 | self.count = count 68 | 69 | def __call__(self, *args, **kwds): 70 | key = (args, kwds) 71 | for cached_key, cached_result in self.cache: 72 | if cached_key == key: 73 | return cached_result 74 | result = self.func(*args, **kwds) 75 | self.cache.append((key, result)) 76 | if len(self.cache) > self.count: 77 | del self.cache[0] 78 | return result 79 | -------------------------------------------------------------------------------- /pymode/libs2/rope/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | """rope IDE tools package 2 | 3 | This package contains modules that can be used in IDEs 4 | but do not depend on the UI. So these modules will be used 5 | by `rope.ui` modules. 6 | 7 | """ 8 | -------------------------------------------------------------------------------- /pymode/libs2/rope/contrib/changestack.py: -------------------------------------------------------------------------------- 1 | """For performing many refactorings as a single command 2 | 3 | `changestack` module can be used to perform many refactorings on top 4 | of each other as one bigger command. It can be used like:: 5 | 6 | stack = ChangeStack(project, 'my big command') 7 | 8 | #.. 9 | stack.push(refactoring1.get_changes()) 10 | #.. 11 | stack.push(refactoring2.get_changes()) 12 | #.. 13 | stack.push(refactoringX.get_changes()) 14 | 15 | stack.pop_all() 16 | changes = stack.merged() 17 | 18 | Now `changes` can be previewed or performed as before. 19 | """ 20 | 21 | from rope.base import change 22 | 23 | 24 | class ChangeStack(object): 25 | 26 | def __init__(self, project, description='merged changes'): 27 | self.project = project 28 | self.description = description 29 | self.stack = [] 30 | 31 | def push(self, changes): 32 | self.stack.append(changes) 33 | self.project.do(changes) 34 | 35 | def pop_all(self): 36 | for i in range(len(self.stack)): 37 | self.project.history.undo(drop=True) 38 | 39 | def merged(self): 40 | result = change.ChangeSet(self.description) 41 | for changes in self.stack: 42 | for c in self._basic_changes(changes): 43 | result.add_change(c) 44 | return result 45 | 46 | def _basic_changes(self, changes): 47 | if isinstance(changes, change.ChangeSet): 48 | for child in changes.changes: 49 | for atom in self._basic_changes(child): 50 | yield atom 51 | else: 52 | yield changes 53 | -------------------------------------------------------------------------------- /pymode/libs2/rope/contrib/finderrors.py: -------------------------------------------------------------------------------- 1 | """Finding bad name and attribute accesses 2 | 3 | `find_errors` function can be used to find possible bad name and 4 | attribute accesses. As an example:: 5 | 6 | errors = find_errors(project, project.get_resource('mod.py')) 7 | for error in errors: 8 | print '%s: %s' % (error.lineno, error.error) 9 | 10 | prints possible errors for ``mod.py`` file. 11 | 12 | TODO: 13 | 14 | * use task handles 15 | * reporting names at most once 16 | * attributes of extension modules that don't appear in 17 | extension_modules project config can be ignored 18 | * not calling `PyScope.get_inner_scope_for_line()` if it is a 19 | bottleneck; needs profiling 20 | * not reporting occurrences where rope cannot infer the object 21 | * rope saves multiple objects for some of the names in its objectdb 22 | use all of them not to give false positives 23 | * ... ;-) 24 | 25 | """ 26 | from rope.base import ast, evaluate, pyobjects 27 | 28 | 29 | def find_errors(project, resource): 30 | """Find possible bad name and attribute accesses 31 | 32 | It returns a list of `Error`\s. 33 | """ 34 | pymodule = project.pycore.resource_to_pyobject(resource) 35 | finder = _BadAccessFinder(pymodule) 36 | ast.walk(pymodule.get_ast(), finder) 37 | return finder.errors 38 | 39 | 40 | class _BadAccessFinder(object): 41 | 42 | def __init__(self, pymodule): 43 | self.pymodule = pymodule 44 | self.scope = pymodule.get_scope() 45 | self.errors = [] 46 | 47 | def _Name(self, node): 48 | if isinstance(node.ctx, (ast.Store, ast.Param)): 49 | return 50 | scope = self.scope.get_inner_scope_for_line(node.lineno) 51 | pyname = scope.lookup(node.id) 52 | if pyname is None: 53 | self._add_error(node, 'Unresolved variable') 54 | elif self._is_defined_after(scope, pyname, node.lineno): 55 | self._add_error(node, 'Defined later') 56 | 57 | def _Attribute(self, node): 58 | if not isinstance(node.ctx, ast.Store): 59 | scope = self.scope.get_inner_scope_for_line(node.lineno) 60 | pyname = evaluate.eval_node(scope, node.value) 61 | if pyname is not None and \ 62 | pyname.get_object() != pyobjects.get_unknown(): 63 | if node.attr not in pyname.get_object(): 64 | self._add_error(node, 'Unresolved attribute') 65 | ast.walk(node.value, self) 66 | 67 | def _add_error(self, node, msg): 68 | if isinstance(node, ast.Attribute): 69 | name = node.attr 70 | else: 71 | name = node.id 72 | if name != 'None': 73 | error = Error(node.lineno, msg + ' ' + name) 74 | self.errors.append(error) 75 | 76 | def _is_defined_after(self, scope, pyname, lineno): 77 | location = pyname.get_definition_location() 78 | if location is not None and location[1] is not None: 79 | if location[0] == self.pymodule and \ 80 | lineno <= location[1] <= scope.get_end(): 81 | return True 82 | 83 | 84 | class Error(object): 85 | 86 | def __init__(self, lineno, error): 87 | self.lineno = lineno 88 | self.error = error 89 | 90 | def __str__(self): 91 | return '%s: %s' % (self.lineno, self.error) 92 | -------------------------------------------------------------------------------- /pymode/libs2/rope/contrib/fixmodnames.py: -------------------------------------------------------------------------------- 1 | """Fix the name of modules 2 | 3 | This module is useful when you want to rename many of the modules in 4 | your project. That can happen specially when you want to change their 5 | naming style. 6 | 7 | For instance:: 8 | 9 | fixer = FixModuleNames(project) 10 | changes = fixer.get_changes(fixer=str.lower) 11 | project.do(changes) 12 | 13 | Here it renames all modules and packages to use lower-cased chars. 14 | You can tell it to use any other style by using the ``fixer`` 15 | argument. 16 | 17 | """ 18 | from rope.base import change, taskhandle 19 | from rope.contrib import changestack 20 | from rope.refactor import rename 21 | 22 | 23 | class FixModuleNames(object): 24 | 25 | def __init__(self, project): 26 | self.project = project 27 | 28 | def get_changes(self, fixer=str.lower, 29 | task_handle=taskhandle.NullTaskHandle()): 30 | """Fix module names 31 | 32 | `fixer` is a function that takes and returns a `str`. Given 33 | the name of a module, it should return the fixed name. 34 | 35 | """ 36 | stack = changestack.ChangeStack(self.project, 'Fixing module names') 37 | jobset = task_handle.create_jobset('Fixing module names', 38 | self._count_fixes(fixer) + 1) 39 | try: 40 | while True: 41 | for resource in self._tobe_fixed(fixer): 42 | jobset.started_job(resource.path) 43 | renamer = rename.Rename(self.project, resource) 44 | changes = renamer.get_changes(fixer(self._name(resource))) 45 | stack.push(changes) 46 | jobset.finished_job() 47 | break 48 | else: 49 | break 50 | finally: 51 | jobset.started_job('Reverting to original state') 52 | stack.pop_all() 53 | jobset.finished_job() 54 | return stack.merged() 55 | 56 | def _count_fixes(self, fixer): 57 | return len(list(self._tobe_fixed(fixer))) 58 | 59 | def _tobe_fixed(self, fixer): 60 | for resource in self.project.pycore.get_python_files(): 61 | modname = self._name(resource) 62 | if modname != fixer(modname): 63 | yield resource 64 | 65 | def _name(self, resource): 66 | modname = resource.name.rsplit('.', 1)[0] 67 | if modname == '__init__': 68 | modname = resource.parent.name 69 | return modname 70 | -------------------------------------------------------------------------------- /pymode/libs2/rope/refactor/__init__.py: -------------------------------------------------------------------------------- 1 | """rope refactor package 2 | 3 | This package contains modules that perform python refactorings. 4 | Refactoring classes perform refactorings in 4 steps: 5 | 6 | 1. Collect some data for performing the refactoring and use them 7 | to construct a refactoring class. Like:: 8 | 9 | renamer = Rename(project, resource, offset) 10 | 11 | 2. Some refactorings give you useful information about the 12 | refactoring after their construction. Like:: 13 | 14 | print(renamer.get_old_name()) 15 | 16 | 3. Give the refactoring class more information about how to 17 | perform the refactoring and get the changes this refactoring is 18 | going to make. This is done by calling `get_changes` method of the 19 | refactoring class. Like:: 20 | 21 | changes = renamer.get_changes(new_name) 22 | 23 | 4. You can commit the changes. Like:: 24 | 25 | project.do(changes) 26 | 27 | These steps are like the steps IDEs usually do for performing a 28 | refactoring. These are the things an IDE does in each step: 29 | 30 | 1. Construct a refactoring object by giving it information like 31 | resource, offset and ... . Some of the refactoring problems (like 32 | performing rename refactoring on language keywords) can be reported 33 | here. 34 | 2. Print some information about the refactoring and ask the user 35 | about the information that are necessary for completing the 36 | refactoring (like new name). 37 | 3. Call the `get_changes` by passing it information asked from 38 | the user (if necessary) and get and preview the changes returned by 39 | it. 40 | 4. perform the refactoring. 41 | 42 | From ``0.5m5`` release the `get_changes()` method of some time- 43 | consuming refactorings take an optional `rope.base.taskhandle. 44 | TaskHandle` parameter. You can use this object for stopping or 45 | monitoring the progress of refactorings. 46 | 47 | """ 48 | from rope.refactor.importutils import ImportOrganizer 49 | from rope.refactor.topackage import ModuleToPackage 50 | 51 | 52 | __all__ = ['rename', 'move', 'inline', 'extract', 'restructure', 'topackage', 53 | 'importutils', 'usefunction', 'change_signature', 54 | 'encapsulate_field', 'introduce_factory', 'introduce_parameter', 55 | 'localtofield', 'method_object', 'multiproject'] 56 | -------------------------------------------------------------------------------- /pymode/libs2/rope/refactor/localtofield.py: -------------------------------------------------------------------------------- 1 | from rope.base import pynames, evaluate, exceptions, worder 2 | from rope.refactor.rename import Rename 3 | 4 | 5 | class LocalToField(object): 6 | 7 | def __init__(self, project, resource, offset): 8 | self.project = project 9 | self.pycore = project.pycore 10 | self.resource = resource 11 | self.offset = offset 12 | 13 | def get_changes(self): 14 | name = worder.get_name_at(self.resource, self.offset) 15 | this_pymodule = self.pycore.resource_to_pyobject(self.resource) 16 | pyname = evaluate.eval_location(this_pymodule, self.offset) 17 | if not self._is_a_method_local(pyname): 18 | raise exceptions.RefactoringError( 19 | 'Convert local variable to field should be performed on \n' 20 | 'a local variable of a method.') 21 | 22 | pymodule, lineno = pyname.get_definition_location() 23 | function_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) 24 | # Not checking redefinition 25 | #self._check_redefinition(name, function_scope) 26 | 27 | new_name = self._get_field_name(function_scope.pyobject, name) 28 | changes = Rename(self.project, self.resource, self.offset).\ 29 | get_changes(new_name, resources=[self.resource]) 30 | return changes 31 | 32 | def _check_redefinition(self, name, function_scope): 33 | class_scope = function_scope.parent 34 | if name in class_scope.pyobject: 35 | raise exceptions.RefactoringError( 36 | 'The field %s already exists' % name) 37 | 38 | def _get_field_name(self, pyfunction, name): 39 | self_name = pyfunction.get_param_names()[0] 40 | new_name = self_name + '.' + name 41 | return new_name 42 | 43 | def _is_a_method_local(self, pyname): 44 | pymodule, lineno = pyname.get_definition_location() 45 | holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) 46 | parent = holding_scope.parent 47 | return isinstance(pyname, pynames.AssignedName) and \ 48 | pyname in holding_scope.get_names().values() and \ 49 | holding_scope.get_kind() == 'Function' and \ 50 | parent is not None and parent.get_kind() == 'Class' 51 | -------------------------------------------------------------------------------- /pymode/libs2/rope/refactor/multiproject.py: -------------------------------------------------------------------------------- 1 | """This module can be used for performing cross-project refactorings 2 | 3 | See the "cross-project refactorings" section of ``docs/library.txt`` 4 | file. 5 | 6 | """ 7 | 8 | from rope.base import resources, project, libutils 9 | 10 | 11 | class MultiProjectRefactoring(object): 12 | 13 | def __init__(self, refactoring, projects, addpath=True): 14 | """Create a multiproject proxy for the main refactoring 15 | 16 | `projects` are other project. 17 | 18 | """ 19 | self.refactoring = refactoring 20 | self.projects = projects 21 | self.addpath = addpath 22 | 23 | def __call__(self, project, *args, **kwds): 24 | """Create the refactoring""" 25 | return _MultiRefactoring(self.refactoring, self.projects, 26 | self.addpath, project, *args, **kwds) 27 | 28 | 29 | class _MultiRefactoring(object): 30 | 31 | def __init__(self, refactoring, other_projects, addpath, 32 | project, *args, **kwds): 33 | self.refactoring = refactoring 34 | self.projects = [project] + other_projects 35 | for other_project in other_projects: 36 | for folder in self.project.pycore.get_source_folders(): 37 | other_project.get_prefs().add('python_path', folder.real_path) 38 | self.refactorings = [] 39 | for other in self.projects: 40 | args, kwds = self._resources_for_args(other, args, kwds) 41 | self.refactorings.append( 42 | self.refactoring(other, *args, **kwds)) 43 | 44 | def get_all_changes(self, *args, **kwds): 45 | """Get a project to changes dict""" 46 | result = [] 47 | for project, refactoring in zip(self.projects, self.refactorings): 48 | args, kwds = self._resources_for_args(project, args, kwds) 49 | result.append((project, refactoring.get_changes(*args, **kwds))) 50 | return result 51 | 52 | def __getattr__(self, name): 53 | return getattr(self.main_refactoring, name) 54 | 55 | def _resources_for_args(self, project, args, kwds): 56 | newargs = [self._change_project_resource(project, arg) for arg in args] 57 | newkwds = dict((name, self._change_project_resource(project, value)) 58 | for name, value in kwds.items()) 59 | return newargs, newkwds 60 | 61 | def _change_project_resource(self, project, obj): 62 | if isinstance(obj, resources.Resource) and \ 63 | obj.project != project: 64 | return libutils.path_to_resource(project, obj.real_path) 65 | return obj 66 | 67 | @property 68 | def project(self): 69 | return self.projects[0] 70 | 71 | @property 72 | def main_refactoring(self): 73 | return self.refactorings[0] 74 | 75 | 76 | def perform(project_changes): 77 | for project, changes in project_changes: 78 | project.do(changes) 79 | -------------------------------------------------------------------------------- /pymode/libs2/rope/refactor/sourceutils.py: -------------------------------------------------------------------------------- 1 | from rope.base import ast, codeanalyze 2 | 3 | 4 | def get_indents(lines, lineno): 5 | return codeanalyze.count_line_indents(lines.get_line(lineno)) 6 | 7 | 8 | def find_minimum_indents(source_code): 9 | result = 80 10 | lines = source_code.split('\n') 11 | for line in lines: 12 | if line.strip() == '': 13 | continue 14 | result = min(result, codeanalyze.count_line_indents(line)) 15 | return result 16 | 17 | 18 | def indent_lines(source_code, amount): 19 | if amount == 0: 20 | return source_code 21 | lines = source_code.splitlines(True) 22 | result = [] 23 | for l in lines: 24 | if l.strip() == '': 25 | result.append('\n') 26 | continue 27 | if amount < 0: 28 | indents = codeanalyze.count_line_indents(l) 29 | result.append(max(0, indents + amount) * ' ' + l.lstrip()) 30 | else: 31 | result.append(' ' * amount + l) 32 | return ''.join(result) 33 | 34 | 35 | def fix_indentation(code, new_indents): 36 | """Change the indentation of `code` to `new_indents`""" 37 | min_indents = find_minimum_indents(code) 38 | return indent_lines(code, new_indents - min_indents) 39 | 40 | 41 | def add_methods(pymodule, class_scope, methods_sources): 42 | source_code = pymodule.source_code 43 | lines = pymodule.lines 44 | insertion_line = class_scope.get_end() 45 | if class_scope.get_scopes(): 46 | insertion_line = class_scope.get_scopes()[-1].get_end() 47 | insertion_offset = lines.get_line_end(insertion_line) 48 | methods = '\n\n' + '\n\n'.join(methods_sources) 49 | indented_methods = fix_indentation( 50 | methods, get_indents(lines, class_scope.get_start()) + 51 | get_indent(pymodule.pycore)) 52 | result = [] 53 | result.append(source_code[:insertion_offset]) 54 | result.append(indented_methods) 55 | result.append(source_code[insertion_offset:]) 56 | return ''.join(result) 57 | 58 | 59 | def get_body(pyfunction): 60 | """Return unindented function body""" 61 | scope = pyfunction.get_scope() 62 | pymodule = pyfunction.get_module() 63 | start, end = get_body_region(pyfunction) 64 | return fix_indentation(pymodule.source_code[start:end], 0) 65 | 66 | 67 | def get_body_region(defined): 68 | """Return the start and end offsets of function body""" 69 | scope = defined.get_scope() 70 | pymodule = defined.get_module() 71 | lines = pymodule.lines 72 | node = defined.get_ast() 73 | start_line = node.lineno 74 | if defined.get_doc() is None: 75 | start_line = node.body[0].lineno 76 | elif len(node.body) > 1: 77 | start_line = node.body[1].lineno 78 | start = lines.get_line_start(start_line) 79 | scope_start = pymodule.logical_lines.logical_line_in(scope.start) 80 | if scope_start[1] >= start_line: 81 | # a one-liner! 82 | # XXX: what if colon appears in a string 83 | start = pymodule.source_code.index(':', start) + 1 84 | while pymodule.source_code[start].isspace(): 85 | start += 1 86 | end = min(lines.get_line_end(scope.end) + 1, len(pymodule.source_code)) 87 | return start, end 88 | 89 | 90 | def get_indent(pycore): 91 | project = pycore.project 92 | return project.prefs.get('indent_size', 4) 93 | -------------------------------------------------------------------------------- /pymode/libs2/rope/refactor/topackage.py: -------------------------------------------------------------------------------- 1 | import rope.refactor.importutils 2 | from rope.base.change import ChangeSet, ChangeContents, MoveResource, CreateFolder 3 | 4 | 5 | class ModuleToPackage(object): 6 | 7 | def __init__(self, project, resource): 8 | self.project = project 9 | self.pycore = project.pycore 10 | self.resource = resource 11 | 12 | def get_changes(self): 13 | changes = ChangeSet('Transform <%s> module to package' % 14 | self.resource.path) 15 | new_content = self._transform_relatives_to_absolute(self.resource) 16 | if new_content is not None: 17 | changes.add_change(ChangeContents(self.resource, new_content)) 18 | parent = self.resource.parent 19 | name = self.resource.name[:-3] 20 | changes.add_change(CreateFolder(parent, name)) 21 | parent_path = parent.path + '/' 22 | if not parent.path: 23 | parent_path = '' 24 | new_path = parent_path + '%s/__init__.py' % name 25 | if self.resource.project == self.project: 26 | changes.add_change(MoveResource(self.resource, new_path)) 27 | return changes 28 | 29 | def _transform_relatives_to_absolute(self, resource): 30 | pymodule = self.pycore.resource_to_pyobject(resource) 31 | import_tools = rope.refactor.importutils.ImportTools(self.pycore) 32 | return import_tools.relatives_to_absolutes(pymodule) 33 | -------------------------------------------------------------------------------- /pymode/libs3/rope/__init__.py: -------------------------------------------------------------------------------- 1 | """rope, a python refactoring library""" 2 | 3 | INFO = __doc__ 4 | VERSION = '0.9.4' 5 | COPYRIGHT = """\ 6 | Copyright (C) 2006-2010 Ali Gholami Rudi 7 | Copyright (C) 2009-2010 Anton Gritsay 8 | Copyright (C) 2011 Dmitriy Zhukov 9 | 10 | This program is free software; you can redistribute it and/or modify it 11 | under the terms of GNU General Public License as published by the 12 | Free Software Foundation; either version 2 of the license, or (at your 13 | opinion) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details.""" 19 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/__init__.py: -------------------------------------------------------------------------------- 1 | """Base rope package 2 | 3 | This package contains rope core modules that are used by other modules 4 | and packages. 5 | 6 | """ 7 | 8 | __all__ = ['project', 'libutils', 'exceptions'] 9 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/arguments.py: -------------------------------------------------------------------------------- 1 | import rope.base.evaluate 2 | from rope.base import ast 3 | 4 | 5 | class Arguments(object): 6 | """A class for evaluating parameters passed to a function 7 | 8 | You can use the `create_arguments` factory. It handles implicit 9 | first arguments. 10 | 11 | """ 12 | 13 | def __init__(self, args, scope): 14 | self.args = args 15 | self.scope = scope 16 | self.instance = None 17 | 18 | def get_arguments(self, parameters): 19 | result = [] 20 | for pyname in self.get_pynames(parameters): 21 | if pyname is None: 22 | result.append(None) 23 | else: 24 | result.append(pyname.get_object()) 25 | return result 26 | 27 | def get_pynames(self, parameters): 28 | result = [None] * max(len(parameters), len(self.args)) 29 | for index, arg in enumerate(self.args): 30 | if isinstance(arg, ast.keyword) and arg.arg in parameters: 31 | result[parameters.index(arg.arg)] = self._evaluate(arg.value) 32 | else: 33 | result[index] = self._evaluate(arg) 34 | return result 35 | 36 | def get_instance_pyname(self): 37 | if self.args: 38 | return self._evaluate(self.args[0]) 39 | 40 | def _evaluate(self, ast_node): 41 | return rope.base.evaluate.eval_node(self.scope, ast_node) 42 | 43 | 44 | def create_arguments(primary, pyfunction, call_node, scope): 45 | """A factory for creating `Arguments`""" 46 | args = list(call_node.args) 47 | args.extend(call_node.keywords) 48 | called = call_node.func 49 | # XXX: Handle constructors 50 | if _is_method_call(primary, pyfunction) and \ 51 | isinstance(called, ast.Attribute): 52 | args.insert(0, called.value) 53 | return Arguments(args, scope) 54 | 55 | 56 | class ObjectArguments(object): 57 | 58 | def __init__(self, pynames): 59 | self.pynames = pynames 60 | 61 | def get_arguments(self, parameters): 62 | result = [] 63 | for pyname in self.pynames: 64 | if pyname is None: 65 | result.append(None) 66 | else: 67 | result.append(pyname.get_object()) 68 | return result 69 | 70 | def get_pynames(self, parameters): 71 | return self.pynames 72 | 73 | def get_instance_pyname(self): 74 | return self.pynames[0] 75 | class MixedArguments(object): 76 | 77 | def __init__(self, pyname, arguments, scope): 78 | """`argumens` is an instance of `Arguments`""" 79 | self.pyname = pyname 80 | self.args = arguments 81 | 82 | def get_pynames(self, parameters): 83 | return [self.pyname] + self.args.get_pynames(parameters[1:]) 84 | 85 | def get_arguments(self, parameters): 86 | result = [] 87 | for pyname in self.get_pynames(parameters): 88 | if pyname is None: 89 | result.append(None) 90 | else: 91 | result.append(pyname.get_object()) 92 | return result 93 | 94 | def get_instance_pyname(self): 95 | return self.pyname 96 | 97 | 98 | def _is_method_call(primary, pyfunction): 99 | if primary is None: 100 | return False 101 | pyobject = primary.get_object() 102 | if isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) and \ 103 | isinstance(pyfunction, rope.base.pyobjects.PyFunction) and \ 104 | isinstance(pyfunction.parent, rope.base.pyobjects.PyClass): 105 | return True 106 | if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass) and \ 107 | isinstance(pyfunction, rope.base.builtins.BuiltinFunction): 108 | return True 109 | return False 110 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/ast.py: -------------------------------------------------------------------------------- 1 | import _ast 2 | from _ast import * 3 | 4 | from rope.base import fscommands 5 | 6 | 7 | def parse(source, filename=''): 8 | # NOTE: the raw string should be given to `compile` function 9 | if isinstance(source, str): 10 | source = fscommands.unicode_to_file_data(source) 11 | source = source.decode() 12 | if '\r' in source: 13 | source = source.replace('\r\n', '\n').replace('\r', '\n') 14 | if not source.endswith('\n'): 15 | source += '\n' 16 | try: 17 | return compile(source.encode(), filename, 'exec', _ast.PyCF_ONLY_AST) 18 | except (TypeError, ValueError) as e: 19 | error = SyntaxError() 20 | error.lineno = 1 21 | error.filename = filename 22 | error.msg = str(e) 23 | raise error 24 | 25 | 26 | def walk(node, walker): 27 | """Walk the syntax tree""" 28 | method_name = '_' + node.__class__.__name__ 29 | method = getattr(walker, method_name, None) 30 | if method is not None: 31 | return method(node) 32 | for child in get_child_nodes(node): 33 | walk(child, walker) 34 | 35 | 36 | def get_child_nodes(node): 37 | if isinstance(node, _ast.Module): 38 | return node.body 39 | result = [] 40 | if node._fields is not None: 41 | for name in node._fields: 42 | child = getattr(node, name) 43 | if isinstance(child, list): 44 | for entry in child: 45 | if isinstance(entry, _ast.AST): 46 | result.append(entry) 47 | if isinstance(child, _ast.AST): 48 | result.append(child) 49 | return result 50 | 51 | 52 | def call_for_nodes(node, callback, recursive=False): 53 | """If callback returns `True` the child nodes are skipped""" 54 | result = callback(node) 55 | if recursive and not result: 56 | for child in get_child_nodes(node): 57 | call_for_nodes(child, callback, recursive) 58 | 59 | 60 | def get_children(node): 61 | result = [] 62 | if node._fields is not None: 63 | for name in node._fields: 64 | if name in ['lineno', 'col_offset']: 65 | continue 66 | child = getattr(node, name) 67 | result.append(child) 68 | return result 69 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/astutils.py: -------------------------------------------------------------------------------- 1 | from rope.base import ast 2 | 3 | 4 | def get_name_levels(node): 5 | """Return a list of ``(name, level)`` tuples for assigned names 6 | 7 | The `level` is `None` for simple assignments and is a list of 8 | numbers for tuple assignments for example in:: 9 | 10 | a, (b, c) = x 11 | 12 | The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for 13 | `c` is ``[1, 1]``. 14 | 15 | """ 16 | visitor = _NodeNameCollector() 17 | ast.walk(node, visitor) 18 | return visitor.names 19 | 20 | 21 | class _NodeNameCollector(object): 22 | 23 | def __init__(self, levels=None): 24 | self.names = [] 25 | self.levels = levels 26 | self.index = 0 27 | 28 | def _add_node(self, node): 29 | new_levels = [] 30 | if self.levels is not None: 31 | new_levels = list(self.levels) 32 | new_levels.append(self.index) 33 | self.index += 1 34 | self._added(node, new_levels) 35 | 36 | def _added(self, node, levels): 37 | if hasattr(node, 'id'): 38 | self.names.append((node.id, levels)) 39 | 40 | def _Name(self, node): 41 | self._add_node(node) 42 | 43 | def _Tuple(self, node): 44 | new_levels = [] 45 | if self.levels is not None: 46 | new_levels = list(self.levels) 47 | new_levels.append(self.index) 48 | self.index += 1 49 | visitor = _NodeNameCollector(new_levels) 50 | for child in ast.get_child_nodes(node): 51 | ast.walk(child, visitor) 52 | self.names.extend(visitor.names) 53 | 54 | def _Subscript(self, node): 55 | self._add_node(node) 56 | 57 | def _Attribute(self, node): 58 | self._add_node(node) 59 | 60 | def _Slice(self, node): 61 | self._add_node(node) 62 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/default_config.py: -------------------------------------------------------------------------------- 1 | # The default ``config.py`` 2 | 3 | 4 | def set_prefs(prefs): 5 | """This function is called before opening the project""" 6 | 7 | # Specify which files and folders to ignore in the project. 8 | # Changes to ignored resources are not added to the history and 9 | # VCSs. Also they are not returned in `Project.get_files()`. 10 | # Note that ``?`` and ``*`` match all characters but slashes. 11 | # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' 12 | # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' 13 | # '.svn': matches 'pkg/.svn' and all of its children 14 | # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' 15 | # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' 16 | prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', 17 | '.hg', '.svn', '_svn', '.git', 18 | '__pycache__'] 19 | 20 | # Specifies which files should be considered python files. It is 21 | # useful when you have scripts inside your project. Only files 22 | # ending with ``.py`` are considered to be python files by 23 | # default. 24 | #prefs['python_files'] = ['*.py'] 25 | 26 | # Custom source folders: By default rope searches the project 27 | # for finding source folders (folders that should be searched 28 | # for finding modules). You can add paths to that list. Note 29 | # that rope guesses project source folders correctly most of the 30 | # time; use this if you have any problems. 31 | # The folders should be relative to project root and use '/' for 32 | # separating folders regardless of the platform rope is running on. 33 | # 'src/my_source_folder' for instance. 34 | #prefs.add('source_folders', 'src') 35 | 36 | # You can extend python path for looking up modules 37 | #prefs.add('python_path', '~/python/') 38 | 39 | # Should rope save object information or not. 40 | prefs['save_objectdb'] = True 41 | prefs['compress_objectdb'] = False 42 | 43 | # If `True`, rope analyzes each module when it is being saved. 44 | prefs['automatic_soa'] = True 45 | # The depth of calls to follow in static object analysis 46 | prefs['soa_followed_calls'] = 0 47 | 48 | # If `False` when running modules or unit tests "dynamic object 49 | # analysis" is turned off. This makes them much faster. 50 | prefs['perform_doa'] = True 51 | 52 | # Rope can check the validity of its object DB when running. 53 | prefs['validate_objectdb'] = True 54 | 55 | # How many undos to hold? 56 | prefs['max_history_items'] = 32 57 | 58 | # Shows whether to save history across sessions. 59 | prefs['save_history'] = True 60 | prefs['compress_history'] = False 61 | 62 | # Set the number spaces used for indenting. According to 63 | # :PEP:`8`, it is best to use 4 spaces. Since most of rope's 64 | # unit-tests use 4 spaces it is more reliable, too. 65 | prefs['indent_size'] = 4 66 | 67 | # Builtin and c-extension modules that are allowed to be imported 68 | # and inspected by rope. 69 | prefs['extension_modules'] = [] 70 | 71 | # Add all standard c-extensions to extension_modules list. 72 | prefs['import_dynload_stdmods'] = True 73 | 74 | # If `True` modules with syntax errors are considered to be empty. 75 | # The default value is `False`; When `False` syntax errors raise 76 | # `rope.base.exceptions.ModuleSyntaxError` exception. 77 | prefs['ignore_syntax_errors'] = False 78 | 79 | # If `True`, rope ignores unresolvable imports. Otherwise, they 80 | # appear in the importing namespace. 81 | prefs['ignore_bad_imports'] = False 82 | 83 | 84 | def project_opened(project): 85 | """This function is called after opening the project""" 86 | # Do whatever you like here! 87 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/exceptions.py: -------------------------------------------------------------------------------- 1 | class RopeError(Exception): 2 | """Base exception for rope""" 3 | 4 | 5 | class ResourceNotFoundError(RopeError): 6 | """Resource not found exception""" 7 | 8 | 9 | class RefactoringError(RopeError): 10 | """Errors for performing a refactoring""" 11 | 12 | 13 | class InterruptedTaskError(RopeError): 14 | """The task has been interrupted""" 15 | 16 | 17 | class HistoryError(RopeError): 18 | """Errors for history undo/redo operations""" 19 | 20 | 21 | class ModuleNotFoundError(RopeError): 22 | """Module not found exception""" 23 | 24 | 25 | class AttributeNotFoundError(RopeError): 26 | """Attribute not found exception""" 27 | 28 | 29 | class NameNotFoundError(RopeError): 30 | """Name not found exception""" 31 | 32 | 33 | class BadIdentifierError(RopeError): 34 | """The name cannot be resolved""" 35 | 36 | 37 | class ModuleSyntaxError(RopeError): 38 | """Module has syntax errors 39 | 40 | The `filename` and `lineno` fields indicate where the error has 41 | occurred. 42 | 43 | """ 44 | 45 | def __init__(self, filename, lineno, message): 46 | self.filename = filename 47 | self.lineno = lineno 48 | self.message_ = message 49 | super(ModuleSyntaxError, self).__init__( 50 | 'Syntax error in file <%s> line <%s>: %s' % 51 | (filename, lineno, message)) 52 | 53 | 54 | class ModuleDecodeError(RopeError): 55 | """Cannot decode module""" 56 | 57 | def __init__(self, filename, message): 58 | self.filename = filename 59 | self.message_ = message 60 | super(ModuleDecodeError, self).__init__( 61 | 'Cannot decode file <%s>: %s' % (filename, message)) 62 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/libutils.py: -------------------------------------------------------------------------------- 1 | """A few useful functions for using rope as a library""" 2 | import os.path 3 | 4 | import rope.base.project 5 | import rope.base.pycore 6 | from rope.base import taskhandle 7 | 8 | 9 | def path_to_resource(project, path, type=None): 10 | """Get the resource at path 11 | 12 | You only need to specify `type` if `path` does not exist. It can 13 | be either 'file' or 'folder'. If the type is `None` it is assumed 14 | that the resource already exists. 15 | 16 | Note that this function uses `Project.get_resource()`, 17 | `Project.get_file()`, and `Project.get_folder()` methods. 18 | 19 | """ 20 | project_path = relative(project.address, path) 21 | if project_path is None: 22 | project_path = rope.base.project._realpath(path) 23 | project = rope.base.project.get_no_project() 24 | if type is None: 25 | return project.get_resource(project_path) 26 | if type == 'file': 27 | return project.get_file(project_path) 28 | if type == 'folder': 29 | return project.get_folder(project_path) 30 | return None 31 | 32 | def relative(root, path): 33 | root = rope.base.project._realpath(root).replace(os.path.sep, '/') 34 | path = rope.base.project._realpath(path).replace(os.path.sep, '/') 35 | if path == root: 36 | return '' 37 | if path.startswith(root + '/'): 38 | return path[len(root) + 1:] 39 | 40 | def report_change(project, path, old_content): 41 | """Report that the contents of file at `path` was changed 42 | 43 | The new contents of file is retrieved by reading the file. 44 | 45 | """ 46 | resource = path_to_resource(project, path) 47 | if resource is None: 48 | return 49 | for observer in list(project.observers): 50 | observer.resource_changed(resource) 51 | if project.pycore.automatic_soa: 52 | rope.base.pycore.perform_soa_on_changed_scopes(project, resource, 53 | old_content) 54 | 55 | def analyze_modules(project, task_handle=taskhandle.NullTaskHandle()): 56 | """Perform static object analysis on all python files in the project 57 | 58 | Note that this might be really time consuming. 59 | """ 60 | resources = project.pycore.get_python_files() 61 | job_set = task_handle.create_jobset('Analyzing Modules', len(resources)) 62 | for resource in resources: 63 | job_set.started_job(resource.path) 64 | project.pycore.analyze_module(resource) 65 | job_set.finished_job() 66 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/oi/__init__.py: -------------------------------------------------------------------------------- 1 | """Rope object analysis and inference package 2 | 3 | Rope makes some simplifying assumptions about a python program. It 4 | assumes that a program only performs assignments and function calls. 5 | Tracking assignments is simple and `PyName` objects handle that. The 6 | main problem is function calls. Rope uses these two approaches for 7 | obtaining call information: 8 | 9 | * Static object analysis: `rope.base.pycore.PyCore.analyze_module()` 10 | 11 | It can analyze modules to obtain information about functions. This 12 | is done by analyzing function calls in a module or scope. Currently 13 | SOA analyzes the scopes that are changed while saving or when the 14 | user asks to analyze a module. That is mainly because static 15 | analysis is time-consuming. 16 | 17 | * Dynamic object analysis: `rope.base.pycore.PyCore.run_module()` 18 | 19 | When you run a module or your testsuite, when DOA is enabled, it 20 | collects information about parameters passed to and objects returned 21 | from functions. The main problem with this approach is that it is 22 | quite slow; Not when looking up the information but when collecting 23 | them. 24 | 25 | An instance of `rope.base.oi.objectinfo.ObjectInfoManager` can be used 26 | for accessing these information. It saves the data in a 27 | `rope.base.oi.objectdb.ObjectDB` internally. 28 | 29 | Now if our objectdb does not know anything about a function and we 30 | need the value returned by it, static object inference, SOI, comes 31 | into play. It analyzes function body and tries to infer the object 32 | that is returned from it (we usually need the returned value for the 33 | given parameter objects). 34 | 35 | Rope might collect and store information for other `PyName`\s, too. 36 | For instance rope stores the object builtin containers hold. 37 | 38 | """ 39 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/oi/memorydb.py: -------------------------------------------------------------------------------- 1 | from rope.base.oi import objectdb 2 | 3 | 4 | class MemoryDB(objectdb.FileDict): 5 | 6 | def __init__(self, project, persist=None): 7 | self.project = project 8 | self._persist = persist 9 | self.files = self 10 | self._load_files() 11 | self.project.data_files.add_write_hook(self.write) 12 | 13 | def _load_files(self): 14 | self._files = {} 15 | if self.persist: 16 | result = self.project.data_files.read_data( 17 | 'objectdb', compress=self.compress, import_=True) 18 | if result is not None: 19 | self._files = result 20 | 21 | def keys(self): 22 | return list(self._files.keys()) 23 | 24 | def __contains__(self, key): 25 | return key in self._files 26 | 27 | def __getitem__(self, key): 28 | return FileInfo(self._files[key]) 29 | 30 | def create(self, path): 31 | self._files[path] = {} 32 | 33 | def rename(self, file, newfile): 34 | if file not in self._files: 35 | return 36 | self._files[newfile] = self._files[file] 37 | del self[file] 38 | 39 | def __delitem__(self, file): 40 | del self._files[file] 41 | 42 | def write(self): 43 | if self.persist: 44 | self.project.data_files.write_data('objectdb', self._files, 45 | self.compress) 46 | 47 | @property 48 | def compress(self): 49 | return self.project.prefs.get('compress_objectdb', False) 50 | 51 | @property 52 | def persist(self): 53 | if self._persist is not None: 54 | return self._persist 55 | else: 56 | return self.project.prefs.get('save_objectdb', False) 57 | 58 | 59 | class FileInfo(objectdb.FileInfo): 60 | 61 | def __init__(self, scopes): 62 | self.scopes = scopes 63 | 64 | def create_scope(self, key): 65 | self.scopes[key] = ScopeInfo() 66 | 67 | def keys(self): 68 | return list(self.scopes.keys()) 69 | 70 | def __contains__(self, key): 71 | return key in self.scopes 72 | 73 | def __getitem__(self, key): 74 | return self.scopes[key] 75 | 76 | def __delitem__(self, key): 77 | del self.scopes[key] 78 | 79 | 80 | class ScopeInfo(objectdb.ScopeInfo): 81 | 82 | def __init__(self): 83 | self.call_info = {} 84 | self.per_name = {} 85 | 86 | def get_per_name(self, name): 87 | return self.per_name.get(name, None) 88 | 89 | def save_per_name(self, name, value): 90 | self.per_name[name] = value 91 | 92 | def get_returned(self, parameters): 93 | return self.call_info.get(parameters, None) 94 | 95 | def get_call_infos(self): 96 | for args, returned in self.call_info.items(): 97 | yield objectdb.CallInfo(args, returned) 98 | 99 | def add_call(self, parameters, returned): 100 | self.call_info[parameters] = returned 101 | 102 | def __getstate__(self): 103 | return (self.call_info, self.per_name) 104 | 105 | def __setstate__(self, data): 106 | self.call_info, self.per_name = data 107 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/prefs.py: -------------------------------------------------------------------------------- 1 | class Prefs(object): 2 | 3 | def __init__(self): 4 | self.prefs = {} 5 | self.callbacks = {} 6 | 7 | def set(self, key, value): 8 | """Set the value of `key` preference to `value`.""" 9 | if key in self.callbacks: 10 | self.callbacks[key](value) 11 | else: 12 | self.prefs[key] = value 13 | 14 | def add(self, key, value): 15 | """Add an entry to a list preference 16 | 17 | Add `value` to the list of entries for the `key` preference. 18 | 19 | """ 20 | if not key in self.prefs: 21 | self.prefs[key] = [] 22 | self.prefs[key].append(value) 23 | 24 | def get(self, key, default=None): 25 | """Get the value of the key preference""" 26 | return self.prefs.get(key, default) 27 | 28 | def add_callback(self, key, callback): 29 | """Add `key` preference with `callback` function 30 | 31 | Whenever `key` is set the callback is called with the 32 | given `value` as parameter. 33 | 34 | """ 35 | self.callbacks[key] = callback 36 | 37 | def __setitem__(self, key, value): 38 | self.set(key, value) 39 | 40 | def __getitem__(self, key): 41 | return self.get(key) 42 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/pynamesdef.py: -------------------------------------------------------------------------------- 1 | import rope.base.oi.soi 2 | from rope.base import pynames 3 | from rope.base.pynames import * 4 | 5 | 6 | class AssignedName(pynames.AssignedName): 7 | 8 | def __init__(self, lineno=None, module=None, pyobject=None): 9 | self.lineno = lineno 10 | self.module = module 11 | self.assignments = [] 12 | self.pyobject = _Inferred(self._get_inferred, 13 | pynames._get_concluded_data(module)) 14 | self.pyobject.set(pyobject) 15 | 16 | @utils.prevent_recursion(lambda: None) 17 | def _get_inferred(self): 18 | if self.module is not None: 19 | return rope.base.oi.soi.infer_assigned_object(self) 20 | 21 | def get_object(self): 22 | return self.pyobject.get() 23 | 24 | def get_definition_location(self): 25 | """Returns a (module, lineno) tuple""" 26 | if self.lineno is None and self.assignments: 27 | self.lineno = self.assignments[0].get_lineno() 28 | return (self.module, self.lineno) 29 | 30 | def invalidate(self): 31 | """Forget the `PyObject` this `PyName` holds""" 32 | self.pyobject.set(None) 33 | 34 | 35 | class ParameterName(pynames.ParameterName): 36 | 37 | def __init__(self, pyfunction, index): 38 | self.pyfunction = pyfunction 39 | self.index = index 40 | 41 | def get_object(self): 42 | result = self.pyfunction.get_parameter(self.index) 43 | if result is None: 44 | result = rope.base.pyobjects.get_unknown() 45 | return result 46 | 47 | def get_objects(self): 48 | """Returns the list of objects passed as this parameter""" 49 | return rope.base.oi.soi.get_passed_objects( 50 | self.pyfunction, self.index) 51 | 52 | def get_definition_location(self): 53 | return (self.pyfunction.get_module(), self.pyfunction.get_ast().lineno) 54 | 55 | _Inferred = pynames._Inferred 56 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/simplify.py: -------------------------------------------------------------------------------- 1 | """A module to ease code analysis 2 | 3 | This module is here to help source code analysis. 4 | """ 5 | import re 6 | 7 | from rope.base import codeanalyze, utils 8 | 9 | 10 | @utils.cached(7) 11 | def real_code(source): 12 | """Simplify `source` for analysis 13 | 14 | It replaces: 15 | 16 | * comments with spaces 17 | * strs with a new str filled with spaces 18 | * implicit and explicit continuations with spaces 19 | * tabs and semicolons with spaces 20 | 21 | The resulting code is a lot easier to analyze if we are interested 22 | only in offsets. 23 | """ 24 | collector = codeanalyze.ChangeCollector(source) 25 | for start, end in ignored_regions(source): 26 | if source[start] == '#': 27 | replacement = ' ' * (end - start) 28 | else: 29 | replacement = '"%s"' % (' ' * (end - start - 2)) 30 | collector.add_change(start, end, replacement) 31 | source = collector.get_changed() or source 32 | collector = codeanalyze.ChangeCollector(source) 33 | parens = 0 34 | for match in _parens.finditer(source): 35 | i = match.start() 36 | c = match.group() 37 | if c in '({[': 38 | parens += 1 39 | if c in ')}]': 40 | parens -= 1 41 | if c == '\n' and parens > 0: 42 | collector.add_change(i, i + 1, ' ') 43 | source = collector.get_changed() or source 44 | return source.replace('\\\n', ' ').replace('\t', ' ').replace(';', '\n') 45 | 46 | 47 | @utils.cached(7) 48 | def ignored_regions(source): 49 | """Return ignored regions like strings and comments in `source` """ 50 | return [(match.start(), match.end()) for match in _str.finditer(source)] 51 | 52 | 53 | _str = re.compile('%s|%s' % (codeanalyze.get_comment_pattern(), 54 | codeanalyze.get_string_pattern())) 55 | _parens = re.compile(r'[\({\[\]}\)\n]') 56 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/stdmods.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from rope.base import utils 5 | 6 | 7 | def _stdlib_path(): 8 | import inspect 9 | return os.path.dirname(inspect.getsourcefile(inspect)) 10 | 11 | @utils.cached(1) 12 | def standard_modules(): 13 | return python_modules() | dynload_modules() 14 | 15 | @utils.cached(1) 16 | def python_modules(): 17 | result = set() 18 | lib_path = _stdlib_path() 19 | if os.path.exists(lib_path): 20 | for name in os.listdir(lib_path): 21 | path = os.path.join(lib_path, name) 22 | if os.path.isdir(path): 23 | if '-' not in name: 24 | result.add(name) 25 | else: 26 | if name.endswith('.py'): 27 | result.add(name[:-3]) 28 | return result 29 | 30 | @utils.cached(1) 31 | def dynload_modules(): 32 | result = set(sys.builtin_module_names) 33 | dynload_path = os.path.join(_stdlib_path(), 'lib-dynload') 34 | if os.path.exists(dynload_path): 35 | for name in os.listdir(dynload_path): 36 | path = os.path.join(dynload_path, name) 37 | if os.path.isfile(path): 38 | if name.endswith('.so') or name.endswith('.dll'): 39 | if "cpython" in name: 40 | result.add(os.path.splitext(os.path.splitext(name)[0])[0]) 41 | else: 42 | result.add(os.path.splitext(name)[0]) 43 | return result 44 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/taskhandle.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | from rope.base import exceptions 4 | 5 | 6 | class TaskHandle(object): 7 | 8 | def __init__(self, name='Task', interrupts=True): 9 | """Construct a TaskHandle 10 | 11 | If `interrupts` is `False` the task won't be interrupted by 12 | calling `TaskHandle.stop()`. 13 | 14 | """ 15 | self.name = name 16 | self.interrupts = interrupts 17 | self.stopped = False 18 | self.job_sets = [] 19 | self.observers = [] 20 | 21 | def stop(self): 22 | """Interrupts the refactoring""" 23 | if self.interrupts: 24 | self.stopped = True 25 | self._inform_observers() 26 | 27 | def current_jobset(self): 28 | """Return the current `JobSet`""" 29 | if self.job_sets: 30 | return self.job_sets[-1] 31 | 32 | def add_observer(self, observer): 33 | """Register an observer for this task handle 34 | 35 | The observer is notified whenever the task is stopped or 36 | a job gets finished. 37 | 38 | """ 39 | self.observers.append(observer) 40 | 41 | def is_stopped(self): 42 | return self.stopped 43 | 44 | def get_jobsets(self): 45 | return self.job_sets 46 | 47 | def create_jobset(self, name='JobSet', count=None): 48 | result = JobSet(self, name=name, count=count) 49 | self.job_sets.append(result) 50 | self._inform_observers() 51 | return result 52 | 53 | def _inform_observers(self): 54 | for observer in list(self.observers): 55 | observer() 56 | 57 | 58 | class JobSet(object): 59 | 60 | def __init__(self, handle, name, count): 61 | self.handle = handle 62 | self.name = name 63 | self.count = count 64 | self.done = 0 65 | self.job_name = None 66 | 67 | def started_job(self, name): 68 | self.check_status() 69 | self.job_name = name 70 | self.handle._inform_observers() 71 | 72 | def finished_job(self): 73 | self.check_status() 74 | self.done += 1 75 | self.handle._inform_observers() 76 | self.job_name = None 77 | 78 | def check_status(self): 79 | if self.handle.is_stopped(): 80 | raise exceptions.InterruptedTaskError() 81 | 82 | def get_active_job_name(self): 83 | return self.job_name 84 | 85 | def get_percent_done(self): 86 | if self.count is not None and self.count > 0: 87 | percent = self.done * 100 // self.count 88 | return min(percent, 100) 89 | 90 | def get_name(self): 91 | return self.name 92 | 93 | 94 | class NullTaskHandle(object): 95 | 96 | def __init__(self): 97 | pass 98 | 99 | def is_stopped(self): 100 | return False 101 | 102 | def stop(self): 103 | pass 104 | 105 | def create_jobset(self, *args, **kwds): 106 | return NullJobSet() 107 | 108 | def get_jobsets(self): 109 | return [] 110 | 111 | def add_observer(self, observer): 112 | pass 113 | 114 | 115 | class NullJobSet(object): 116 | 117 | def started_job(self, name): 118 | pass 119 | 120 | def finished_job(self): 121 | pass 122 | 123 | def check_status(self): 124 | pass 125 | 126 | def get_active_job_name(self): 127 | pass 128 | 129 | def get_percent_done(self): 130 | pass 131 | 132 | def get_name(self): 133 | pass 134 | -------------------------------------------------------------------------------- /pymode/libs3/rope/base/utils.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | def saveit(func): 5 | """A decorator that caches the return value of a function""" 6 | 7 | name = '_' + func.__name__ 8 | def _wrapper(self, *args, **kwds): 9 | if not hasattr(self, name): 10 | setattr(self, name, func(self, *args, **kwds)) 11 | return getattr(self, name) 12 | return _wrapper 13 | 14 | cacheit = saveit 15 | 16 | def prevent_recursion(default): 17 | """A decorator that returns the return value of `default` in recursions""" 18 | def decorator(func): 19 | name = '_calling_%s_' % func.__name__ 20 | def newfunc(self, *args, **kwds): 21 | if getattr(self, name, False): 22 | return default() 23 | setattr(self, name, True) 24 | try: 25 | return func(self, *args, **kwds) 26 | finally: 27 | setattr(self, name, False) 28 | return newfunc 29 | return decorator 30 | 31 | 32 | def ignore_exception(exception_class): 33 | """A decorator that ignores `exception_class` exceptions""" 34 | def _decorator(func): 35 | def newfunc(*args, **kwds): 36 | try: 37 | return func(*args, **kwds) 38 | except exception_class: 39 | pass 40 | return newfunc 41 | return _decorator 42 | 43 | 44 | def deprecated(message=None): 45 | """A decorator for deprecated functions""" 46 | def _decorator(func, message=message): 47 | if message is None: 48 | message = '%s is deprecated' % func.__name__ 49 | def newfunc(*args, **kwds): 50 | warnings.warn(message, DeprecationWarning, stacklevel=2) 51 | return func(*args, **kwds) 52 | return newfunc 53 | return _decorator 54 | 55 | 56 | def cached(count): 57 | """A caching decorator based on parameter objects""" 58 | def decorator(func): 59 | return _Cached(func, count) 60 | return decorator 61 | 62 | class _Cached(object): 63 | 64 | def __init__(self, func, count): 65 | self.func = func 66 | self.cache = [] 67 | self.count = count 68 | 69 | def __call__(self, *args, **kwds): 70 | key = (args, kwds) 71 | for cached_key, cached_result in self.cache: 72 | if cached_key == key: 73 | return cached_result 74 | result = self.func(*args, **kwds) 75 | self.cache.append((key, result)) 76 | if len(self.cache) > self.count: 77 | del self.cache[0] 78 | return result 79 | -------------------------------------------------------------------------------- /pymode/libs3/rope/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | """rope IDE tools package 2 | 3 | This package contains modules that can be used in IDEs 4 | but do not depend on the UI. So these modules will be used 5 | by `rope.ui` modules. 6 | 7 | """ 8 | -------------------------------------------------------------------------------- /pymode/libs3/rope/contrib/changestack.py: -------------------------------------------------------------------------------- 1 | """For performing many refactorings as a single command 2 | 3 | `changestack` module can be used to perform many refactorings on top 4 | of each other as one bigger command. It can be used like:: 5 | 6 | stack = ChangeStack(project, 'my big command') 7 | 8 | #.. 9 | stack.push(refactoring1.get_changes()) 10 | #.. 11 | stack.push(refactoring2.get_changes()) 12 | #.. 13 | stack.push(refactoringX.get_changes()) 14 | 15 | stack.pop_all() 16 | changes = stack.merged() 17 | 18 | Now `changes` can be previewed or performed as before. 19 | """ 20 | 21 | from rope.base import change 22 | 23 | 24 | class ChangeStack(object): 25 | 26 | def __init__(self, project, description='merged changes'): 27 | self.project = project 28 | self.description = description 29 | self.stack = [] 30 | 31 | def push(self, changes): 32 | self.stack.append(changes) 33 | self.project.do(changes) 34 | 35 | def pop_all(self): 36 | for i in range(len(self.stack)): 37 | self.project.history.undo(drop=True) 38 | 39 | def merged(self): 40 | result = change.ChangeSet(self.description) 41 | for changes in self.stack: 42 | for c in self._basic_changes(changes): 43 | result.add_change(c) 44 | return result 45 | 46 | def _basic_changes(self, changes): 47 | if isinstance(changes, change.ChangeSet): 48 | for child in changes.changes: 49 | for atom in self._basic_changes(child): 50 | yield atom 51 | else: 52 | yield changes 53 | -------------------------------------------------------------------------------- /pymode/libs3/rope/contrib/finderrors.py: -------------------------------------------------------------------------------- 1 | """Finding bad name and attribute accesses 2 | 3 | `find_errors` function can be used to find possible bad name and 4 | attribute accesses. As an example:: 5 | 6 | errors = find_errors(project, project.get_resource('mod.py')) 7 | for error in errors: 8 | print '%s: %s' % (error.lineno, error.error) 9 | 10 | prints possible errors for ``mod.py`` file. 11 | 12 | TODO: 13 | 14 | * use task handles 15 | * reporting names at most once 16 | * attributes of extension modules that don't appear in 17 | extension_modules project config can be ignored 18 | * not calling `PyScope.get_inner_scope_for_line()` if it is a 19 | bottleneck; needs profiling 20 | * not reporting occurrences where rope cannot infer the object 21 | * rope saves multiple objects for some of the names in its objectdb 22 | use all of them not to give false positives 23 | * ... ;-) 24 | 25 | """ 26 | from rope.base import ast, evaluate, pyobjects 27 | 28 | 29 | def find_errors(project, resource): 30 | """Find possible bad name and attribute accesses 31 | 32 | It returns a list of `Error`\s. 33 | """ 34 | pymodule = project.pycore.resource_to_pyobject(resource) 35 | finder = _BadAccessFinder(pymodule) 36 | ast.walk(pymodule.get_ast(), finder) 37 | return finder.errors 38 | 39 | 40 | class _BadAccessFinder(object): 41 | 42 | def __init__(self, pymodule): 43 | self.pymodule = pymodule 44 | self.scope = pymodule.get_scope() 45 | self.errors = [] 46 | 47 | def _Name(self, node): 48 | if isinstance(node.ctx, (ast.Store, ast.Param)): 49 | return 50 | scope = self.scope.get_inner_scope_for_line(node.lineno) 51 | pyname = scope.lookup(node.id) 52 | if pyname is None: 53 | self._add_error(node, 'Unresolved variable') 54 | elif self._is_defined_after(scope, pyname, node.lineno): 55 | self._add_error(node, 'Defined later') 56 | 57 | def _Attribute(self, node): 58 | if not isinstance(node.ctx, ast.Store): 59 | scope = self.scope.get_inner_scope_for_line(node.lineno) 60 | pyname = evaluate.eval_node(scope, node.value) 61 | if pyname is not None and \ 62 | pyname.get_object() != pyobjects.get_unknown(): 63 | if node.attr not in pyname.get_object(): 64 | self._add_error(node, 'Unresolved attribute') 65 | ast.walk(node.value, self) 66 | 67 | def _add_error(self, node, msg): 68 | if isinstance(node, ast.Attribute): 69 | name = node.attr 70 | else: 71 | name = node.id 72 | if name != 'None': 73 | error = Error(node.lineno, msg + ' ' + name) 74 | self.errors.append(error) 75 | 76 | def _is_defined_after(self, scope, pyname, lineno): 77 | location = pyname.get_definition_location() 78 | if location is not None and location[1] is not None: 79 | if location[0] == self.pymodule and \ 80 | lineno <= location[1] <= scope.get_end(): 81 | return True 82 | 83 | 84 | class Error(object): 85 | 86 | def __init__(self, lineno, error): 87 | self.lineno = lineno 88 | self.error = error 89 | 90 | def __str__(self): 91 | return '%s: %s' % (self.lineno, self.error) 92 | -------------------------------------------------------------------------------- /pymode/libs3/rope/contrib/fixmodnames.py: -------------------------------------------------------------------------------- 1 | """Fix the name of modules 2 | 3 | This module is useful when you want to rename many of the modules in 4 | your project. That can happen specially when you want to change their 5 | naming style. 6 | 7 | For instance:: 8 | 9 | fixer = FixModuleNames(project) 10 | changes = fixer.get_changes(fixer=str.lower) 11 | project.do(changes) 12 | 13 | Here it renames all modules and packages to use lower-cased chars. 14 | You can tell it to use any other style by using the ``fixer`` 15 | argument. 16 | 17 | """ 18 | from rope.base import change, taskhandle 19 | from rope.contrib import changestack 20 | from rope.refactor import rename 21 | 22 | 23 | class FixModuleNames(object): 24 | 25 | def __init__(self, project): 26 | self.project = project 27 | 28 | def get_changes(self, fixer=str.lower, 29 | task_handle=taskhandle.NullTaskHandle()): 30 | """Fix module names 31 | 32 | `fixer` is a function that takes and returns a `str`. Given 33 | the name of a module, it should return the fixed name. 34 | 35 | """ 36 | stack = changestack.ChangeStack(self.project, 'Fixing module names') 37 | jobset = task_handle.create_jobset('Fixing module names', 38 | self._count_fixes(fixer) + 1) 39 | try: 40 | while True: 41 | for resource in self._tobe_fixed(fixer): 42 | jobset.started_job(resource.path) 43 | renamer = rename.Rename(self.project, resource) 44 | changes = renamer.get_changes(fixer(self._name(resource))) 45 | stack.push(changes) 46 | jobset.finished_job() 47 | break 48 | else: 49 | break 50 | finally: 51 | jobset.started_job('Reverting to original state') 52 | stack.pop_all() 53 | jobset.finished_job() 54 | return stack.merged() 55 | 56 | def _count_fixes(self, fixer): 57 | return len(list(self._tobe_fixed(fixer))) 58 | 59 | def _tobe_fixed(self, fixer): 60 | for resource in self.project.pycore.get_python_files(): 61 | modname = self._name(resource) 62 | if modname != fixer(modname): 63 | yield resource 64 | 65 | def _name(self, resource): 66 | modname = resource.name.rsplit('.', 1)[0] 67 | if modname == '__init__': 68 | modname = resource.parent.name 69 | return modname 70 | -------------------------------------------------------------------------------- /pymode/libs3/rope/refactor/__init__.py: -------------------------------------------------------------------------------- 1 | """rope refactor package 2 | 3 | This package contains modules that perform python refactorings. 4 | Refactoring classes perform refactorings in 4 steps: 5 | 6 | 1. Collect some data for performing the refactoring and use them 7 | to construct a refactoring class. Like:: 8 | 9 | renamer = Rename(project, resource, offset) 10 | 11 | 2. Some refactorings give you useful information about the 12 | refactoring after their construction. Like:: 13 | 14 | print(renamer.get_old_name()) 15 | 16 | 3. Give the refactoring class more information about how to 17 | perform the refactoring and get the changes this refactoring is 18 | going to make. This is done by calling `get_changes` method of the 19 | refactoring class. Like:: 20 | 21 | changes = renamer.get_changes(new_name) 22 | 23 | 4. You can commit the changes. Like:: 24 | 25 | project.do(changes) 26 | 27 | These steps are like the steps IDEs usually do for performing a 28 | refactoring. These are the things an IDE does in each step: 29 | 30 | 1. Construct a refactoring object by giving it information like 31 | resource, offset and ... . Some of the refactoring problems (like 32 | performing rename refactoring on language keywords) can be reported 33 | here. 34 | 2. Print some information about the refactoring and ask the user 35 | about the information that are necessary for completing the 36 | refactoring (like new name). 37 | 3. Call the `get_changes` by passing it information asked from 38 | the user (if necessary) and get and preview the changes returned by 39 | it. 40 | 4. perform the refactoring. 41 | 42 | From ``0.5m5`` release the `get_changes()` method of some time- 43 | consuming refactorings take an optional `rope.base.taskhandle. 44 | TaskHandle` parameter. You can use this object for stopping or 45 | monitoring the progress of refactorings. 46 | 47 | """ 48 | from rope.refactor.importutils import ImportOrganizer 49 | from rope.refactor.topackage import ModuleToPackage 50 | 51 | 52 | __all__ = ['rename', 'move', 'inline', 'extract', 'restructure', 'topackage', 53 | 'importutils', 'usefunction', 'change_signature', 54 | 'encapsulate_field', 'introduce_factory', 'introduce_parameter', 55 | 'localtofield', 'method_object', 'multiproject'] 56 | -------------------------------------------------------------------------------- /pymode/libs3/rope/refactor/localtofield.py: -------------------------------------------------------------------------------- 1 | from rope.base import pynames, evaluate, exceptions, worder 2 | from rope.refactor.rename import Rename 3 | 4 | 5 | class LocalToField(object): 6 | 7 | def __init__(self, project, resource, offset): 8 | self.project = project 9 | self.pycore = project.pycore 10 | self.resource = resource 11 | self.offset = offset 12 | 13 | def get_changes(self): 14 | name = worder.get_name_at(self.resource, self.offset) 15 | this_pymodule = self.pycore.resource_to_pyobject(self.resource) 16 | pyname = evaluate.eval_location(this_pymodule, self.offset) 17 | if not self._is_a_method_local(pyname): 18 | raise exceptions.RefactoringError( 19 | 'Convert local variable to field should be performed on \n' 20 | 'a local variable of a method.') 21 | 22 | pymodule, lineno = pyname.get_definition_location() 23 | function_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) 24 | # Not checking redefinition 25 | #self._check_redefinition(name, function_scope) 26 | 27 | new_name = self._get_field_name(function_scope.pyobject, name) 28 | changes = Rename(self.project, self.resource, self.offset).\ 29 | get_changes(new_name, resources=[self.resource]) 30 | return changes 31 | 32 | def _check_redefinition(self, name, function_scope): 33 | class_scope = function_scope.parent 34 | if name in class_scope.pyobject: 35 | raise exceptions.RefactoringError( 36 | 'The field %s already exists' % name) 37 | 38 | def _get_field_name(self, pyfunction, name): 39 | self_name = pyfunction.get_param_names()[0] 40 | new_name = self_name + '.' + name 41 | return new_name 42 | 43 | def _is_a_method_local(self, pyname): 44 | pymodule, lineno = pyname.get_definition_location() 45 | holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) 46 | parent = holding_scope.parent 47 | return isinstance(pyname, pynames.AssignedName) and \ 48 | pyname in list(holding_scope.get_names().values()) and \ 49 | holding_scope.get_kind() == 'Function' and \ 50 | parent is not None and parent.get_kind() == 'Class' 51 | -------------------------------------------------------------------------------- /pymode/libs3/rope/refactor/multiproject.py: -------------------------------------------------------------------------------- 1 | """This module can be used for performing cross-project refactorings 2 | 3 | See the "cross-project refactorings" section of ``docs/library.txt`` 4 | file. 5 | 6 | """ 7 | 8 | from rope.base import resources, project, libutils 9 | 10 | 11 | class MultiProjectRefactoring(object): 12 | 13 | def __init__(self, refactoring, projects, addpath=True): 14 | """Create a multiproject proxy for the main refactoring 15 | 16 | `projects` are other project. 17 | 18 | """ 19 | self.refactoring = refactoring 20 | self.projects = projects 21 | self.addpath = addpath 22 | 23 | def __call__(self, project, *args, **kwds): 24 | """Create the refactoring""" 25 | return _MultiRefactoring(self.refactoring, self.projects, 26 | self.addpath, project, *args, **kwds) 27 | 28 | 29 | class _MultiRefactoring(object): 30 | 31 | def __init__(self, refactoring, other_projects, addpath, 32 | project, *args, **kwds): 33 | self.refactoring = refactoring 34 | self.projects = [project] + other_projects 35 | for other_project in other_projects: 36 | for folder in self.project.pycore.get_source_folders(): 37 | other_project.get_prefs().add('python_path', folder.real_path) 38 | self.refactorings = [] 39 | for other in self.projects: 40 | args, kwds = self._resources_for_args(other, args, kwds) 41 | self.refactorings.append( 42 | self.refactoring(other, *args, **kwds)) 43 | 44 | def get_all_changes(self, *args, **kwds): 45 | """Get a project to changes dict""" 46 | result = [] 47 | for project, refactoring in zip(self.projects, self.refactorings): 48 | args, kwds = self._resources_for_args(project, args, kwds) 49 | result.append((project, refactoring.get_changes(*args, **kwds))) 50 | return result 51 | 52 | def __getattr__(self, name): 53 | return getattr(self.main_refactoring, name) 54 | 55 | def _resources_for_args(self, project, args, kwds): 56 | newargs = [self._change_project_resource(project, arg) for arg in args] 57 | newkwds = dict((name, self._change_project_resource(project, value)) 58 | for name, value in kwds.items()) 59 | return newargs, newkwds 60 | 61 | def _change_project_resource(self, project, obj): 62 | if isinstance(obj, resources.Resource) and \ 63 | obj.project != project: 64 | return libutils.path_to_resource(project, obj.real_path) 65 | return obj 66 | 67 | @property 68 | def project(self): 69 | return self.projects[0] 70 | 71 | @property 72 | def main_refactoring(self): 73 | return self.refactorings[0] 74 | 75 | 76 | def perform(project_changes): 77 | for project, changes in project_changes: 78 | project.do(changes) 79 | -------------------------------------------------------------------------------- /pymode/libs3/rope/refactor/sourceutils.py: -------------------------------------------------------------------------------- 1 | from rope.base import ast, codeanalyze 2 | 3 | 4 | def get_indents(lines, lineno): 5 | return codeanalyze.count_line_indents(lines.get_line(lineno)) 6 | 7 | 8 | def find_minimum_indents(source_code): 9 | result = 80 10 | lines = source_code.split('\n') 11 | for line in lines: 12 | if line.strip() == '': 13 | continue 14 | result = min(result, codeanalyze.count_line_indents(line)) 15 | return result 16 | 17 | 18 | def indent_lines(source_code, amount): 19 | if amount == 0: 20 | return source_code 21 | lines = source_code.splitlines(True) 22 | result = [] 23 | for l in lines: 24 | if l.strip() == '': 25 | result.append('\n') 26 | continue 27 | if amount < 0: 28 | indents = codeanalyze.count_line_indents(l) 29 | result.append(max(0, indents + amount) * ' ' + l.lstrip()) 30 | else: 31 | result.append(' ' * amount + l) 32 | return ''.join(result) 33 | 34 | 35 | def fix_indentation(code, new_indents): 36 | """Change the indentation of `code` to `new_indents`""" 37 | min_indents = find_minimum_indents(code) 38 | return indent_lines(code, new_indents - min_indents) 39 | 40 | 41 | def add_methods(pymodule, class_scope, methods_sources): 42 | source_code = pymodule.source_code 43 | lines = pymodule.lines 44 | insertion_line = class_scope.get_end() 45 | if class_scope.get_scopes(): 46 | insertion_line = class_scope.get_scopes()[-1].get_end() 47 | insertion_offset = lines.get_line_end(insertion_line) 48 | methods = '\n\n' + '\n\n'.join(methods_sources) 49 | indented_methods = fix_indentation( 50 | methods, get_indents(lines, class_scope.get_start()) + 51 | get_indent(pymodule.pycore)) 52 | result = [] 53 | result.append(source_code[:insertion_offset]) 54 | result.append(indented_methods) 55 | result.append(source_code[insertion_offset:]) 56 | return ''.join(result) 57 | 58 | 59 | def get_body(pyfunction): 60 | """Return unindented function body""" 61 | scope = pyfunction.get_scope() 62 | pymodule = pyfunction.get_module() 63 | start, end = get_body_region(pyfunction) 64 | return fix_indentation(pymodule.source_code[start:end], 0) 65 | 66 | 67 | def get_body_region(defined): 68 | """Return the start and end offsets of function body""" 69 | scope = defined.get_scope() 70 | pymodule = defined.get_module() 71 | lines = pymodule.lines 72 | node = defined.get_ast() 73 | start_line = node.lineno 74 | if defined.get_doc() is None: 75 | start_line = node.body[0].lineno 76 | elif len(node.body) > 1: 77 | start_line = node.body[1].lineno 78 | start = lines.get_line_start(start_line) 79 | scope_start = pymodule.logical_lines.logical_line_in(scope.start) 80 | if scope_start[1] >= start_line: 81 | # a one-liner! 82 | # XXX: what if colon appears in a string 83 | start = pymodule.source_code.index(':', start) + 1 84 | while pymodule.source_code[start].isspace(): 85 | start += 1 86 | end = min(lines.get_line_end(scope.end) + 1, len(pymodule.source_code)) 87 | return start, end 88 | 89 | 90 | def get_indent(pycore): 91 | project = pycore.project 92 | return project.prefs.get('indent_size', 4) 93 | -------------------------------------------------------------------------------- /pymode/libs3/rope/refactor/topackage.py: -------------------------------------------------------------------------------- 1 | import rope.refactor.importutils 2 | from rope.base.change import ChangeSet, ChangeContents, MoveResource, CreateFolder 3 | 4 | 5 | class ModuleToPackage(object): 6 | 7 | def __init__(self, project, resource): 8 | self.project = project 9 | self.pycore = project.pycore 10 | self.resource = resource 11 | 12 | def get_changes(self): 13 | changes = ChangeSet('Transform <%s> module to package' % 14 | self.resource.path) 15 | new_content = self._transform_relatives_to_absolute(self.resource) 16 | if new_content is not None: 17 | changes.add_change(ChangeContents(self.resource, new_content)) 18 | parent = self.resource.parent 19 | name = self.resource.name[:-3] 20 | changes.add_change(CreateFolder(parent, name)) 21 | parent_path = parent.path + '/' 22 | if not parent.path: 23 | parent_path = '' 24 | new_path = parent_path + '%s/__init__.py' % name 25 | if self.resource.project == self.project: 26 | changes.add_change(MoveResource(self.resource, new_path)) 27 | return changes 28 | 29 | def _transform_relatives_to_absolute(self, resource): 30 | pymodule = self.pycore.resource_to_pyobject(resource) 31 | import_tools = rope.refactor.importutils.ImportTools(self.pycore) 32 | return import_tools.relatives_to_absolutes(pymodule) 33 | -------------------------------------------------------------------------------- /pymode/lint.py: -------------------------------------------------------------------------------- 1 | """ Pylama integration. """ 2 | 3 | from .environment import env 4 | from .utils import silence_stderr 5 | 6 | import os.path 7 | 8 | 9 | def code_check(): 10 | """ Run pylama and check current file. 11 | 12 | :return bool: 13 | 14 | """ 15 | with silence_stderr(): 16 | 17 | from pylama.main import parse_options 18 | from pylama.tasks import check_path 19 | 20 | if not env.curbuf.name: 21 | return env.stop() 22 | 23 | options = parse_options( 24 | ignore=env.var('g:pymode_lint_ignore'), 25 | select=env.var('g:pymode_lint_select'), 26 | linters=env.var('g:pymode_lint_checkers'), 27 | force=1, 28 | ) 29 | env.debug(options) 30 | 31 | path = os.path.relpath(env.curbuf.name, env.curdir) 32 | env.debug("Start code check: ", path) 33 | 34 | if getattr(options, 'skip', None) and any(p.match(path) for p in options.skip): # noqa 35 | env.message('Skip code checking.') 36 | env.debug("Skipped") 37 | return env.stop() 38 | 39 | if env.options.get('debug'): 40 | from pylama.core import LOGGER, logging 41 | LOGGER.setLevel(logging.DEBUG) 42 | 43 | errors = check_path( 44 | path, options=options, code='\n'.join(env.curbuf) + '\n') 45 | 46 | env.debug("Find errors: ", len(errors)) 47 | sort_rules = env.var('g:pymode_lint_sort') 48 | 49 | def __sort(e): 50 | try: 51 | return sort_rules.index(e.get('type')) 52 | except ValueError: 53 | return 999 54 | 55 | if sort_rules: 56 | env.debug("Find sorting: ", sort_rules) 57 | errors = sorted(errors, key=__sort) 58 | 59 | for e in errors: 60 | e._info['bufnr'] = env.curbuf.number 61 | 62 | env.run('g:PymodeLocList.current().extend', [e._info for e in errors]) 63 | 64 | # pylama:ignore=W0212 65 | -------------------------------------------------------------------------------- /pymode/run.py: -------------------------------------------------------------------------------- 1 | """ Code runnning support. """ 2 | import sys 3 | from re import compile as re 4 | 5 | from ._compat import StringIO 6 | from .environment import env 7 | 8 | 9 | encoding = re(r'#[^\w]+coding:\s+utf.*$') 10 | 11 | 12 | def run_code(): 13 | """ Run python code in current buffer. 14 | 15 | :returns: None 16 | 17 | """ 18 | errors, err = [], '' 19 | line1, line2 = env.var('a:line1'), env.var('a:line2') 20 | lines = __prepare_lines(line1, line2) 21 | for ix in (0, 1): 22 | if encoding.match(lines[ix]): 23 | lines.pop(ix) 24 | 25 | context = dict( 26 | __name__='__main__', 27 | __file__=env.var('expand("%:p")'), 28 | input=env.user_input, 29 | raw_input=env.user_input) 30 | 31 | sys.stdout, stdout_ = StringIO(), sys.stdout 32 | sys.stderr, stderr_ = StringIO(), sys.stderr 33 | 34 | try: 35 | code = compile('\n'.join(lines) + '\n', env.curbuf.name, 'exec') 36 | sys.path.insert(0, env.curdir) 37 | exec(code, context) # noqa 38 | sys.path.pop(0) 39 | 40 | except SystemExit as e: 41 | if e.code: 42 | # A non-false code indicates abnormal termination. 43 | # A false code will be treated as a 44 | # successful run, and the error will be hidden from Vim 45 | env.error("Script exited with code %s" % e.code) 46 | return env.stop() 47 | 48 | except Exception: 49 | import traceback 50 | err = traceback.format_exc() 51 | 52 | else: 53 | err = sys.stderr.getvalue() 54 | 55 | output = sys.stdout.getvalue() 56 | output = env.prepare_value(output, dumps=False) 57 | sys.stdout, sys.stderr = stdout_, stderr_ 58 | 59 | errors += [er for er in err.splitlines() if er and "" not in er] 60 | 61 | env.let('l:traceback', errors[2:]) 62 | env.let('l:output', [s for s in output.split('\n')]) 63 | 64 | 65 | def __prepare_lines(line1, line2): 66 | 67 | lines = [l.rstrip() for l in env.lines[int(line1) - 1:int(line2)]] 68 | 69 | indent = 0 70 | for line in lines: 71 | if line: 72 | indent = len(line) - len(line.lstrip()) 73 | break 74 | 75 | if len(lines) == 1: 76 | lines.append('') 77 | return [l[indent:] for l in lines] 78 | -------------------------------------------------------------------------------- /pymode/utils.py: -------------------------------------------------------------------------------- 1 | """ Pymode utils. """ 2 | import os.path 3 | import sys 4 | import threading 5 | import warnings 6 | from contextlib import contextmanager 7 | 8 | import vim # noqa 9 | from ._compat import StringIO, PY2 10 | 11 | 12 | DEBUG = int(vim.eval('g:pymode_debug')) 13 | 14 | warnings.filterwarnings('ignore') 15 | 16 | 17 | @contextmanager 18 | def silence_stderr(): 19 | """ Redirect stderr. """ 20 | if DEBUG: 21 | yield 22 | 23 | else: 24 | with threading.Lock(): 25 | stderr = sys.stderr 26 | sys.stderr = StringIO() 27 | 28 | yield 29 | 30 | with threading.Lock(): 31 | sys.stderr = stderr 32 | 33 | 34 | def patch_paths(): 35 | """ Function description. """ 36 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'libs')) 37 | 38 | if PY2: 39 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'libs2')) 40 | else: 41 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'libs3')) 42 | -------------------------------------------------------------------------------- /pymode/virtualenv.py: -------------------------------------------------------------------------------- 1 | """ Support virtualenv in pymode. """ 2 | 3 | import os.path 4 | 5 | from .environment import env 6 | 7 | 8 | @env.catch_exceptions 9 | def enable_virtualenv(): 10 | """ Enable virtualenv for vim. 11 | 12 | :return bool: 13 | 14 | """ 15 | path = env.var('g:pymode_virtualenv_path') 16 | enabled = env.var('g:pymode_virtualenv_enabled') 17 | if path == enabled: 18 | env.message('Virtualenv %s already enabled.' % path) 19 | return env.stop() 20 | 21 | activate_this = os.path.join(os.path.join(path, 'bin'), 'activate_this.py') 22 | 23 | # Fix for windows 24 | if not os.path.exists(activate_this): 25 | activate_this = os.path.join( 26 | os.path.join(path, 'Scripts'), 'activate_this.py') 27 | 28 | f = open(activate_this) 29 | try: 30 | source = f.read() 31 | exec(compile( # noqa 32 | source, activate_this, 'exec'), dict(__file__=activate_this)) 33 | env.message('Activate virtualenv: ' + path) 34 | env.let('g:pymode_virtualenv_enabled', path) 35 | return True 36 | finally: 37 | f.close() 38 | -------------------------------------------------------------------------------- /syntax/pyrex.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: Pyrex 3 | " Maintainer: John Tyree 4 | " Last Change: 2012 Nov 06 5 | 6 | " For version 5.x: Clear all syntax items 7 | " For version 6.x: Quit when a syntax file was already loaded 8 | if version < 600 9 | syntax clear 10 | elseif exists("b:current_syntax") 11 | finish 12 | endif 13 | 14 | " Read the Python syntax to start with 15 | if version < 600 16 | so :p:h/python.vim 17 | else 18 | runtime! syntax/python.vim 19 | unlet b:current_syntax 20 | endif 21 | 22 | " Pyrex extentions 23 | syn keyword pyrexStatement nogil inline typedef ctypedef sizeof 24 | syn keyword pyrexType Py_ssize_t int long short float double char object void 25 | " Here we want slightly different behavior depending on whether we're declaring 26 | " variables or functions. c[p]def should work on the top level as a keyword, but 27 | " should ALSO work to identify functions and classes. 28 | syn match pyrexStatement "\" 29 | syn match pyrexStatement "\[^=]*(\@=" contains=pythonStatement,pyrexStatement,pythonFunction,pyrexType skipwhite 30 | syn keyword pyrexType signed unsigned 31 | syn keyword pyrexStructure struct union enum 32 | syn keyword pyrexInclude include cimport 33 | syn keyword pyrexAccess public private property readonly extern 34 | " If someome wants Python's built-ins highlighted probably he 35 | " also wants Pyrex's built-ins highlighted 36 | if exists("python_highlight_builtins") || exists("pyrex_highlight_builtins") 37 | syn keyword pyrexBuiltin NULL 38 | endif 39 | 40 | " This deletes "from" from the keywords and re-adds it as a 41 | " match with lower priority than pyrexForFrom 42 | syn clear pythonInclude 43 | syn keyword pythonInclude import 44 | syn match pythonInclude "\" 45 | 46 | " With "for[^:]*\zsfrom" VIM does not match "for" anymore, so 47 | " I used the slower "\@<=" form 48 | syn match pyrexForFrom "\(\[^:]*\)\@<=\" 49 | 50 | " Default highlighting 51 | if version >= 508 || !exists("did_pyrex_syntax_inits") 52 | if version < 508 53 | let did_pyrex_syntax_inits = 1 54 | command -nargs=+ HiLink hi link 55 | else 56 | command -nargs=+ HiLink hi def link 57 | endif 58 | HiLink pyrexStatement Statement 59 | HiLink pyrexType Type 60 | HiLink pyrexStructure Structure 61 | HiLink pyrexInclude PreCondit 62 | HiLink pyrexAccess pyrexStatement 63 | if exists("python_highlight_builtins") || exists("pyrex_highlight_builtins") 64 | HiLink pyrexBuiltin Function 65 | endif 66 | HiLink pyrexForFrom Statement 67 | 68 | delcommand HiLink 69 | endif 70 | 71 | let b:current_syntax = "pyrex" 72 | -------------------------------------------------------------------------------- /t/docs.vim: -------------------------------------------------------------------------------- 1 | source plugin/pymode.vim 2 | 3 | describe 'docs' 4 | before 5 | set filetype=python 6 | end 7 | 8 | after 9 | bd! 10 | bd! 11 | end 12 | 13 | it 'pymode show docs' 14 | Expect g:pymode_doc == 1 15 | put = 'def' 16 | normal GK 17 | wincmd p 18 | Expect bufname('%') == "__doc__" 19 | Expect getline(1) == 'Function definitions' 20 | Expect &filetype == 'rst' 21 | end 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /t/ftplugin.vim: -------------------------------------------------------------------------------- 1 | source plugin/pymode.vim 2 | 3 | describe 'pymode-ftplugin' 4 | 5 | before 6 | set filetype=python 7 | end 8 | 9 | after 10 | bd! 11 | end 12 | 13 | it 'pymode init' 14 | PymodePython import pymode 15 | end 16 | 17 | end 18 | 19 | -------------------------------------------------------------------------------- /t/indent.vim: -------------------------------------------------------------------------------- 1 | source plugin/pymode.vim 2 | 3 | describe 'indent' 4 | 5 | before 6 | set ft=python 7 | source after/indent/python.vim 8 | end 9 | 10 | after 11 | bd! 12 | end 13 | 14 | it 'pymode indent loaded' 15 | Expect g:pymode_indent == 1 16 | Expect &expandtab == 1 17 | Expect &shiftround == 1 18 | Expect &autoindent == 1 19 | Expect &indentexpr == 'pymode#indent#get_indent(v:lnum)' 20 | end 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /t/lint.vim: -------------------------------------------------------------------------------- 1 | source plugin/pymode.vim 2 | 3 | describe 'pymode check code' 4 | 5 | before 6 | set ft=python 7 | end 8 | 9 | after 10 | bd! 11 | end 12 | 13 | it 'pymode lint loaded' 14 | Expect g:pymode_lint == 1 15 | end 16 | 17 | it 'lint new' 18 | put =['# coding: utf-8', 'call_unknown_function()'] 19 | PymodeLint 20 | Expect getloclist(0) == [] 21 | end 22 | 23 | it 'lint code' 24 | e t/test.py 25 | PymodeLint 26 | Expect getloclist(0) == [{'lnum': 6, 'bufnr': 1, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': 0, 'type': 'E', 'pattern': '', 'text': 'W0612 local variable "unused" is assigned to but never used [pyflakes]'}, {'lnum': 8, 'bufnr': 1, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': 0, 'type': 'E', 'pattern': '', 'text': 'E0602 undefined name "unknown" [pyflakes]'}] 27 | end 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /t/plugin.vim: -------------------------------------------------------------------------------- 1 | describe 'pymode-plugin' 2 | 3 | before 4 | source plugin/pymode.vim 5 | set filetype=python 6 | end 7 | 8 | after 9 | bd! 10 | end 11 | 12 | it 'pymode options' 13 | Expect g:pymode == 1 14 | Expect g:pymode_python == 'python' 15 | Expect g:pymode_paths == [] 16 | Expect g:pymode_virtualenv == 1 17 | Expect g:pymode_run == 1 18 | Expect g:pymode_lint == 1 19 | Expect g:pymode_breakpoint == 1 20 | Expect g:pymode_doc == 1 21 | Expect g:pymode_indent == 1 22 | end 23 | 24 | it 'pymode interpreter' 25 | PymodePython import vim 26 | PymodePython vim.current.buffer.append('test success') 27 | Expect getline('$') == 'test success' 28 | end 29 | 30 | it 'pymode save' 31 | Expect expand('%') == '' 32 | Expect pymode#save() == 0 33 | end 34 | 35 | end 36 | 37 | 38 | describe 'pymode-python-disable' 39 | before 40 | let g:pymode_python = 'disable' 41 | source plugin/pymode.vim 42 | set filetype=python 43 | end 44 | 45 | after 46 | bd! 47 | end 48 | 49 | it 'pymode disable python' 50 | Expect g:pymode_doc == 0 51 | Expect g:pymode_lint == 0 52 | Expect g:pymode_path == 0 53 | Expect g:pymode_rope == 0 54 | Expect g:pymode_run == 0 55 | Expect g:pymode_virtualenv == 0 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /t/rope.vim: -------------------------------------------------------------------------------- 1 | let g:pymode_rope_completion_bind = 'X' 2 | let g:pymode_rope_autoimport = 0 3 | let g:pymode_debug = 1 4 | let g:pymode_rope_lookup_project = 0 5 | 6 | source plugin/pymode.vim 7 | 8 | describe 'pymode-plugin' 9 | 10 | before 11 | set filetype=python 12 | end 13 | 14 | after 15 | bd! 16 | bd! 17 | end 18 | 19 | it 'pymode rope auto open project in current working directory' 20 | 21 | if $TRAVIS != "" 22 | SKIP 'Travis fails on this test' 23 | endif 24 | 25 | let project_path = getcwd() . '/.ropeproject' 26 | Expect isdirectory(project_path) == 0 27 | normal oimporX 28 | Expect getline('.') == 'import' 29 | Expect g:pymode_rope_current == getcwd() . '/' 30 | Expect g:pymode_rope_current . '.ropeproject' == project_path 31 | Expect isdirectory(project_path) == 1 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /t/syntax.vim: -------------------------------------------------------------------------------- 1 | describe 'pymode-syntax' 2 | 3 | before 4 | syntax on 5 | set filetype=python 6 | end 7 | 8 | after 9 | bd! 10 | end 11 | 12 | it 'pymode-syntax options' 13 | Expect g:pymode_syntax == 1 14 | Expect g:pymode_syntax_all == 1 15 | Expect g:pymode_syntax_print_as_function == 0 16 | Expect g:pymode_syntax_highlight_equal_operator == 1 17 | Expect g:pymode_syntax_highlight_stars_operator == 1 18 | Expect g:pymode_syntax_highlight_self == 1 19 | Expect g:pymode_syntax_indent_errors == 1 20 | Expect g:pymode_syntax_space_errors == 1 21 | Expect g:pymode_syntax_string_formatting == 1 22 | Expect g:pymode_syntax_string_format == 1 23 | Expect g:pymode_syntax_string_templates == 1 24 | Expect g:pymode_syntax_doctests == 1 25 | Expect g:pymode_syntax_builtin_objs == 1 26 | Expect g:pymode_syntax_builtin_types == 1 27 | Expect g:pymode_syntax_builtin_funcs == 1 28 | Expect g:pymode_syntax_highlight_exceptions == 1 29 | Expect g:pymode_syntax_slow_sync == 1 30 | end 31 | 32 | end 33 | 34 | -------------------------------------------------------------------------------- /t/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | 5 | def main(): 6 | unused = 1 7 | 8 | unknown() 9 | -------------------------------------------------------------------------------- /t/trouble.vim: -------------------------------------------------------------------------------- 1 | source plugin/pymode.vim 2 | 3 | describe 'pymode troubleshooting' 4 | 5 | after 6 | bd! 7 | bd! 8 | end 9 | 10 | it 'pymode troubleshooting' 11 | call pymode#troubleshooting#test() 12 | Expect getline(1) == 'Pymode diagnostic' 13 | end 14 | 15 | end 16 | --------------------------------------------------------------------------------