├── .gitignore ├── .no-sublime-package ├── Context.sublime-menu ├── Default (Linux).sublime-mousemap ├── Default (OSX).sublime-mousemap ├── Default (Windows).sublime-mousemap ├── LICENSE.txt ├── Main.sublime-menu ├── README.markdown ├── SublimePython.sublime-commands ├── SublimePython.sublime-settings ├── __init__.py ├── gutter_mark_themes ├── alpha-illegal.png ├── alpha-violation.png ├── alpha-warning.png ├── bright-illegal.png ├── bright-violation.png ├── bright-warning.png ├── dark-illegal.png ├── dark-violation.png ├── dark-warning.png ├── hard-illegal.png ├── hard-violation.png ├── hard-warning.png ├── simple-illegal.png ├── simple-violation.png └── simple-warning.png ├── messages.json ├── messages ├── 1.0.0.txt ├── 1.0.3.txt └── install.txt ├── pep8.py ├── pyflakes ├── __init__.py ├── api.py ├── checker.py ├── messages.py └── reporter.py ├── server ├── decorators.py ├── lib │ ├── python2 │ │ └── 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 │ ├── python3 │ │ └── 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 │ └── python_all │ │ └── jedi │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── _compatibility.py │ │ ├── api │ │ ├── __init__.py │ │ ├── classes.py │ │ ├── helpers.py │ │ ├── interpreter.py │ │ ├── keywords.py │ │ ├── replstartup.py │ │ └── usages.py │ │ ├── cache.py │ │ ├── common.py │ │ ├── debug.py │ │ ├── evaluate │ │ ├── __init__.py │ │ ├── analysis.py │ │ ├── cache.py │ │ ├── compiled │ │ │ ├── __init__.py │ │ │ ├── fake.py │ │ │ └── fake │ │ │ │ ├── _functools.pym │ │ │ │ ├── _sqlite3.pym │ │ │ │ ├── _sre.pym │ │ │ │ ├── _weakref.pym │ │ │ │ ├── builtins.pym │ │ │ │ ├── datetime.pym │ │ │ │ ├── io.pym │ │ │ │ └── posix.pym │ │ ├── docstrings.py │ │ ├── dynamic.py │ │ ├── finder.py │ │ ├── flow_analysis.py │ │ ├── helpers.py │ │ ├── imports.py │ │ ├── iterable.py │ │ ├── param.py │ │ ├── precedence.py │ │ ├── recursion.py │ │ ├── representation.py │ │ ├── stdlib.py │ │ └── sys_path.py │ │ ├── parser │ │ ├── __init__.py │ │ ├── fast.py │ │ ├── grammar2.7.txt │ │ ├── grammar3.4.txt │ │ ├── pgen2 │ │ │ ├── __init__.py │ │ │ ├── grammar.py │ │ │ ├── parse.py │ │ │ └── pgen.py │ │ ├── token.py │ │ ├── tokenize.py │ │ ├── tree.py │ │ └── user_context.py │ │ ├── refactoring.py │ │ ├── settings.py │ │ └── utils.py ├── linter.py └── server.py ├── sublime_python.py ├── sublime_python_colors.py ├── sublime_python_commands.py ├── sublime_python_errors.py ├── sublime_python_linting.py └── sublime_python_refactorings.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sublime-project 3 | *.sublime-workspace 4 | *.pyc 5 | -------------------------------------------------------------------------------- /.no-sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/.no-sublime-package -------------------------------------------------------------------------------- /Context.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { "command": "python_get_documentation", "caption": "Get Documentation" }, 3 | { "command": "python_goto_definition", "caption": "Go to Definition"} 4 | ] -------------------------------------------------------------------------------- /Default (Linux).sublime-mousemap: -------------------------------------------------------------------------------- 1 | [ 2 | { "button": "button1", "modifiers": ["alt"], "command": "python_goto_definition", "press_command": "drag_select" } 3 | ] 4 | -------------------------------------------------------------------------------- /Default (OSX).sublime-mousemap: -------------------------------------------------------------------------------- 1 | [ 2 | { "button": "button1", "modifiers": ["ctrl"], "command": "python_goto_definition", "press_command": "drag_select" } 3 | ] 4 | -------------------------------------------------------------------------------- /Default (Windows).sublime-mousemap: -------------------------------------------------------------------------------- 1 | [ 2 | { "button": "button1", "modifiers": ["alt"], "command": "python_goto_definition", "press_command": "drag_select" } 3 | ] 4 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | 4 | "id": "preferences", 5 | "children": 6 | [ 7 | { 8 | "caption": "Package Settings", 9 | "mnemonic": "P", 10 | "id": "package-settings", 11 | "children": 12 | [ 13 | { 14 | "caption": "SublimePythonIDE", 15 | "children": 16 | [ 17 | { 18 | "command": "open_file", 19 | "args": {"file": "${packages}/SublimePythonIDE/SublimePython.sublime-settings"}, 20 | "caption": "Settings - Default" 21 | }, 22 | { "caption": "-" }, 23 | { 24 | "command": "open_file", 25 | "args": {"file": "${packages}/User/SublimePython.sublime-settings"}, 26 | "caption": "Settings – User" 27 | }, 28 | ] 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | 35 | ] -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | **SublimePythonIDE** 2 | =========================== 3 | This plugin adds Python completions and some IDE-like functions to Sublime Text 3, through the use of the Rope library. 4 | It is a complete rewrite of SublimeRope for ST2. It should be a lot faster and easier to use than SublimeRope was. 5 | 6 | In contrast to SublimeRope, it does use the built in Python only for UI-related functions, the completions and refactorings 7 | are calculated using the exact same python interpreter you use for your project (e.g. the one in your virtualenv). 8 | This eliminates a lot of small and big problems that SublimeRope had, e.g., not recognizing dict comprehensions because Python2.6 is used in ST2, or not recognizing some of your libraries because you did not configure all the paths etc.. 9 | Everything your projects interpreter sees, should be visible to SublimePython -> easier configuration. 10 | 11 | I also added a lot caching throughout the underlying Rope library which improved completion performance by several orders of magnitude. I hope no functionality breaks because of this ;-) 12 | 13 | 14 | Configuration 15 | ------------- 16 | 17 | ## Python location 18 | 19 | The only necessary configuration is pointing SublimePythonIDE at the correct Python interpreter to use. 20 | There are four mechanisms for detecting Python that are used in the following order: 21 | 22 | - Checking the option "python_interpreter" in project settings (see below) 23 | - Auto-detecting a virtual environment (in "venv" or $WORKON_HOME for virtualenvwrapper) 24 | - Reading a #! (shebang) line in the active file 25 | - Auto-detecting the system Python from $PATH 26 | 27 | The option "python_interpreter" can be set in the projects settings (Project->Edit Project). Example: 28 | 29 | { 30 | "folders": [ 31 | { 32 | "path": "XYZ" 33 | }, 34 | { 35 | "path": "ABC" 36 | } 37 | ], 38 | "settings": { 39 | "python_interpreter": "/path/to/some/virtualenv/bin/python" 40 | } 41 | } 42 | 43 | This is also the way to select a virtualenv (point it to the interpreter in the venv) and thus get the completions/definitions for you project working. 44 | 45 | To suppress the "Could not find Python dialog", save the following setting: 46 | 47 | "suppress_python_not_found_error": false, 48 | 49 | 50 | ## Imports location 51 | 52 | SublimePythonIDE will also look up imports relative to the project root directory (the top directory of your project). 53 | 54 | In cases where the project directory is outside of your root python module, you may optionally set a custom source root directory in the project settings: 55 | 56 | { 57 | "folders": [ 58 | { 59 | "path": "XYZ" 60 | }, 61 | ], 62 | "settings": { 63 | "src_root": "XYZ/THE_ACTUAL_SRC" 64 | "python_interpreter": "/path/to/some/virtualenv/bin/python", 65 | } 66 | } 67 | 68 | See Packages/SublimePythonIDE/SublimePython.sublime-settings for other options. As with all ST packages, copy this file into your Packages/User folder and editing the copy there. 69 | 70 | Copyright (C) 2013 Julian Eberius 71 | 72 | License: 73 | -------- 74 | 75 | This program is free software; you can redistribute it and/or modify 76 | it under the terms of the GNU General Public License as published by 77 | the Free Software Foundation; either version 2 of the License, or 78 | (at your option) any later version. 79 | 80 | This program is distributed in the hope that it will be useful, 81 | but WITHOUT ANY WARRANTY; without even the implied warranty of 82 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 83 | GNU General Public License for more details. 84 | 85 | You should have received a copy of the GNU General Public License along 86 | with this program; if not, write to the Free Software Foundation, Inc., 87 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 88 | 89 | Have a look at "LICENSE.txt" file for more information. 90 | 91 | EXTERNAL LICENSES 92 | ----------------- 93 | This project uses code from other open source projects (Rope) 94 | which may include licenses of their own. 95 | -------------------------------------------------------------------------------- /SublimePython.sublime-commands: -------------------------------------------------------------------------------- 1 | 2 | [ 3 | { 4 | "caption": "Python: Go to definition", 5 | "command": "python_goto_definition" 6 | }, 7 | { 8 | "caption": "Python: Get back", 9 | "command": "python_go_back" 10 | }, 11 | { 12 | "caption": "Python: Get documentation", 13 | "command": "python_get_documentation" 14 | }, 15 | { 16 | "caption": "Python: Enable Pep8 Linting On View", 17 | "command": "python_enable_pep8" 18 | }, 19 | { 20 | "caption": "Python: Disable Pep8 Linting On View", 21 | "command": "python_disable_pep8" 22 | }, 23 | { 24 | "caption": "Python Refactor: Rename", 25 | "command": "python_refactor_rename" 26 | }, 27 | { 28 | "caption": "Python Refactor: Extract Method", 29 | "command": "python_extract_method" 30 | }, 31 | { 32 | "caption": "Python Refactor: Organize Imports", 33 | "command": "python_organize_imports" 34 | }, 35 | ] 36 | -------------------------------------------------------------------------------- /SublimePython.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // leave empty string to use default system interpreter 3 | // e.g. /usr/local/bin/python 4 | // or "C:\\Python27\\python.exe" 5 | // if you use virtualenvs, then set the absolute path to the virtualenv's 6 | // python in your project settings (Project->Edit Project) as in: 7 | // 8 | // { 9 | // "folders": ... 10 | // "settings": 11 | // { 12 | // "python_interpreter": "/Users/USER/.virtualenvs/PROJECT/bin/python" 13 | // } 14 | // } 15 | "python_interpreter": "", 16 | 17 | // make python_open_documentation command output in a view or in the output 18 | // panel if false 19 | "open_pydoc_in_view": false, 20 | 21 | // when a doc view is created it will be placed in the active view group 22 | // if false and only one group exist then a new group will be created 23 | "create_view_in_same_group": false, 24 | 25 | // Linter settings 26 | "python_linting": true, 27 | "python_linter_mark_style": "outline", // "none" or "outline" 28 | "python_linter_gutter_marks": true, 29 | "python_linter_gutter_marks_theme": "simple", // see folder gutter_mark_themes 30 | 31 | // linting colors 32 | "warning_color":"EDBA00", 33 | "error_color":"DA2000", 34 | 35 | "pep8": true, 36 | // disable certain pep8 errors 37 | // overview of possible error codes at http://pep8.readthedocs.org/en/latest/intro.html#error-codes 38 | "pep8_ignore": [], 39 | "pep8_max_line_length": 79, 40 | "pyflakes_ignore": [], 41 | 42 | // If the organize imports refactoring should be called on every file save 43 | "python_organize_imports_on_save": false 44 | } 45 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/__init__.py -------------------------------------------------------------------------------- /gutter_mark_themes/alpha-illegal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/alpha-illegal.png -------------------------------------------------------------------------------- /gutter_mark_themes/alpha-violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/alpha-violation.png -------------------------------------------------------------------------------- /gutter_mark_themes/alpha-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/alpha-warning.png -------------------------------------------------------------------------------- /gutter_mark_themes/bright-illegal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/bright-illegal.png -------------------------------------------------------------------------------- /gutter_mark_themes/bright-violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/bright-violation.png -------------------------------------------------------------------------------- /gutter_mark_themes/bright-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/bright-warning.png -------------------------------------------------------------------------------- /gutter_mark_themes/dark-illegal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/dark-illegal.png -------------------------------------------------------------------------------- /gutter_mark_themes/dark-violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/dark-violation.png -------------------------------------------------------------------------------- /gutter_mark_themes/dark-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/dark-warning.png -------------------------------------------------------------------------------- /gutter_mark_themes/hard-illegal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/hard-illegal.png -------------------------------------------------------------------------------- /gutter_mark_themes/hard-violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/hard-violation.png -------------------------------------------------------------------------------- /gutter_mark_themes/hard-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/hard-warning.png -------------------------------------------------------------------------------- /gutter_mark_themes/simple-illegal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/simple-illegal.png -------------------------------------------------------------------------------- /gutter_mark_themes/simple-violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/simple-violation.png -------------------------------------------------------------------------------- /gutter_mark_themes/simple-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/gutter_mark_themes/simple-warning.png -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.txt", 3 | "1.0.3": "messages/1.0.3.txt" 4 | } 5 | -------------------------------------------------------------------------------- /messages/1.0.0.txt: -------------------------------------------------------------------------------- 1 | SublimePythonIDE was just updated to a major new version, with many architectural changes and a new autocompletion engine (Jedi). 2 | It is not unlikely that some things will break, so feel free to report at https://github.com/JulianEberius/SublimePythonIDE/issues -------------------------------------------------------------------------------- /messages/1.0.3.txt: -------------------------------------------------------------------------------- 1 | SublimePythonIDE was just updated to a new minor version. The detection of the Python interpreter to use was improved. It now uses four different methods in the following order (see README or Github for details): 2 | 3 | - Check for the option "python_interpreter" in project settings 4 | - Try to auto-detect virtual environments (in "venv" or $WORKON_HOME for virtualenvwrapper) 5 | - Read a #! (shebang) line in the active file (NEW) 6 | - Try to auto-detect the system Python from $PATH 7 | 8 | In addition, the bundled libraries were updated and open issues were fixed. 9 | Feel free to report any new issues at https://github.com/JulianEberius/SublimePythonIDE/issues -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulianEberius/SublimePythonIDE/d70e40abc0c9f347af3204c7b910e0d6bfd6e459/messages/install.txt -------------------------------------------------------------------------------- /pyflakes/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.0.0' 2 | -------------------------------------------------------------------------------- /pyflakes/messages.py: -------------------------------------------------------------------------------- 1 | """ 2 | Provide the class Message and its subclasses. 3 | """ 4 | 5 | 6 | class Message(object): 7 | message = '' 8 | message_args = () 9 | 10 | def __init__(self, filename, loc): 11 | self.filename = filename 12 | self.lineno = loc.lineno 13 | self.col = getattr(loc, 'col_offset', 0) 14 | 15 | def __str__(self): 16 | return '%s:%s: %s' % (self.filename, self.lineno, 17 | self.message % self.message_args) 18 | 19 | 20 | class UnusedImport(Message): 21 | message = '%r imported but unused' 22 | 23 | def __init__(self, filename, loc, name): 24 | Message.__init__(self, filename, loc) 25 | self.message_args = (name,) 26 | 27 | 28 | class RedefinedWhileUnused(Message): 29 | message = 'redefinition of unused %r from line %r' 30 | 31 | def __init__(self, filename, loc, name, orig_loc): 32 | Message.__init__(self, filename, loc) 33 | self.message_args = (name, orig_loc.lineno) 34 | 35 | 36 | class RedefinedInListComp(Message): 37 | message = 'list comprehension redefines %r from line %r' 38 | 39 | def __init__(self, filename, loc, name, orig_loc): 40 | Message.__init__(self, filename, loc) 41 | self.message_args = (name, orig_loc.lineno) 42 | 43 | 44 | class ImportShadowedByLoopVar(Message): 45 | message = 'import %r from line %r shadowed by loop variable' 46 | 47 | def __init__(self, filename, loc, name, orig_loc): 48 | Message.__init__(self, filename, loc) 49 | self.message_args = (name, orig_loc.lineno) 50 | 51 | 52 | class ImportStarUsed(Message): 53 | message = "'from %s import *' used; unable to detect undefined names" 54 | 55 | def __init__(self, filename, loc, modname): 56 | Message.__init__(self, filename, loc) 57 | self.message_args = (modname,) 58 | 59 | 60 | class UndefinedName(Message): 61 | message = 'undefined name %r' 62 | 63 | def __init__(self, filename, loc, name): 64 | Message.__init__(self, filename, loc) 65 | self.message_args = (name,) 66 | 67 | 68 | class DoctestSyntaxError(Message): 69 | message = 'syntax error in doctest' 70 | 71 | def __init__(self, filename, loc, position=None): 72 | Message.__init__(self, filename, loc) 73 | if position: 74 | (self.lineno, self.col) = position 75 | self.message_args = () 76 | 77 | 78 | class UndefinedExport(Message): 79 | message = 'undefined name %r in __all__' 80 | 81 | def __init__(self, filename, loc, name): 82 | Message.__init__(self, filename, loc) 83 | self.message_args = (name,) 84 | 85 | 86 | class UndefinedLocal(Message): 87 | message = ('local variable %r (defined in enclosing scope on line %r) ' 88 | 'referenced before assignment') 89 | 90 | def __init__(self, filename, loc, name, orig_loc): 91 | Message.__init__(self, filename, loc) 92 | self.message_args = (name, orig_loc.lineno) 93 | 94 | 95 | class DuplicateArgument(Message): 96 | message = 'duplicate argument %r in function definition' 97 | 98 | def __init__(self, filename, loc, name): 99 | Message.__init__(self, filename, loc) 100 | self.message_args = (name,) 101 | 102 | 103 | class LateFutureImport(Message): 104 | message = 'future import(s) %r after other statements' 105 | 106 | def __init__(self, filename, loc, names): 107 | Message.__init__(self, filename, loc) 108 | self.message_args = (names,) 109 | 110 | 111 | class UnusedVariable(Message): 112 | """ 113 | Indicates that a variable has been explicity assigned to but not actually 114 | used. 115 | """ 116 | message = 'local variable %r is assigned to but never used' 117 | 118 | def __init__(self, filename, loc, names): 119 | Message.__init__(self, filename, loc) 120 | self.message_args = (names,) 121 | 122 | 123 | class ReturnWithArgsInsideGenerator(Message): 124 | """ 125 | Indicates a return statement with arguments inside a generator. 126 | """ 127 | message = '\'return\' with argument inside generator' 128 | 129 | 130 | class ReturnOutsideFunction(Message): 131 | """ 132 | Indicates a return statement outside of a function/method. 133 | """ 134 | message = '\'return\' outside function' 135 | -------------------------------------------------------------------------------- /pyflakes/reporter.py: -------------------------------------------------------------------------------- 1 | """ 2 | Provide the Reporter class. 3 | """ 4 | 5 | import re 6 | import sys 7 | 8 | 9 | class Reporter(object): 10 | """ 11 | Formats the results of pyflakes checks to users. 12 | """ 13 | 14 | def __init__(self, warningStream, errorStream): 15 | """ 16 | Construct a L{Reporter}. 17 | 18 | @param warningStream: A file-like object where warnings will be 19 | written to. The stream's C{write} method must accept unicode. 20 | C{sys.stdout} is a good value. 21 | @param errorStream: A file-like object where error output will be 22 | written to. The stream's C{write} method must accept unicode. 23 | C{sys.stderr} is a good value. 24 | """ 25 | self._stdout = warningStream 26 | self._stderr = errorStream 27 | 28 | def unexpectedError(self, filename, msg): 29 | """ 30 | An unexpected error occurred trying to process C{filename}. 31 | 32 | @param filename: The path to a file that we could not process. 33 | @ptype filename: C{unicode} 34 | @param msg: A message explaining the problem. 35 | @ptype msg: C{unicode} 36 | """ 37 | self._stderr.write("%s: %s\n" % (filename, msg)) 38 | 39 | def syntaxError(self, filename, msg, lineno, offset, text): 40 | """ 41 | There was a syntax errror in C{filename}. 42 | 43 | @param filename: The path to the file with the syntax error. 44 | @ptype filename: C{unicode} 45 | @param msg: An explanation of the syntax error. 46 | @ptype msg: C{unicode} 47 | @param lineno: The line number where the syntax error occurred. 48 | @ptype lineno: C{int} 49 | @param offset: The column on which the syntax error occurred, or None. 50 | @ptype offset: C{int} 51 | @param text: The source code containing the syntax error. 52 | @ptype text: C{unicode} 53 | """ 54 | line = text.splitlines()[-1] 55 | if offset is not None: 56 | offset = offset - (len(text) - len(line)) 57 | self._stderr.write('%s:%d:%d: %s\n' % 58 | (filename, lineno, offset + 1, msg)) 59 | else: 60 | self._stderr.write('%s:%d: %s\n' % (filename, lineno, msg)) 61 | self._stderr.write(line) 62 | self._stderr.write('\n') 63 | if offset is not None: 64 | self._stderr.write(re.sub(r'\S', ' ', line[:offset]) + 65 | "^\n") 66 | 67 | def flake(self, message): 68 | """ 69 | pyflakes found something wrong with the code. 70 | 71 | @param: A L{pyflakes.messages.Message}. 72 | """ 73 | self._stdout.write(str(message)) 74 | self._stdout.write('\n') 75 | 76 | 77 | def _makeDefaultReporter(): 78 | """ 79 | Make a reporter that can be used when no reporter is specified. 80 | """ 81 | return Reporter(sys.stdout, sys.stderr) 82 | -------------------------------------------------------------------------------- /server/decorators.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (c) 2013 Oscar Campos 3 | # See LICENSE for more details 4 | 5 | """ 6 | .. module:: decorators 7 | :platform: Unix, Windows 8 | :synopsis: Decorators for SublimePython plugin 9 | 10 | .. moduleauthor:: Oscar Campos 11 | 12 | """ 13 | 14 | import os 15 | import functools 16 | 17 | 18 | def debug(f): 19 | 20 | @functools.wrap(f) 21 | def wrapped(*args, **kwargs): 22 | try: 23 | return f(*args, **kwargs) 24 | except: 25 | import traceback 26 | with open(os.path.expanduser("~/trace"), "w") as fl: 27 | traceback.print_exc(file=fl) 28 | return wrapped 29 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/rope/base/ast.py: -------------------------------------------------------------------------------- 1 | import _ast 2 | from _ast import * 3 | 4 | from rope.base import fscommands, utils 5 | 6 | 7 | @utils.cached(10) 8 | def parse(source, filename=''): 9 | # NOTE: the raw string should be given to `compile` function 10 | if isinstance(source, unicode): 11 | source = fscommands.unicode_to_file_data(source) 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, filename, 'exec', _ast.PyCF_ONLY_AST) 18 | except (TypeError, ValueError), 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 | if isinstance(node, _ast.ImportFrom) and node.module is None: 32 | # In python < 2.7 ``node.module == ''`` for relative imports 33 | # but for python 2.7 it is None. Generalizing it to ''. 34 | node.module = '' 35 | return method(node) 36 | for child in get_child_nodes(node): 37 | walk(child, walker) 38 | 39 | 40 | def get_child_nodes(node): 41 | if isinstance(node, _ast.Module): 42 | return node.body 43 | result = [] 44 | if node._fields is not None: 45 | for name in node._fields: 46 | child = getattr(node, name) 47 | if isinstance(child, list): 48 | for entry in child: 49 | if isinstance(entry, _ast.AST): 50 | result.append(entry) 51 | if isinstance(child, _ast.AST): 52 | result.append(child) 53 | return result 54 | 55 | 56 | def call_for_nodes(node, callback, recursive=False): 57 | """If callback returns `True` the child nodes are skipped""" 58 | result = callback(node) 59 | if recursive and not result: 60 | for child in get_child_nodes(node): 61 | call_for_nodes(child, callback, recursive) 62 | 63 | 64 | def get_children(node): 65 | result = [] 66 | if node._fields is not None: 67 | for name in node._fields: 68 | if name in ['lineno', 'col_offset']: 69 | continue 70 | child = getattr(node, name) 71 | result.append(child) 72 | return result 73 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/rope/base/utils.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | from functools import partial 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 | def cached(count): 56 | """A caching decorator based on parameter objects""" 57 | def decorator(func): 58 | return _Cached(func, count) 59 | return decorator 60 | 61 | class _Cached(object): 62 | 63 | def __init__(self, func, count): 64 | self.func = func 65 | self.cache = [] 66 | self.count = count 67 | 68 | def __call__(self, *args, **kwds): 69 | key = (args, kwds) 70 | for cached_key, cached_result in self.cache: 71 | if cached_key == key: 72 | return cached_result 73 | result = self.func(*args, **kwds) 74 | self.cache.append((key, result)) 75 | if len(self.cache) > self.count: 76 | del self.cache[0] 77 | return result 78 | 79 | class memoize(object): 80 | """cache the return value of a method 81 | 82 | This class is meant to be used as a decorator of methods. The return value 83 | from a given method invocation will be cached on the instance whose method 84 | was invoked. All arguments passed to a method decorated with memoize must 85 | be hashable. 86 | 87 | If a memoized method is invoked directly on its class the result will not 88 | be cached. Instead the method will be invoked like a static method: 89 | class Obj(object): 90 | @memoize 91 | def add_to(self, arg): 92 | return self + arg 93 | Obj.add_to(1) # not enough arguments 94 | Obj.add_to(1, 2) # returns 3, result is not cached 95 | """ 96 | def __init__(self, func): 97 | self.func = func 98 | def __get__(self, obj, objtype=None): 99 | if obj is None: 100 | return self.func 101 | return partial(self, obj) 102 | def __call__(self, *args, **kw): 103 | obj = args[0] 104 | try: 105 | cache = obj.__cache 106 | except AttributeError: 107 | cache = obj.__cache = {} 108 | key = (self.func, args[1:], frozenset(kw.items())) 109 | try: 110 | res = cache[key] 111 | except KeyError: 112 | res = cache[key] = self.func(*args, **kw) 113 | return res 114 | 115 | def lazyprop(fn): 116 | attr_name = '_lazy_' + fn.__name__ 117 | @property 118 | def _lazyprop(self): 119 | if not hasattr(self, attr_name): 120 | setattr(self, attr_name, fn(self)) 121 | return getattr(self, attr_name) 122 | return _lazyprop 123 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/rope/contrib/findit.py: -------------------------------------------------------------------------------- 1 | import rope.base.codeanalyze 2 | import rope.base.evaluate 3 | import rope.base.pyobjects 4 | from rope.base import taskhandle, exceptions, worder 5 | from rope.contrib import fixsyntax 6 | from rope.refactor import occurrences 7 | 8 | 9 | def find_occurrences(project, resource, offset, unsure=False, resources=None, 10 | in_hierarchy=False, task_handle=taskhandle.NullTaskHandle()): 11 | """Return a list of `Location`\s 12 | 13 | If `unsure` is `True`, possible matches are returned, too. You 14 | can use `Location.unsure` to see which are unsure occurrences. 15 | `resources` can be a list of `rope.base.resource.File`\s that 16 | should be searched for occurrences; if `None` all python files 17 | in the project are searched. 18 | 19 | """ 20 | name = worder.get_name_at(resource, offset) 21 | this_pymodule = project.pycore.resource_to_pyobject(resource) 22 | primary, pyname = rope.base.evaluate.eval_location2( 23 | this_pymodule, offset) 24 | def is_match(occurrence): 25 | return unsure 26 | finder = occurrences.create_finder( 27 | project.pycore, name, pyname, unsure=is_match, 28 | in_hierarchy=in_hierarchy, instance=primary) 29 | if resources is None: 30 | resources = project.pycore.get_python_files() 31 | job_set = task_handle.create_jobset('Finding Occurrences', 32 | count=len(resources)) 33 | return _find_locations(finder, resources, job_set) 34 | 35 | 36 | def find_implementations(project, resource, offset, resources=None, 37 | task_handle=taskhandle.NullTaskHandle()): 38 | """Find the places a given method is overridden. 39 | 40 | Finds the places a method is implemented. Returns a list of 41 | `Location`\s. 42 | """ 43 | name = worder.get_name_at(resource, offset) 44 | this_pymodule = project.pycore.resource_to_pyobject(resource) 45 | pyname = rope.base.evaluate.eval_location(this_pymodule, offset) 46 | if pyname is not None: 47 | pyobject = pyname.get_object() 48 | if not isinstance(pyobject, rope.base.pyobjects.PyFunction) or \ 49 | pyobject.get_kind() != 'method': 50 | raise exceptions.BadIdentifierError('Not a method!') 51 | else: 52 | raise exceptions.BadIdentifierError('Cannot resolve the identifier!') 53 | def is_defined(occurrence): 54 | if not occurrence.is_defined(): 55 | return False 56 | def not_self(occurrence): 57 | if occurrence.get_pyname().get_object() == pyname.get_object(): 58 | return False 59 | filters = [is_defined, not_self, 60 | occurrences.InHierarchyFilter(pyname, True)] 61 | finder = occurrences.Finder(project.pycore, name, filters=filters) 62 | if resources is None: 63 | resources = project.pycore.get_python_files() 64 | job_set = task_handle.create_jobset('Finding Implementations', 65 | count=len(resources)) 66 | return _find_locations(finder, resources, job_set) 67 | 68 | 69 | def find_definition(project, code, offset, resource=None, maxfixes=1): 70 | """Return the definition location of the python name at `offset` 71 | 72 | A `Location` object is returned if the definition location can be 73 | determined, otherwise ``None`` is returned. 74 | """ 75 | fixer = fixsyntax.FixSyntax(project.pycore, code, resource, maxfixes) 76 | main_module = fixer.get_pymodule() 77 | pyname = fixer.pyname_at(offset) 78 | if pyname is not None: 79 | module, lineno = pyname.get_definition_location() 80 | name = rope.base.worder.Worder(code).get_word_at(offset) 81 | if lineno is not None: 82 | start = module.lines.get_line_start(lineno) 83 | def check_offset(occurrence): 84 | if occurrence.offset < start: 85 | return False 86 | pyname_filter = occurrences.PyNameFilter(pyname) 87 | finder = occurrences.Finder(project.pycore, name, 88 | [check_offset, pyname_filter]) 89 | for occurrence in finder.find_occurrences(pymodule=module): 90 | return Location(occurrence) 91 | 92 | 93 | class Location(object): 94 | 95 | def __init__(self, occurrence): 96 | self.resource = occurrence.resource 97 | self.region = occurrence.get_word_range() 98 | self.offset = self.region[0] 99 | self.unsure = occurrence.is_unsure() 100 | self.lineno = occurrence.lineno 101 | 102 | 103 | def _find_locations(finder, resources, job_set): 104 | result = [] 105 | for resource in resources: 106 | job_set.started_job(resource.path) 107 | for occurrence in finder.find_occurrences(resource): 108 | result.append(Location(occurrence)) 109 | job_set.finished_job() 110 | return result 111 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/rope/refactor/introduce_parameter.py: -------------------------------------------------------------------------------- 1 | import rope.base.change 2 | from rope.base import exceptions, evaluate, worder, codeanalyze 3 | from rope.refactor import functionutils, sourceutils, occurrences 4 | 5 | 6 | class IntroduceParameter(object): 7 | """Introduce parameter refactoring 8 | 9 | This refactoring adds a new parameter to a function and replaces 10 | references to an expression in it with the new parameter. 11 | 12 | The parameter finding part is different from finding similar 13 | pieces in extract refactorings. In this refactoring parameters 14 | are found based on the object they reference to. For instance 15 | in:: 16 | 17 | class A(object): 18 | var = None 19 | 20 | class B(object): 21 | a = A() 22 | 23 | b = B() 24 | a = b.a 25 | 26 | def f(a): 27 | x = b.a.var + a.var 28 | 29 | using this refactoring on ``a.var`` with ``p`` as the new 30 | parameter name, will result in:: 31 | 32 | def f(p=a.var): 33 | x = p + p 34 | 35 | """ 36 | 37 | def __init__(self, project, resource, offset): 38 | self.pycore = project.pycore 39 | self.resource = resource 40 | self.offset = offset 41 | self.pymodule = self.pycore.resource_to_pyobject(self.resource) 42 | scope = self.pymodule.get_scope().get_inner_scope_for_offset(offset) 43 | if scope.get_kind() != 'Function': 44 | raise exceptions.RefactoringError( 45 | 'Introduce parameter should be performed inside functions') 46 | self.pyfunction = scope.pyobject 47 | self.name, self.pyname = self._get_name_and_pyname() 48 | if self.pyname is None: 49 | raise exceptions.RefactoringError( 50 | 'Cannot find the definition of <%s>' % self.name) 51 | 52 | def _get_primary(self): 53 | word_finder = worder.Worder(self.resource.read()) 54 | return word_finder.get_primary_at(self.offset) 55 | 56 | def _get_name_and_pyname(self): 57 | return (worder.get_name_at(self.resource, self.offset), 58 | evaluate.eval_location(self.pymodule, self.offset)) 59 | 60 | def get_changes(self, new_parameter): 61 | definition_info = functionutils.DefinitionInfo.read(self.pyfunction) 62 | definition_info.args_with_defaults.append((new_parameter, 63 | self._get_primary())) 64 | collector = codeanalyze.ChangeCollector(self.resource.read()) 65 | header_start, header_end = self._get_header_offsets() 66 | body_start, body_end = sourceutils.get_body_region(self.pyfunction) 67 | collector.add_change(header_start, header_end, 68 | definition_info.to_string()) 69 | self._change_function_occurances(collector, body_start, 70 | body_end, new_parameter) 71 | changes = rope.base.change.ChangeSet('Introduce parameter <%s>' % 72 | new_parameter) 73 | change = rope.base.change.ChangeContents(self.resource, 74 | collector.get_changed()) 75 | changes.add_change(change) 76 | return changes 77 | 78 | def _get_header_offsets(self): 79 | lines = self.pymodule.lines 80 | start_line = self.pyfunction.get_scope().get_start() 81 | end_line = self.pymodule.logical_lines.\ 82 | logical_line_in(start_line)[1] 83 | start = lines.get_line_start(start_line) 84 | end = lines.get_line_end(end_line) 85 | start = self.pymodule.source_code.find('def', start) + 4 86 | end = self.pymodule.source_code.rfind(':', start, end) 87 | return start, end 88 | 89 | def _change_function_occurances(self, collector, function_start, 90 | function_end, new_name): 91 | finder = occurrences.create_finder(self.pycore, self.name, self.pyname) 92 | for occurrence in finder.find_occurrences(resource=self.resource): 93 | start, end = occurrence.get_primary_range() 94 | if function_start <= start < function_end: 95 | collector.add_change(start, end, new_name) 96 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/rope/refactor/method_object.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze 4 | from rope.refactor import sourceutils, occurrences, rename 5 | 6 | 7 | class MethodObject(object): 8 | 9 | def __init__(self, project, resource, offset): 10 | self.pycore = project.pycore 11 | this_pymodule = self.pycore.resource_to_pyobject(resource) 12 | pyname = evaluate.eval_location(this_pymodule, offset) 13 | if pyname is None or not isinstance(pyname.get_object(), 14 | pyobjects.PyFunction): 15 | raise exceptions.RefactoringError( 16 | 'Replace method with method object refactoring should be ' 17 | 'performed on a function.') 18 | self.pyfunction = pyname.get_object() 19 | self.pymodule = self.pyfunction.get_module() 20 | self.resource = self.pymodule.get_resource() 21 | 22 | def get_new_class(self, name): 23 | body = sourceutils.fix_indentation( 24 | self._get_body(), sourceutils.get_indent(self.pycore) * 2) 25 | return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \ 26 | (name, self._get_init(), 27 | ' ' * sourceutils.get_indent(self.pycore), body) 28 | 29 | def get_changes(self, classname=None, new_class_name=None): 30 | if new_class_name is not None: 31 | warnings.warn( 32 | 'new_class_name parameter is deprecated; use classname', 33 | DeprecationWarning, stacklevel=2) 34 | classname = new_class_name 35 | collector = codeanalyze.ChangeCollector(self.pymodule.source_code) 36 | start, end = sourceutils.get_body_region(self.pyfunction) 37 | indents = sourceutils.get_indents( 38 | self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \ 39 | sourceutils.get_indent(self.pycore) 40 | new_contents = ' ' * indents + 'return %s(%s)()\n' % \ 41 | (classname, ', '.join(self._get_parameter_names())) 42 | collector.add_change(start, end, new_contents) 43 | insertion = self._get_class_insertion_point() 44 | collector.add_change(insertion, insertion, 45 | '\n\n' + self.get_new_class(classname)) 46 | changes = change.ChangeSet('Replace method with method object refactoring') 47 | changes.add_change(change.ChangeContents(self.resource, 48 | collector.get_changed())) 49 | return changes 50 | 51 | def _get_class_insertion_point(self): 52 | current = self.pyfunction 53 | while current.parent != self.pymodule: 54 | current = current.parent 55 | end = self.pymodule.lines.get_line_end(current.get_scope().get_end()) 56 | return min(end + 1, len(self.pymodule.source_code)) 57 | 58 | def _get_body(self): 59 | body = sourceutils.get_body(self.pyfunction) 60 | for param in self._get_parameter_names(): 61 | body = param + ' = None\n' + body 62 | pymod = self.pycore.get_string_module(body, self.resource) 63 | pyname = pymod[param] 64 | finder = occurrences.create_finder(self.pycore, param, pyname) 65 | result = rename.rename_in_module(finder, 'self.' + param, 66 | pymodule=pymod) 67 | body = result[result.index('\n') + 1:] 68 | return body 69 | 70 | def _get_init(self): 71 | params = self._get_parameter_names() 72 | indents = ' ' * sourceutils.get_indent(self.pycore) 73 | if not params: 74 | return '' 75 | header = indents + 'def __init__(self' 76 | body = '' 77 | for arg in params: 78 | new_name = arg 79 | if arg == 'self': 80 | new_name = 'host' 81 | header += ', %s' % new_name 82 | body += indents * 2 + 'self.%s = %s\n' % (arg, new_name) 83 | header += '):' 84 | return '%s\n%s\n' % (header, body) 85 | 86 | def _get_parameter_names(self): 87 | return self.pyfunction.get_param_names() 88 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python2/rope/refactor/suites.py: -------------------------------------------------------------------------------- 1 | from rope.base import ast 2 | 3 | 4 | def find_visible(node, lines): 5 | """Return the line which is visible from all `lines`""" 6 | root = ast_suite_tree(node) 7 | return find_visible_for_suite(root, lines) 8 | 9 | 10 | def find_visible_for_suite(root, lines): 11 | if len(lines) == 1: 12 | return lines[0] 13 | line1 = lines[0] 14 | line2 = find_visible_for_suite(root, lines[1:]) 15 | suite1 = root.find_suite(line1) 16 | suite2 = root.find_suite(line2) 17 | def valid(suite): 18 | return suite is not None and not suite.ignored 19 | if valid(suite1) and not valid(suite2): 20 | return line1 21 | if not valid(suite1) and valid(suite2): 22 | return line2 23 | if not valid(suite1) and not valid(suite2): 24 | return None 25 | while suite1 != suite2 and suite1.parent != suite2.parent: 26 | if suite1._get_level() < suite2._get_level(): 27 | line2 = suite2.get_start() 28 | suite2 = suite2.parent 29 | elif suite1._get_level() > suite2._get_level(): 30 | line1 = suite1.get_start() 31 | suite1 = suite1.parent 32 | else: 33 | line1 = suite1.get_start() 34 | line2 = suite2.get_start() 35 | suite1 = suite1.parent 36 | suite2 = suite2.parent 37 | if suite1 == suite2: 38 | return min(line1, line2) 39 | return min(suite1.get_start(), suite2.get_start()) 40 | 41 | 42 | def ast_suite_tree(node): 43 | if hasattr(node, 'lineno'): 44 | lineno = node.lineno 45 | else: 46 | lineno = 1 47 | return Suite(node.body, lineno) 48 | 49 | 50 | class Suite(object): 51 | 52 | def __init__(self, child_nodes, lineno, parent=None, ignored=False): 53 | self.parent = parent 54 | self.lineno = lineno 55 | self.child_nodes = child_nodes 56 | self._children = None 57 | self.ignored = ignored 58 | 59 | def get_start(self): 60 | if self.parent is None: 61 | if self.child_nodes: 62 | return self.local_start() 63 | else: 64 | return 1 65 | return self.lineno 66 | 67 | def get_children(self): 68 | if self._children is None: 69 | walker = _SuiteWalker(self) 70 | for child in self.child_nodes: 71 | ast.walk(child, walker) 72 | self._children = walker.suites 73 | return self._children 74 | 75 | def local_start(self): 76 | return self.child_nodes[0].lineno 77 | 78 | def local_end(self): 79 | end = self.child_nodes[-1].lineno 80 | if self.get_children(): 81 | end = max(end, self.get_children()[-1].local_end()) 82 | return end 83 | 84 | def find_suite(self, line): 85 | if line is None: 86 | return None 87 | for child in self.get_children(): 88 | if child.local_start() <= line <= child.local_end(): 89 | return child.find_suite(line) 90 | return self 91 | 92 | def _get_level(self): 93 | if self.parent is None: 94 | return 0 95 | return self.parent._get_level() + 1 96 | 97 | 98 | class _SuiteWalker(object): 99 | 100 | def __init__(self, suite): 101 | self.suite = suite 102 | self.suites = [] 103 | 104 | def _If(self, node): 105 | self._add_if_like_node(node) 106 | 107 | def _For(self, node): 108 | self._add_if_like_node(node) 109 | 110 | def _While(self, node): 111 | self._add_if_like_node(node) 112 | 113 | def _With(self, node): 114 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 115 | 116 | def _TryFinally(self, node): 117 | if len(node.finalbody) == 1 and \ 118 | isinstance(node.body[0], ast.TryExcept): 119 | self._TryExcept(node.body[0]) 120 | else: 121 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 122 | self.suites.append(Suite(node.finalbody, node.lineno, self.suite)) 123 | 124 | def _TryExcept(self, node): 125 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 126 | for handler in node.handlers: 127 | self.suites.append(Suite(handler.body, node.lineno, self.suite)) 128 | if node.orelse: 129 | self.suites.append(Suite(node.orelse, node.lineno, self.suite)) 130 | 131 | def _add_if_like_node(self, node): 132 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 133 | if node.orelse: 134 | self.suites.append(Suite(node.orelse, node.lineno, self.suite)) 135 | 136 | def _FunctionDef(self, node): 137 | self.suites.append(Suite(node.body, node.lineno, 138 | self.suite, ignored=True)) 139 | 140 | def _ClassDef(self, node): 141 | self.suites.append(Suite(node.body, node.lineno, 142 | self.suite, ignored=True)) 143 | -------------------------------------------------------------------------------- /server/lib/python2/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/rope/base/ast.py: -------------------------------------------------------------------------------- 1 | import _ast 2 | from _ast import * 3 | 4 | from rope.base import fscommands, utils 5 | 6 | 7 | @utils.cached(10) 8 | def parse(source, filename=''): 9 | # NOTE: the raw string should be given to `compile` function 10 | if isinstance(source, str): 11 | source = fscommands.unicode_to_file_data(source) 12 | source = source.decode() 13 | if '\r' in source: 14 | source = source.replace('\r\n', '\n').replace('\r', '\n') 15 | if not source.endswith('\n'): 16 | source += '\n' 17 | try: 18 | return compile(source.encode(), filename, 'exec', _ast.PyCF_ONLY_AST) 19 | except (TypeError, ValueError) as e: 20 | error = SyntaxError() 21 | error.lineno = 1 22 | error.filename = filename 23 | error.msg = str(e) 24 | raise error 25 | 26 | 27 | def walk(node, walker): 28 | """Walk the syntax tree""" 29 | method_name = '_' + node.__class__.__name__ 30 | method = getattr(walker, method_name, None) 31 | if method is not None: 32 | return method(node) 33 | for child in get_child_nodes(node): 34 | walk(child, walker) 35 | 36 | 37 | def get_child_nodes(node): 38 | if isinstance(node, _ast.Module): 39 | return node.body 40 | result = [] 41 | if node._fields is not None: 42 | for name in node._fields: 43 | child = getattr(node, name) 44 | if isinstance(child, list): 45 | for entry in child: 46 | if isinstance(entry, _ast.AST): 47 | result.append(entry) 48 | if isinstance(child, _ast.AST): 49 | result.append(child) 50 | return result 51 | 52 | 53 | def call_for_nodes(node, callback, recursive=False): 54 | """If callback returns `True` the child nodes are skipped""" 55 | result = callback(node) 56 | if recursive and not result: 57 | for child in get_child_nodes(node): 58 | call_for_nodes(child, callback, recursive) 59 | 60 | 61 | def get_children(node): 62 | result = [] 63 | if node._fields is not None: 64 | for name in node._fields: 65 | if name in ['lineno', 'col_offset']: 66 | continue 67 | child = getattr(node, name) 68 | result.append(child) 69 | return result 70 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/rope/base/utils.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | from functools import partial 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 | def cached(count): 56 | """A caching decorator based on parameter objects""" 57 | def decorator(func): 58 | return _Cached(func, count) 59 | return decorator 60 | 61 | class _Cached(object): 62 | 63 | def __init__(self, func, count): 64 | self.func = func 65 | self.cache = [] 66 | self.count = count 67 | 68 | def __call__(self, *args, **kwds): 69 | key = (args, kwds) 70 | for cached_key, cached_result in self.cache: 71 | if cached_key == key: 72 | return cached_result 73 | result = self.func(*args, **kwds) 74 | self.cache.append((key, result)) 75 | if len(self.cache) > self.count: 76 | del self.cache[0] 77 | return result 78 | 79 | class memoize(object): 80 | """cache the return value of a method 81 | 82 | This class is meant to be used as a decorator of methods. The return value 83 | from a given method invocation will be cached on the instance whose method 84 | was invoked. All arguments passed to a method decorated with memoize must 85 | be hashable. 86 | 87 | If a memoized method is invoked directly on its class the result will not 88 | be cached. Instead the method will be invoked like a static method: 89 | class Obj(object): 90 | @memoize 91 | def add_to(self, arg): 92 | return self + arg 93 | Obj.add_to(1) # not enough arguments 94 | Obj.add_to(1, 2) # returns 3, result is not cached 95 | """ 96 | def __init__(self, func): 97 | self.func = func 98 | def __get__(self, obj, objtype=None): 99 | if obj is None: 100 | return self.func 101 | return partial(self, obj) 102 | def __call__(self, *args, **kw): 103 | obj = args[0] 104 | try: 105 | cache = obj.__cache 106 | except AttributeError: 107 | cache = obj.__cache = {} 108 | key = (self.func, args[1:], frozenset(kw.items())) 109 | try: 110 | res = cache[key] 111 | except KeyError: 112 | res = cache[key] = self.func(*args, **kw) 113 | return res 114 | 115 | def lazyprop(fn): 116 | attr_name = '_lazy_' + fn.__name__ 117 | @property 118 | def _lazyprop(self): 119 | if not hasattr(self, attr_name): 120 | setattr(self, attr_name, fn(self)) 121 | return getattr(self, attr_name) 122 | return _lazyprop 123 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/rope/contrib/findit.py: -------------------------------------------------------------------------------- 1 | import rope.base.codeanalyze 2 | import rope.base.evaluate 3 | import rope.base.pyobjects 4 | from rope.base import taskhandle, exceptions, worder 5 | from rope.contrib import fixsyntax 6 | from rope.refactor import occurrences 7 | 8 | 9 | def find_occurrences(project, resource, offset, unsure=False, resources=None, 10 | in_hierarchy=False, task_handle=taskhandle.NullTaskHandle()): 11 | """Return a list of `Location`\s 12 | 13 | If `unsure` is `True`, possible matches are returned, too. You 14 | can use `Location.unsure` to see which are unsure occurrences. 15 | `resources` can be a list of `rope.base.resource.File`\s that 16 | should be searched for occurrences; if `None` all python files 17 | in the project are searched. 18 | 19 | """ 20 | name = worder.get_name_at(resource, offset) 21 | this_pymodule = project.pycore.resource_to_pyobject(resource) 22 | primary, pyname = rope.base.evaluate.eval_location2( 23 | this_pymodule, offset) 24 | def is_match(occurrence): 25 | return unsure 26 | finder = occurrences.create_finder( 27 | project.pycore, name, pyname, unsure=is_match, 28 | in_hierarchy=in_hierarchy, instance=primary) 29 | if resources is None: 30 | resources = project.pycore.get_python_files() 31 | job_set = task_handle.create_jobset('Finding Occurrences', 32 | count=len(resources)) 33 | return _find_locations(finder, resources, job_set) 34 | 35 | 36 | def find_implementations(project, resource, offset, resources=None, 37 | task_handle=taskhandle.NullTaskHandle()): 38 | """Find the places a given method is overridden. 39 | 40 | Finds the places a method is implemented. Returns a list of 41 | `Location`\s. 42 | """ 43 | name = worder.get_name_at(resource, offset) 44 | this_pymodule = project.pycore.resource_to_pyobject(resource) 45 | pyname = rope.base.evaluate.eval_location(this_pymodule, offset) 46 | if pyname is not None: 47 | pyobject = pyname.get_object() 48 | if not isinstance(pyobject, rope.base.pyobjects.PyFunction) or \ 49 | pyobject.get_kind() != 'method': 50 | raise exceptions.BadIdentifierError('Not a method!') 51 | else: 52 | raise exceptions.BadIdentifierError('Cannot resolve the identifier!') 53 | def is_defined(occurrence): 54 | if not occurrence.is_defined(): 55 | return False 56 | def not_self(occurrence): 57 | if occurrence.get_pyname().get_object() == pyname.get_object(): 58 | return False 59 | filters = [is_defined, not_self, 60 | occurrences.InHierarchyFilter(pyname, True)] 61 | finder = occurrences.Finder(project.pycore, name, filters=filters) 62 | if resources is None: 63 | resources = project.pycore.get_python_files() 64 | job_set = task_handle.create_jobset('Finding Implementations', 65 | count=len(resources)) 66 | return _find_locations(finder, resources, job_set) 67 | 68 | 69 | def find_definition(project, code, offset, resource=None, maxfixes=1): 70 | """Return the definition location of the python name at `offset` 71 | 72 | A `Location` object is returned if the definition location can be 73 | determined, otherwise ``None`` is returned. 74 | """ 75 | fixer = fixsyntax.FixSyntax(project.pycore, code, resource, maxfixes) 76 | main_module = fixer.get_pymodule() 77 | pyname = fixer.pyname_at(offset) 78 | if pyname is not None: 79 | module, lineno = pyname.get_definition_location() 80 | name = rope.base.worder.Worder(code).get_word_at(offset) 81 | if lineno is not None: 82 | start = module.lines.get_line_start(lineno) 83 | def check_offset(occurrence): 84 | if occurrence.offset < start: 85 | return False 86 | pyname_filter = occurrences.PyNameFilter(pyname) 87 | finder = occurrences.Finder(project.pycore, name, 88 | [check_offset, pyname_filter]) 89 | for occurrence in finder.find_occurrences(pymodule=module): 90 | return Location(occurrence) 91 | 92 | 93 | class Location(object): 94 | 95 | def __init__(self, occurrence): 96 | self.resource = occurrence.resource 97 | self.region = occurrence.get_word_range() 98 | self.offset = self.region[0] 99 | self.unsure = occurrence.is_unsure() 100 | self.lineno = occurrence.lineno 101 | 102 | 103 | def _find_locations(finder, resources, job_set): 104 | result = [] 105 | for resource in resources: 106 | job_set.started_job(resource.path) 107 | for occurrence in finder.find_occurrences(resource): 108 | result.append(Location(occurrence)) 109 | job_set.finished_job() 110 | return result 111 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/rope/refactor/introduce_parameter.py: -------------------------------------------------------------------------------- 1 | import rope.base.change 2 | from rope.base import exceptions, evaluate, worder, codeanalyze 3 | from rope.refactor import functionutils, sourceutils, occurrences 4 | 5 | 6 | class IntroduceParameter(object): 7 | """Introduce parameter refactoring 8 | 9 | This refactoring adds a new parameter to a function and replaces 10 | references to an expression in it with the new parameter. 11 | 12 | The parameter finding part is different from finding similar 13 | pieces in extract refactorings. In this refactoring parameters 14 | are found based on the object they reference to. For instance 15 | in:: 16 | 17 | class A(object): 18 | var = None 19 | 20 | class B(object): 21 | a = A() 22 | 23 | b = B() 24 | a = b.a 25 | 26 | def f(a): 27 | x = b.a.var + a.var 28 | 29 | using this refactoring on ``a.var`` with ``p`` as the new 30 | parameter name, will result in:: 31 | 32 | def f(p=a.var): 33 | x = p + p 34 | 35 | """ 36 | 37 | def __init__(self, project, resource, offset): 38 | self.pycore = project.pycore 39 | self.resource = resource 40 | self.offset = offset 41 | self.pymodule = self.pycore.resource_to_pyobject(self.resource) 42 | scope = self.pymodule.get_scope().get_inner_scope_for_offset(offset) 43 | if scope.get_kind() != 'Function': 44 | raise exceptions.RefactoringError( 45 | 'Introduce parameter should be performed inside functions') 46 | self.pyfunction = scope.pyobject 47 | self.name, self.pyname = self._get_name_and_pyname() 48 | if self.pyname is None: 49 | raise exceptions.RefactoringError( 50 | 'Cannot find the definition of <%s>' % self.name) 51 | 52 | def _get_primary(self): 53 | word_finder = worder.Worder(self.resource.read()) 54 | return word_finder.get_primary_at(self.offset) 55 | 56 | def _get_name_and_pyname(self): 57 | return (worder.get_name_at(self.resource, self.offset), 58 | evaluate.eval_location(self.pymodule, self.offset)) 59 | 60 | def get_changes(self, new_parameter): 61 | definition_info = functionutils.DefinitionInfo.read(self.pyfunction) 62 | definition_info.args_with_defaults.append((new_parameter, 63 | self._get_primary())) 64 | collector = codeanalyze.ChangeCollector(self.resource.read()) 65 | header_start, header_end = self._get_header_offsets() 66 | body_start, body_end = sourceutils.get_body_region(self.pyfunction) 67 | collector.add_change(header_start, header_end, 68 | definition_info.to_string()) 69 | self._change_function_occurances(collector, body_start, 70 | body_end, new_parameter) 71 | changes = rope.base.change.ChangeSet('Introduce parameter <%s>' % 72 | new_parameter) 73 | change = rope.base.change.ChangeContents(self.resource, 74 | collector.get_changed()) 75 | changes.add_change(change) 76 | return changes 77 | 78 | def _get_header_offsets(self): 79 | lines = self.pymodule.lines 80 | start_line = self.pyfunction.get_scope().get_start() 81 | end_line = self.pymodule.logical_lines.\ 82 | logical_line_in(start_line)[1] 83 | start = lines.get_line_start(start_line) 84 | end = lines.get_line_end(end_line) 85 | start = self.pymodule.source_code.find('def', start) + 4 86 | end = self.pymodule.source_code.rfind(':', start, end) 87 | return start, end 88 | 89 | def _change_function_occurances(self, collector, function_start, 90 | function_end, new_name): 91 | finder = occurrences.create_finder(self.pycore, self.name, self.pyname) 92 | for occurrence in finder.find_occurrences(resource=self.resource): 93 | start, end = occurrence.get_primary_range() 94 | if function_start <= start < function_end: 95 | collector.add_change(start, end, new_name) 96 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/rope/refactor/method_object.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze 4 | from rope.refactor import sourceutils, occurrences, rename 5 | 6 | 7 | class MethodObject(object): 8 | 9 | def __init__(self, project, resource, offset): 10 | self.pycore = project.pycore 11 | this_pymodule = self.pycore.resource_to_pyobject(resource) 12 | pyname = evaluate.eval_location(this_pymodule, offset) 13 | if pyname is None or not isinstance(pyname.get_object(), 14 | pyobjects.PyFunction): 15 | raise exceptions.RefactoringError( 16 | 'Replace method with method object refactoring should be ' 17 | 'performed on a function.') 18 | self.pyfunction = pyname.get_object() 19 | self.pymodule = self.pyfunction.get_module() 20 | self.resource = self.pymodule.get_resource() 21 | 22 | def get_new_class(self, name): 23 | body = sourceutils.fix_indentation( 24 | self._get_body(), sourceutils.get_indent(self.pycore) * 2) 25 | return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \ 26 | (name, self._get_init(), 27 | ' ' * sourceutils.get_indent(self.pycore), body) 28 | 29 | def get_changes(self, classname=None, new_class_name=None): 30 | if new_class_name is not None: 31 | warnings.warn( 32 | 'new_class_name parameter is deprecated; use classname', 33 | DeprecationWarning, stacklevel=2) 34 | classname = new_class_name 35 | collector = codeanalyze.ChangeCollector(self.pymodule.source_code) 36 | start, end = sourceutils.get_body_region(self.pyfunction) 37 | indents = sourceutils.get_indents( 38 | self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \ 39 | sourceutils.get_indent(self.pycore) 40 | new_contents = ' ' * indents + 'return %s(%s)()\n' % \ 41 | (classname, ', '.join(self._get_parameter_names())) 42 | collector.add_change(start, end, new_contents) 43 | insertion = self._get_class_insertion_point() 44 | collector.add_change(insertion, insertion, 45 | '\n\n' + self.get_new_class(classname)) 46 | changes = change.ChangeSet('Replace method with method object refactoring') 47 | changes.add_change(change.ChangeContents(self.resource, 48 | collector.get_changed())) 49 | return changes 50 | 51 | def _get_class_insertion_point(self): 52 | current = self.pyfunction 53 | while current.parent != self.pymodule: 54 | current = current.parent 55 | end = self.pymodule.lines.get_line_end(current.get_scope().get_end()) 56 | return min(end + 1, len(self.pymodule.source_code)) 57 | 58 | def _get_body(self): 59 | body = sourceutils.get_body(self.pyfunction) 60 | for param in self._get_parameter_names(): 61 | body = param + ' = None\n' + body 62 | pymod = self.pycore.get_string_module(body, self.resource) 63 | pyname = pymod[param] 64 | finder = occurrences.create_finder(self.pycore, param, pyname) 65 | result = rename.rename_in_module(finder, 'self.' + param, 66 | pymodule=pymod) 67 | body = result[result.index('\n') + 1:] 68 | return body 69 | 70 | def _get_init(self): 71 | params = self._get_parameter_names() 72 | indents = ' ' * sourceutils.get_indent(self.pycore) 73 | if not params: 74 | return '' 75 | header = indents + 'def __init__(self' 76 | body = '' 77 | for arg in params: 78 | new_name = arg 79 | if arg == 'self': 80 | new_name = 'host' 81 | header += ', %s' % new_name 82 | body += indents * 2 + 'self.%s = %s\n' % (arg, new_name) 83 | header += '):' 84 | return '%s\n%s\n' % (header, body) 85 | 86 | def _get_parameter_names(self): 87 | return self.pyfunction.get_param_names() 88 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python3/rope/refactor/suites.py: -------------------------------------------------------------------------------- 1 | from rope.base import ast 2 | 3 | 4 | def find_visible(node, lines): 5 | """Return the line which is visible from all `lines`""" 6 | root = ast_suite_tree(node) 7 | return find_visible_for_suite(root, lines) 8 | 9 | 10 | def find_visible_for_suite(root, lines): 11 | if len(lines) == 1: 12 | return lines[0] 13 | line1 = lines[0] 14 | line2 = find_visible_for_suite(root, lines[1:]) 15 | suite1 = root.find_suite(line1) 16 | suite2 = root.find_suite(line2) 17 | def valid(suite): 18 | return suite is not None and not suite.ignored 19 | if valid(suite1) and not valid(suite2): 20 | return line1 21 | if not valid(suite1) and valid(suite2): 22 | return line2 23 | if not valid(suite1) and not valid(suite2): 24 | return None 25 | while suite1 != suite2 and suite1.parent != suite2.parent: 26 | if suite1._get_level() < suite2._get_level(): 27 | line2 = suite2.get_start() 28 | suite2 = suite2.parent 29 | elif suite1._get_level() > suite2._get_level(): 30 | line1 = suite1.get_start() 31 | suite1 = suite1.parent 32 | else: 33 | line1 = suite1.get_start() 34 | line2 = suite2.get_start() 35 | suite1 = suite1.parent 36 | suite2 = suite2.parent 37 | if suite1 == suite2: 38 | return min(line1, line2) 39 | return min(suite1.get_start(), suite2.get_start()) 40 | 41 | 42 | def ast_suite_tree(node): 43 | if hasattr(node, 'lineno'): 44 | lineno = node.lineno 45 | else: 46 | lineno = 1 47 | return Suite(node.body, lineno) 48 | 49 | 50 | class Suite(object): 51 | 52 | def __init__(self, child_nodes, lineno, parent=None, ignored=False): 53 | self.parent = parent 54 | self.lineno = lineno 55 | self.child_nodes = child_nodes 56 | self._children = None 57 | self.ignored = ignored 58 | 59 | def get_start(self): 60 | if self.parent is None: 61 | if self.child_nodes: 62 | return self.local_start() 63 | else: 64 | return 1 65 | return self.lineno 66 | 67 | def get_children(self): 68 | if self._children is None: 69 | walker = _SuiteWalker(self) 70 | for child in self.child_nodes: 71 | ast.walk(child, walker) 72 | self._children = walker.suites 73 | return self._children 74 | 75 | def local_start(self): 76 | return self.child_nodes[0].lineno 77 | 78 | def local_end(self): 79 | end = self.child_nodes[-1].lineno 80 | if self.get_children(): 81 | end = max(end, self.get_children()[-1].local_end()) 82 | return end 83 | 84 | def find_suite(self, line): 85 | if line is None: 86 | return None 87 | for child in self.get_children(): 88 | if child.local_start() <= line <= child.local_end(): 89 | return child.find_suite(line) 90 | return self 91 | 92 | def _get_level(self): 93 | if self.parent is None: 94 | return 0 95 | return self.parent._get_level() + 1 96 | 97 | 98 | class _SuiteWalker(object): 99 | 100 | def __init__(self, suite): 101 | self.suite = suite 102 | self.suites = [] 103 | 104 | def _If(self, node): 105 | self._add_if_like_node(node) 106 | 107 | def _For(self, node): 108 | self._add_if_like_node(node) 109 | 110 | def _While(self, node): 111 | self._add_if_like_node(node) 112 | 113 | def _With(self, node): 114 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 115 | 116 | def _TryFinally(self, node): 117 | if len(node.finalbody) == 1 and \ 118 | isinstance(node.body[0], ast.TryExcept): 119 | self._TryExcept(node.body[0]) 120 | else: 121 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 122 | self.suites.append(Suite(node.finalbody, node.lineno, self.suite)) 123 | 124 | def _TryExcept(self, node): 125 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 126 | for handler in node.handlers: 127 | self.suites.append(Suite(handler.body, node.lineno, self.suite)) 128 | if node.orelse: 129 | self.suites.append(Suite(node.orelse, node.lineno, self.suite)) 130 | 131 | def _add_if_like_node(self, node): 132 | self.suites.append(Suite(node.body, node.lineno, self.suite)) 133 | if node.orelse: 134 | self.suites.append(Suite(node.orelse, node.lineno, self.suite)) 135 | 136 | def _FunctionDef(self, node): 137 | self.suites.append(Suite(node.body, node.lineno, 138 | self.suite, ignored=True)) 139 | 140 | def _ClassDef(self, node): 141 | self.suites.append(Suite(node.body, node.lineno, 142 | self.suite, ignored=True)) 143 | -------------------------------------------------------------------------------- /server/lib/python3/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 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Jedi is a static analysis tool for Python that can be used in IDEs/editors. Its 3 | historic focus is autocompletion, but does static analysis for now as well. 4 | Jedi is fast and is very well tested. It understands Python on a deeper level 5 | than all other static analysis frameworks for Python. 6 | 7 | Jedi has support for two different goto functions. It's possible to search for 8 | related names and to list all names in a Python file and infer them. Jedi 9 | understands docstrings and you can use Jedi autocompletion in your REPL as 10 | well. 11 | 12 | Jedi uses a very simple API to connect with IDE's. There's a reference 13 | implementation as a `VIM-Plugin `_, 14 | which uses Jedi's autocompletion. We encourage you to use Jedi in your IDEs. 15 | It's really easy. 16 | 17 | To give you a simple example how you can use the Jedi library, here is an 18 | example for the autocompletion feature: 19 | 20 | >>> import jedi 21 | >>> source = ''' 22 | ... import datetime 23 | ... datetime.da''' 24 | >>> script = jedi.Script(source, 3, len('datetime.da'), 'example.py') 25 | >>> script 26 | 27 | >>> completions = script.completions() 28 | >>> completions #doctest: +ELLIPSIS 29 | [, , ...] 30 | >>> print(completions[0].complete) 31 | te 32 | >>> print(completions[0].name) 33 | date 34 | 35 | As you see Jedi is pretty simple and allows you to concentrate on writing a 36 | good text editor, while still having very good IDE features for Python. 37 | """ 38 | 39 | __version__ = '0.9.0' 40 | 41 | from jedi.api import Script, Interpreter, NotFoundError, set_debug_function 42 | from jedi.api import preload_module, defined_names, names 43 | from jedi import settings 44 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/__main__.py: -------------------------------------------------------------------------------- 1 | from sys import argv 2 | from os.path import join, dirname, abspath, isdir 3 | 4 | 5 | if len(argv) == 2 and argv[1] == 'repl': 6 | # don't want to use __main__ only for repl yet, maybe we want to use it for 7 | # something else. So just use the keyword ``repl`` for now. 8 | print(join(dirname(abspath(__file__)), 'api', 'replstartup.py')) 9 | elif len(argv) > 1 and argv[1] == 'linter': 10 | """ 11 | This is a pre-alpha API. You're not supposed to use it at all, except for 12 | testing. It will very likely change. 13 | """ 14 | import jedi 15 | import sys 16 | 17 | if '--debug' in sys.argv: 18 | jedi.set_debug_function() 19 | 20 | for path in sys.argv[2:]: 21 | if path.startswith('--'): 22 | continue 23 | if isdir(path): 24 | import fnmatch 25 | import os 26 | 27 | paths = [] 28 | for root, dirnames, filenames in os.walk(path): 29 | for filename in fnmatch.filter(filenames, '*.py'): 30 | paths.append(os.path.join(root, filename)) 31 | else: 32 | paths = [path] 33 | 34 | try: 35 | for path in paths: 36 | for error in jedi.Script(path=path)._analysis(): 37 | print(error) 38 | except Exception: 39 | if '--pdb' in sys.argv: 40 | import pdb 41 | pdb.post_mortem() 42 | else: 43 | raise 44 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/api/helpers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helpers for the API 3 | """ 4 | import re 5 | 6 | from jedi.parser import tree as pt 7 | from jedi.evaluate import imports 8 | 9 | 10 | def completion_parts(path_until_cursor): 11 | """ 12 | Returns the parts for the completion 13 | :return: tuple - (path, dot, like) 14 | """ 15 | match = re.match(r'^(.*?)(\.|)(\w?[\w\d]*)$', path_until_cursor, flags=re.S) 16 | return match.groups() 17 | 18 | 19 | def sorted_definitions(defs): 20 | # Note: `or ''` below is required because `module_path` could be 21 | return sorted(defs, key=lambda x: (x.module_path or '', x.line or 0, x.column or 0)) 22 | 23 | 24 | def get_on_import_stmt(evaluator, user_context, user_stmt, is_like_search=False): 25 | """ 26 | Resolve the user statement, if it is an import. Only resolve the 27 | parts until the user position. 28 | """ 29 | name = user_stmt.name_for_position(user_context.position) 30 | if name is None: 31 | return None, None 32 | 33 | i = imports.ImportWrapper(evaluator, name) 34 | return i, name 35 | 36 | 37 | def check_error_statements(module, pos): 38 | for error_statement in module.error_statement_stacks: 39 | if error_statement.first_type in ('import_from', 'import_name') \ 40 | and error_statement.first_pos < pos <= error_statement.next_start_pos: 41 | return importer_from_error_statement(error_statement, pos) 42 | return None, 0, False, False 43 | 44 | 45 | def importer_from_error_statement(error_statement, pos): 46 | def check_dotted(children): 47 | for name in children[::2]: 48 | if name.start_pos <= pos: 49 | yield name 50 | 51 | names = [] 52 | level = 0 53 | only_modules = True 54 | unfinished_dotted = False 55 | for typ, nodes in error_statement.stack: 56 | if typ == 'dotted_name': 57 | names += check_dotted(nodes) 58 | if nodes[-1] == '.': 59 | # An unfinished dotted_name 60 | unfinished_dotted = True 61 | elif typ == 'import_name': 62 | if nodes[0].start_pos <= pos <= nodes[0].end_pos: 63 | # We are on the import. 64 | return None, 0, False, False 65 | elif typ == 'import_from': 66 | for node in nodes: 67 | if node.start_pos >= pos: 68 | break 69 | elif isinstance(node, pt.Node) and node.type == 'dotted_name': 70 | names += check_dotted(node.children) 71 | elif node in ('.', '...'): 72 | level += len(node.value) 73 | elif isinstance(node, pt.Name): 74 | names.append(node) 75 | elif node == 'import': 76 | only_modules = False 77 | 78 | return names, level, only_modules, unfinished_dotted 79 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/api/interpreter.py: -------------------------------------------------------------------------------- 1 | """ 2 | TODO Some parts of this module are still not well documented. 3 | """ 4 | import inspect 5 | import re 6 | 7 | from jedi._compatibility import builtins 8 | from jedi import debug 9 | from jedi.common import source_to_unicode 10 | from jedi.cache import underscore_memoization 11 | from jedi.evaluate import compiled 12 | from jedi.evaluate.compiled.fake import get_module 13 | from jedi.parser import tree as pt 14 | from jedi.parser import load_grammar 15 | from jedi.parser.fast import FastParser 16 | from jedi.evaluate import helpers 17 | from jedi.evaluate import iterable 18 | from jedi.evaluate import representation as er 19 | 20 | 21 | def add_namespaces_to_parser(evaluator, namespaces, parser_module): 22 | for namespace in namespaces: 23 | for key, value in namespace.items(): 24 | # Name lookups in an ast tree work by checking names_dict. 25 | # Therefore we just add fake names to that and we're done. 26 | arr = parser_module.names_dict.setdefault(key, []) 27 | arr.append(LazyName(evaluator, parser_module, key, value)) 28 | 29 | 30 | class LazyName(helpers.FakeName): 31 | def __init__(self, evaluator, module, name, value): 32 | super(LazyName, self).__init__(name) 33 | self._module = module 34 | self._evaluator = evaluator 35 | self._value = value 36 | self._name = name 37 | 38 | def is_definition(self): 39 | return True 40 | 41 | @property 42 | @underscore_memoization 43 | def parent(self): 44 | """ 45 | Creating fake statements for the interpreter. 46 | """ 47 | obj = self._value 48 | parser_path = [] 49 | if inspect.ismodule(obj): 50 | module = obj 51 | else: 52 | names = [] 53 | try: 54 | o = obj.__objclass__ 55 | names.append(obj.__name__) 56 | obj = o 57 | except AttributeError: 58 | pass 59 | 60 | try: 61 | module_name = obj.__module__ 62 | names.insert(0, obj.__name__) 63 | except AttributeError: 64 | # Unfortunately in some cases like `int` there's no __module__ 65 | module = builtins 66 | else: 67 | # TODO this import is wrong. Yields x for x.y.z instead of z 68 | module = __import__(module_name) 69 | parser_path = names 70 | raw_module = get_module(self._value) 71 | 72 | found = [] 73 | try: 74 | path = module.__file__ 75 | except AttributeError: 76 | pass 77 | else: 78 | path = re.sub('c$', '', path) 79 | if path.endswith('.py'): 80 | # cut the `c` from `.pyc` 81 | with open(path) as f: 82 | source = source_to_unicode(f.read()) 83 | mod = FastParser(load_grammar(), source, path[:-1]).module 84 | if parser_path: 85 | assert len(parser_path) == 1 86 | found = self._evaluator.find_types(mod, parser_path[0], search_global=True) 87 | else: 88 | found = [self._evaluator.wrap(mod)] 89 | 90 | if not found: 91 | debug.warning('Possibly an interpreter lookup for Python code failed %s', 92 | parser_path) 93 | 94 | if not found: 95 | evaluated = compiled.CompiledObject(obj) 96 | if evaluated == builtins: 97 | # The builtins module is special and always cached. 98 | evaluated = compiled.builtin 99 | found = [evaluated] 100 | 101 | content = iterable.AlreadyEvaluated(found) 102 | stmt = pt.ExprStmt([self, pt.Operator(pt.zero_position_modifier, 103 | '=', (0, 0), ''), content]) 104 | stmt.parent = self._module 105 | return stmt 106 | 107 | @parent.setter 108 | def parent(self, value): 109 | """Needed because the super class tries to set parent.""" 110 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/api/keywords.py: -------------------------------------------------------------------------------- 1 | import pydoc 2 | import keyword 3 | 4 | from jedi._compatibility import is_py3 5 | from jedi import common 6 | from jedi.evaluate import compiled 7 | from jedi.evaluate.helpers import FakeName 8 | 9 | try: 10 | from pydoc_data import topics as pydoc_topics 11 | except ImportError: 12 | # Python 2.6 13 | import pydoc_topics 14 | 15 | if is_py3: 16 | keys = keyword.kwlist 17 | else: 18 | keys = keyword.kwlist + ['None', 'False', 'True'] 19 | 20 | 21 | def keywords(string='', pos=(0, 0), all=False): 22 | if all: 23 | return set([Keyword(k, pos) for k in keys]) 24 | if string in keys: 25 | return set([Keyword(string, pos)]) 26 | return set() 27 | 28 | 29 | def keyword_names(*args, **kwargs): 30 | return [k.name for k in keywords(*args, **kwargs)] 31 | 32 | 33 | def get_operator(string, pos): 34 | return Keyword(string, pos) 35 | 36 | 37 | class Keyword(object): 38 | def __init__(self, name, pos): 39 | self.name = FakeName(name, self, pos) 40 | self.start_pos = pos 41 | self.parent = compiled.builtin 42 | 43 | def get_parent_until(self): 44 | return self.parent 45 | 46 | @property 47 | def names(self): 48 | """ For a `parsing.Name` like comparision """ 49 | return [self.name] 50 | 51 | @property 52 | def docstr(self): 53 | return imitate_pydoc(self.name) 54 | 55 | def __repr__(self): 56 | return '<%s: %s>' % (type(self).__name__, self.name) 57 | 58 | 59 | def imitate_pydoc(string): 60 | """ 61 | It's not possible to get the pydoc's without starting the annoying pager 62 | stuff. 63 | """ 64 | # str needed because of possible unicode stuff in py2k (pydoc doesn't work 65 | # with unicode strings) 66 | string = str(string) 67 | h = pydoc.help 68 | with common.ignored(KeyError): 69 | # try to access symbols 70 | string = h.symbols[string] 71 | string, _, related = string.partition(' ') 72 | 73 | get_target = lambda s: h.topics.get(s, h.keywords.get(s)) 74 | while isinstance(string, str): 75 | string = get_target(string) 76 | 77 | try: 78 | # is a tuple now 79 | label, related = string 80 | except TypeError: 81 | return '' 82 | 83 | try: 84 | return pydoc_topics.topics[label] if pydoc_topics else '' 85 | except KeyError: 86 | return '' 87 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/api/replstartup.py: -------------------------------------------------------------------------------- 1 | """ 2 | To use Jedi completion in Python interpreter, add the following in your shell 3 | setup (e.g., ``.bashrc``):: 4 | 5 | export PYTHONSTARTUP="$(python -m jedi repl)" 6 | 7 | Then you will be able to use Jedi completer in your Python interpreter:: 8 | 9 | $ python 10 | Python 2.7.2+ (default, Jul 20 2012, 22:15:08) 11 | [GCC 4.6.1] on linux2 12 | Type "help", "copyright", "credits" or "license" for more information. 13 | >>> import os 14 | >>> os.path.join().split().in # doctest: +SKIP 15 | os.path.join().split().index os.path.join().split().insert 16 | 17 | """ 18 | import jedi.utils 19 | from jedi import __version__ as __jedi_version__ 20 | 21 | print('REPL completion using Jedi %s' % __jedi_version__) 22 | jedi.utils.setup_readline() 23 | 24 | del jedi 25 | 26 | # Note: try not to do many things here, as it will contaminate global 27 | # namespace of the interpreter. 28 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/api/usages.py: -------------------------------------------------------------------------------- 1 | from jedi._compatibility import unicode 2 | from jedi.api import classes 3 | from jedi.parser import tree 4 | from jedi.evaluate import imports 5 | 6 | 7 | def usages(evaluator, definition_names, mods): 8 | """ 9 | :param definitions: list of Name 10 | """ 11 | def compare_array(definitions): 12 | """ `definitions` are being compared by module/start_pos, because 13 | sometimes the id's of the objects change (e.g. executions). 14 | """ 15 | result = [] 16 | for d in definitions: 17 | module = d.get_parent_until() 18 | result.append((module, d.start_pos)) 19 | return result 20 | 21 | search_name = unicode(list(definition_names)[0]) 22 | compare_definitions = compare_array(definition_names) 23 | mods |= set([d.get_parent_until() for d in definition_names]) 24 | definitions = [] 25 | for m in imports.get_modules_containing_name(evaluator, mods, search_name): 26 | try: 27 | check_names = m.used_names[search_name] 28 | except KeyError: 29 | continue 30 | for name in check_names: 31 | 32 | result = evaluator.goto(name) 33 | if [c for c in compare_array(result) if c in compare_definitions]: 34 | definitions.append(classes.Definition(evaluator, name)) 35 | # Previous definitions might be imports, so include them 36 | # (because goto might return that import name). 37 | compare_definitions += compare_array([name]) 38 | return definitions 39 | 40 | 41 | def usages_add_import_modules(evaluator, definitions): 42 | """ Adds the modules of the imports """ 43 | new = set() 44 | for d in definitions: 45 | imp_or_stmt = d.get_definition() 46 | if isinstance(imp_or_stmt, tree.Import): 47 | s = imports.ImportWrapper(evaluator, d) 48 | new |= set(s.follow(is_goto=True)) 49 | return set(definitions) | new 50 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/debug.py: -------------------------------------------------------------------------------- 1 | from jedi._compatibility import encoding, is_py3, u 2 | import inspect 3 | import os 4 | import time 5 | 6 | try: 7 | if os.name == 'nt': 8 | # does not work on Windows, as pyreadline and colorama interfere 9 | raise ImportError 10 | else: 11 | # Use colorama for nicer console output. 12 | from colorama import Fore, init 13 | from colorama import initialise 14 | # pytest resets the stream at the end - causes troubles. Since after 15 | # every output the stream is reset automatically we don't need this. 16 | initialise.atexit_done = True 17 | init() 18 | except ImportError: 19 | class Fore(object): 20 | RED = '' 21 | GREEN = '' 22 | YELLOW = '' 23 | RESET = '' 24 | 25 | NOTICE = object() 26 | WARNING = object() 27 | SPEED = object() 28 | 29 | enable_speed = False 30 | enable_warning = False 31 | enable_notice = False 32 | 33 | # callback, interface: level, str 34 | debug_function = None 35 | ignored_modules = ['jedi.evaluate.builtin', 'jedi.parser'] 36 | _debug_indent = -1 37 | _start_time = time.time() 38 | 39 | 40 | def reset_time(): 41 | global _start_time, _debug_indent 42 | _start_time = time.time() 43 | _debug_indent = -1 44 | 45 | 46 | def increase_indent(func): 47 | """Decorator for makin """ 48 | def wrapper(*args, **kwargs): 49 | global _debug_indent 50 | _debug_indent += 1 51 | try: 52 | result = func(*args, **kwargs) 53 | finally: 54 | _debug_indent -= 1 55 | return result 56 | return wrapper 57 | 58 | 59 | def dbg(message, *args): 60 | """ Looks at the stack, to see if a debug message should be printed. """ 61 | if debug_function and enable_notice: 62 | frm = inspect.stack()[1] 63 | mod = inspect.getmodule(frm[0]) 64 | if not (mod.__name__ in ignored_modules): 65 | i = ' ' * _debug_indent 66 | debug_function(NOTICE, i + 'dbg: ' + message % tuple(u(repr(a)) for a in args)) 67 | 68 | 69 | def warning(message, *args): 70 | if debug_function and enable_warning: 71 | i = ' ' * _debug_indent 72 | debug_function(WARNING, i + 'warning: ' + message % tuple(u(repr(a)) for a in args)) 73 | 74 | 75 | def speed(name): 76 | if debug_function and enable_speed: 77 | now = time.time() 78 | i = ' ' * _debug_indent 79 | debug_function(SPEED, i + 'speed: ' + '%s %s' % (name, now - _start_time)) 80 | 81 | 82 | def print_to_stdout(level, str_out): 83 | """ The default debug function """ 84 | if level == NOTICE: 85 | col = Fore.GREEN 86 | elif level == WARNING: 87 | col = Fore.RED 88 | else: 89 | col = Fore.YELLOW 90 | if not is_py3: 91 | str_out = str_out.encode(encoding, 'replace') 92 | print(col + str_out + Fore.RESET) 93 | 94 | 95 | # debug_function = print_to_stdout 96 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | - the popular ``memoize_default`` works like a typical memoize and returns the 3 | default otherwise. 4 | - ``CachedMetaClass`` uses ``memoize_default`` to do the same with classes. 5 | """ 6 | 7 | import inspect 8 | 9 | NO_DEFAULT = object() 10 | 11 | 12 | def memoize_default(default=NO_DEFAULT, evaluator_is_first_arg=False, second_arg_is_evaluator=False): 13 | """ This is a typical memoization decorator, BUT there is one difference: 14 | To prevent recursion it sets defaults. 15 | 16 | Preventing recursion is in this case the much bigger use than speed. I 17 | don't think, that there is a big speed difference, but there are many cases 18 | where recursion could happen (think about a = b; b = a). 19 | """ 20 | def func(function): 21 | def wrapper(obj, *args, **kwargs): 22 | if evaluator_is_first_arg: 23 | cache = obj.memoize_cache 24 | elif second_arg_is_evaluator: # needed for meta classes 25 | cache = args[0].memoize_cache 26 | else: 27 | cache = obj._evaluator.memoize_cache 28 | 29 | try: 30 | memo = cache[function] 31 | except KeyError: 32 | memo = {} 33 | cache[function] = memo 34 | 35 | key = (obj, args, frozenset(kwargs.items())) 36 | if key in memo: 37 | return memo[key] 38 | else: 39 | if default is not NO_DEFAULT: 40 | memo[key] = default 41 | rv = function(obj, *args, **kwargs) 42 | if inspect.isgenerator(rv): 43 | rv = list(rv) 44 | memo[key] = rv 45 | return rv 46 | return wrapper 47 | return func 48 | 49 | 50 | class CachedMetaClass(type): 51 | """ 52 | This is basically almost the same than the decorator above, it just caches 53 | class initializations. Either you do it this way or with decorators, but 54 | with decorators you lose class access (isinstance, etc). 55 | """ 56 | @memoize_default(None, second_arg_is_evaluator=True) 57 | def __call__(self, *args, **kwargs): 58 | return super(CachedMetaClass, self).__call__(*args, **kwargs) 59 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake.py: -------------------------------------------------------------------------------- 1 | """ 2 | Loads functions that are mixed in to the standard library. E.g. builtins are 3 | written in C (binaries), but my autocompletion only understands Python code. By 4 | mixing in Python code, the autocompletion should work much better for builtins. 5 | """ 6 | 7 | import os 8 | import inspect 9 | 10 | from jedi._compatibility import is_py3, builtins, unicode 11 | from jedi.parser import Parser, load_grammar 12 | from jedi.parser import tree as pt 13 | from jedi.evaluate.helpers import FakeName 14 | 15 | modules = {} 16 | 17 | 18 | def _load_faked_module(module): 19 | module_name = module.__name__ 20 | if module_name == '__builtin__' and not is_py3: 21 | module_name = 'builtins' 22 | 23 | try: 24 | return modules[module_name] 25 | except KeyError: 26 | path = os.path.dirname(os.path.abspath(__file__)) 27 | try: 28 | with open(os.path.join(path, 'fake', module_name) + '.pym') as f: 29 | source = f.read() 30 | except IOError: 31 | modules[module_name] = None 32 | return 33 | grammar = load_grammar('grammar3.4') 34 | module = Parser(grammar, unicode(source), module_name).module 35 | modules[module_name] = module 36 | 37 | if module_name == 'builtins' and not is_py3: 38 | # There are two implementations of `open` for either python 2/3. 39 | # -> Rename the python2 version (`look at fake/builtins.pym`). 40 | open_func = search_scope(module, 'open') 41 | open_func.children[1] = FakeName('open_python3') 42 | open_func = search_scope(module, 'open_python2') 43 | open_func.children[1] = FakeName('open') 44 | return module 45 | 46 | 47 | def search_scope(scope, obj_name): 48 | for s in scope.subscopes: 49 | if str(s.name) == obj_name: 50 | return s 51 | 52 | 53 | def get_module(obj): 54 | if inspect.ismodule(obj): 55 | return obj 56 | try: 57 | obj = obj.__objclass__ 58 | except AttributeError: 59 | pass 60 | 61 | try: 62 | imp_plz = obj.__module__ 63 | except AttributeError: 64 | # Unfortunately in some cases like `int` there's no __module__ 65 | return builtins 66 | else: 67 | return __import__(imp_plz) 68 | 69 | 70 | def _faked(module, obj, name): 71 | # Crazy underscore actions to try to escape all the internal madness. 72 | if module is None: 73 | module = get_module(obj) 74 | 75 | faked_mod = _load_faked_module(module) 76 | if faked_mod is None: 77 | return 78 | 79 | # Having the module as a `parser.representation.module`, we need to scan 80 | # for methods. 81 | if name is None: 82 | if inspect.isbuiltin(obj): 83 | return search_scope(faked_mod, obj.__name__) 84 | elif not inspect.isclass(obj): 85 | # object is a method or descriptor 86 | cls = search_scope(faked_mod, obj.__objclass__.__name__) 87 | if cls is None: 88 | return 89 | return search_scope(cls, obj.__name__) 90 | else: 91 | if obj == module: 92 | return search_scope(faked_mod, name) 93 | else: 94 | cls = search_scope(faked_mod, obj.__name__) 95 | if cls is None: 96 | return 97 | return search_scope(cls, name) 98 | 99 | 100 | def get_faked(module, obj, name=None): 101 | obj = obj.__class__ if is_class_instance(obj) else obj 102 | result = _faked(module, obj, name) 103 | if result is None or isinstance(result, pt.Class): 104 | # We're not interested in classes. What we want is functions. 105 | return None 106 | else: 107 | # Set the docstr which was previously not set (faked modules don't 108 | # contain it). 109 | doc = '"""%s"""' % obj.__doc__ # TODO need escapes. 110 | suite = result.children[-1] 111 | string = pt.String(pt.zero_position_modifier, doc, (0, 0), '') 112 | new_line = pt.Whitespace('\n', (0, 0), '') 113 | docstr_node = pt.Node('simple_stmt', [string, new_line]) 114 | suite.children.insert(2, docstr_node) 115 | return result 116 | 117 | 118 | def is_class_instance(obj): 119 | """Like inspect.* methods.""" 120 | return not (inspect.isclass(obj) or inspect.ismodule(obj) 121 | or inspect.isbuiltin(obj) or inspect.ismethod(obj) 122 | or inspect.ismethoddescriptor(obj) or inspect.iscode(obj) 123 | or inspect.isgenerator(obj)) 124 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/_functools.pym: -------------------------------------------------------------------------------- 1 | class partial(): 2 | def __init__(self, func, *args, **keywords): 3 | self.__func = func 4 | self.__args = args 5 | self.__keywords = keywords 6 | 7 | def __call__(self, *args, **kwargs): 8 | # TODO should be **dict(self.__keywords, **kwargs) 9 | return self.__func(*(self.__args + args), **self.__keywords) 10 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/_sqlite3.pym: -------------------------------------------------------------------------------- 1 | def connect(database, timeout=None, isolation_level=None, detect_types=None, factory=None): 2 | return Connection() 3 | 4 | 5 | class Connection(): 6 | def cursor(self): 7 | return Cursor() 8 | 9 | 10 | class Cursor(): 11 | def cursor(self): 12 | return Cursor() 13 | 14 | def fetchone(self): 15 | return Row() 16 | 17 | def fetchmany(self, size=cursor.arraysize): 18 | return [self.fetchone()] 19 | 20 | def fetchall(self): 21 | return [self.fetchone()] 22 | 23 | 24 | class Row(): 25 | def keys(self): 26 | return [''] 27 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/_sre.pym: -------------------------------------------------------------------------------- 1 | def compile(): 2 | class SRE_Match(): 3 | endpos = int() 4 | lastgroup = int() 5 | lastindex = int() 6 | pos = int() 7 | string = str() 8 | regs = ((int(), int()),) 9 | 10 | def __init__(self, pattern): 11 | self.re = pattern 12 | 13 | def start(self): 14 | return int() 15 | 16 | def end(self): 17 | return int() 18 | 19 | def span(self): 20 | return int(), int() 21 | 22 | def expand(self): 23 | return str() 24 | 25 | def group(self, nr): 26 | return str() 27 | 28 | def groupdict(self): 29 | return {str(): str()} 30 | 31 | def groups(self): 32 | return (str(),) 33 | 34 | class SRE_Pattern(): 35 | flags = int() 36 | groupindex = {} 37 | groups = int() 38 | pattern = str() 39 | 40 | def findall(self, string, pos=None, endpos=None): 41 | """ 42 | findall(string[, pos[, endpos]]) --> list. 43 | Return a list of all non-overlapping matches of pattern in string. 44 | """ 45 | return [str()] 46 | 47 | def finditer(self, string, pos=None, endpos=None): 48 | """ 49 | finditer(string[, pos[, endpos]]) --> iterator. 50 | Return an iterator over all non-overlapping matches for the 51 | RE pattern in string. For each match, the iterator returns a 52 | match object. 53 | """ 54 | yield SRE_Match(self) 55 | 56 | def match(self, string, pos=None, endpos=None): 57 | """ 58 | match(string[, pos[, endpos]]) --> match object or None. 59 | Matches zero or more characters at the beginning of the string 60 | pattern 61 | """ 62 | return SRE_Match(self) 63 | 64 | def scanner(self, string, pos=None, endpos=None): 65 | pass 66 | 67 | def search(self, string, pos=None, endpos=None): 68 | """ 69 | search(string[, pos[, endpos]]) --> match object or None. 70 | Scan through string looking for a match, and return a corresponding 71 | MatchObject instance. Return None if no position in the string matches. 72 | """ 73 | return SRE_Match(self) 74 | 75 | def split(self, string, maxsplit=0]): 76 | """ 77 | split(string[, maxsplit = 0]) --> list. 78 | Split string by the occurrences of pattern. 79 | """ 80 | return [str()] 81 | 82 | def sub(self, repl, string, count=0): 83 | """ 84 | sub(repl, string[, count = 0]) --> newstring 85 | Return the string obtained by replacing the leftmost non-overlapping 86 | occurrences of pattern in string by the replacement repl. 87 | """ 88 | return str() 89 | 90 | def subn(self, repl, string, count=0): 91 | """ 92 | subn(repl, string[, count = 0]) --> (newstring, number of subs) 93 | Return the tuple (new_string, number_of_subs_made) found by replacing 94 | the leftmost non-overlapping occurrences of pattern with the 95 | replacement repl. 96 | """ 97 | return (str(), int()) 98 | 99 | return SRE_Pattern() 100 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/_weakref.pym: -------------------------------------------------------------------------------- 1 | def proxy(object, callback=None): 2 | return object 3 | 4 | class weakref(): 5 | def __init__(self, object, callback=None): 6 | self.__object = object 7 | def __call__(self): 8 | return self.__object 9 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/datetime.pym: -------------------------------------------------------------------------------- 1 | class datetime(): 2 | @staticmethod 3 | def now(): 4 | return datetime() 5 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/io.pym: -------------------------------------------------------------------------------- 1 | class TextIOWrapper(): 2 | def __next__(self): 3 | return str() 4 | 5 | def __iter__(self): 6 | yield str() 7 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/compiled/fake/posix.pym: -------------------------------------------------------------------------------- 1 | def getcwd(): 2 | return '' 3 | 4 | def getcwdu(): 5 | return '' 6 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/evaluate/flow_analysis.py: -------------------------------------------------------------------------------- 1 | from jedi.parser import tree 2 | 3 | 4 | class Status(object): 5 | lookup_table = {} 6 | 7 | def __init__(self, value, name): 8 | self._value = value 9 | self._name = name 10 | Status.lookup_table[value] = self 11 | 12 | def invert(self): 13 | if self is REACHABLE: 14 | return UNREACHABLE 15 | elif self is UNREACHABLE: 16 | return REACHABLE 17 | else: 18 | return UNSURE 19 | 20 | def __and__(self, other): 21 | if UNSURE in (self, other): 22 | return UNSURE 23 | else: 24 | return REACHABLE if self._value and other._value else UNREACHABLE 25 | 26 | def __repr__(self): 27 | return '<%s: %s>' % (type(self).__name__, self._name) 28 | 29 | 30 | REACHABLE = Status(True, 'reachable') 31 | UNREACHABLE = Status(False, 'unreachable') 32 | UNSURE = Status(None, 'unsure') 33 | 34 | 35 | def break_check(evaluator, base_scope, stmt, origin_scope=None): 36 | element_scope = evaluator.wrap(stmt.get_parent_scope(include_flows=True)) 37 | # Direct parents get resolved, we filter scopes that are separate branches. 38 | # This makes sense for autocompletion and static analysis. For actual 39 | # Python it doesn't matter, because we're talking about potentially 40 | # unreachable code. 41 | # e.g. `if 0:` would cause all name lookup within the flow make 42 | # unaccessible. This is not a "problem" in Python, because the code is 43 | # never called. In Jedi though, we still want to infer types. 44 | while origin_scope is not None: 45 | if element_scope == origin_scope: 46 | return REACHABLE 47 | origin_scope = origin_scope.parent 48 | return _break_check(evaluator, stmt, base_scope, element_scope) 49 | 50 | 51 | def _break_check(evaluator, stmt, base_scope, element_scope): 52 | element_scope = evaluator.wrap(element_scope) 53 | base_scope = evaluator.wrap(base_scope) 54 | 55 | reachable = REACHABLE 56 | if isinstance(element_scope, tree.IfStmt): 57 | if element_scope.node_after_else(stmt): 58 | for check_node in element_scope.check_nodes(): 59 | reachable = _check_if(evaluator, check_node) 60 | if reachable in (REACHABLE, UNSURE): 61 | break 62 | reachable = reachable.invert() 63 | else: 64 | node = element_scope.node_in_which_check_node(stmt) 65 | reachable = _check_if(evaluator, node) 66 | elif isinstance(element_scope, (tree.TryStmt, tree.WhileStmt)): 67 | return UNSURE 68 | 69 | # Only reachable branches need to be examined further. 70 | if reachable in (UNREACHABLE, UNSURE): 71 | return reachable 72 | 73 | if base_scope != element_scope and base_scope != element_scope.parent: 74 | return reachable & _break_check(evaluator, stmt, base_scope, element_scope.parent) 75 | return reachable 76 | 77 | 78 | def _check_if(evaluator, node): 79 | types = evaluator.eval_element(node) 80 | values = set(x.py__bool__() for x in types) 81 | if len(values) == 1: 82 | return Status.lookup_table[values.pop()] 83 | else: 84 | return UNSURE 85 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/parser/pgen2/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. 2 | # Licensed to PSF under a Contributor Agreement. 3 | 4 | # Modifications: 5 | # Copyright 2006 Google, Inc. All Rights Reserved. 6 | # Licensed to PSF under a Contributor Agreement. 7 | # Copyright 2014 David Halter. Integration into Jedi. 8 | # Modifications are dual-licensed: MIT and PSF. 9 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/parser/token.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from jedi._compatibility import is_py3 4 | from token import * 5 | 6 | 7 | COMMENT = N_TOKENS 8 | tok_name[COMMENT] = 'COMMENT' 9 | N_TOKENS += 1 10 | 11 | NL = N_TOKENS 12 | tok_name[NL] = 'NL' 13 | N_TOKENS += 1 14 | 15 | if is_py3: 16 | BACKQUOTE = N_TOKENS 17 | tok_name[BACKQUOTE] = 'BACKQUOTE' 18 | N_TOKENS += 1 19 | else: 20 | RARROW = N_TOKENS 21 | tok_name[RARROW] = 'RARROW' 22 | N_TOKENS += 1 23 | ELLIPSIS = N_TOKENS 24 | tok_name[ELLIPSIS] = 'ELLIPSIS' 25 | N_TOKENS += 1 26 | 27 | 28 | 29 | # Map from operator to number (since tokenize doesn't do this) 30 | 31 | opmap_raw = """\ 32 | ( LPAR 33 | ) RPAR 34 | [ LSQB 35 | ] RSQB 36 | : COLON 37 | , COMMA 38 | ; SEMI 39 | + PLUS 40 | - MINUS 41 | * STAR 42 | / SLASH 43 | | VBAR 44 | & AMPER 45 | < LESS 46 | > GREATER 47 | = EQUAL 48 | . DOT 49 | % PERCENT 50 | ` BACKQUOTE 51 | { LBRACE 52 | } RBRACE 53 | @ AT 54 | == EQEQUAL 55 | != NOTEQUAL 56 | <> NOTEQUAL 57 | <= LESSEQUAL 58 | >= GREATEREQUAL 59 | ~ TILDE 60 | ^ CIRCUMFLEX 61 | << LEFTSHIFT 62 | >> RIGHTSHIFT 63 | ** DOUBLESTAR 64 | += PLUSEQUAL 65 | -= MINEQUAL 66 | *= STAREQUAL 67 | /= SLASHEQUAL 68 | %= PERCENTEQUAL 69 | &= AMPEREQUAL 70 | |= VBAREQUAL 71 | ^= CIRCUMFLEXEQUAL 72 | <<= LEFTSHIFTEQUAL 73 | >>= RIGHTSHIFTEQUAL 74 | **= DOUBLESTAREQUAL 75 | // DOUBLESLASH 76 | //= DOUBLESLASHEQUAL 77 | -> RARROW 78 | ... ELLIPSIS 79 | """ 80 | 81 | opmap = {} 82 | for line in opmap_raw.splitlines(): 83 | op, name = line.split() 84 | opmap[op] = globals()[name] 85 | -------------------------------------------------------------------------------- /server/lib/python_all/jedi/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utilities for end-users. 3 | """ 4 | 5 | from __future__ import absolute_import 6 | import __main__ 7 | from collections import namedtuple 8 | import re 9 | import os 10 | import sys 11 | 12 | from jedi import Interpreter 13 | from jedi.api.helpers import completion_parts 14 | from jedi.parser.user_context import UserContext 15 | 16 | 17 | def setup_readline(namespace_module=__main__): 18 | """ 19 | Install Jedi completer to :mod:`readline`. 20 | 21 | This function setups :mod:`readline` to use Jedi in Python interactive 22 | shell. If you want to use a custom ``PYTHONSTARTUP`` file (typically 23 | ``$HOME/.pythonrc.py``), you can add this piece of code:: 24 | 25 | try: 26 | from jedi.utils import setup_readline 27 | setup_readline() 28 | except ImportError: 29 | # Fallback to the stdlib readline completer if it is installed. 30 | # Taken from http://docs.python.org/2/library/rlcompleter.html 31 | print("Jedi is not installed, falling back to readline") 32 | try: 33 | import readline 34 | import rlcompleter 35 | readline.parse_and_bind("tab: complete") 36 | except ImportError: 37 | print("Readline is not installed either. No tab completion is enabled.") 38 | 39 | This will fallback to the readline completer if Jedi is not installed. 40 | The readline completer will only complete names in the global namespace, 41 | so for example:: 42 | 43 | ran 44 | 45 | will complete to ``range`` 46 | 47 | with both Jedi and readline, but:: 48 | 49 | range(10).cou 50 | 51 | will show complete to ``range(10).count`` only with Jedi. 52 | 53 | You'll also need to add ``export PYTHONSTARTUP=$HOME/.pythonrc.py`` to 54 | your shell profile (usually ``.bash_profile`` or ``.profile`` if you use 55 | bash). 56 | 57 | """ 58 | class JediRL(object): 59 | def complete(self, text, state): 60 | """ 61 | This complete stuff is pretty weird, a generator would make 62 | a lot more sense, but probably due to backwards compatibility 63 | this is still the way how it works. 64 | 65 | The only important part is stuff in the ``state == 0`` flow, 66 | everything else has been copied from the ``rlcompleter`` std. 67 | library module. 68 | """ 69 | if state == 0: 70 | sys.path.insert(0, os.getcwd()) 71 | # Calling python doesn't have a path, so add to sys.path. 72 | try: 73 | interpreter = Interpreter(text, [namespace_module.__dict__]) 74 | 75 | path = UserContext(text, (1, len(text))).get_path_until_cursor() 76 | path, dot, like = completion_parts(path) 77 | before = text[:len(text) - len(like)] 78 | completions = interpreter.completions() 79 | finally: 80 | sys.path.pop(0) 81 | 82 | self.matches = [before + c.name_with_symbols for c in completions] 83 | try: 84 | return self.matches[state] 85 | except IndexError: 86 | return None 87 | 88 | try: 89 | import readline 90 | except ImportError: 91 | print("Module readline not available.") 92 | else: 93 | readline.set_completer(JediRL().complete) 94 | readline.parse_and_bind("tab: complete") 95 | # jedi itself does the case matching 96 | readline.parse_and_bind("set completion-ignore-case on") 97 | # because it's easier to hit the tab just once 98 | readline.parse_and_bind("set show-all-if-unmodified") 99 | readline.parse_and_bind("set show-all-if-ambiguous on") 100 | # don't repeat all the things written in the readline all the time 101 | readline.parse_and_bind("set completion-prefix-display-length 2") 102 | # No delimiters, Jedi handles that. 103 | readline.set_completer_delims('') 104 | 105 | 106 | def version_info(): 107 | """ 108 | Returns a namedtuple of Jedi's version, similar to Python's 109 | ``sys.version_info``. 110 | """ 111 | Version = namedtuple('Version', 'major, minor, micro') 112 | from jedi import __version__ 113 | tupl = re.findall('[a-z]+|\d+', __version__) 114 | return Version(*[x if i == 3 else int(x) for i, x in enumerate(tupl)]) 115 | -------------------------------------------------------------------------------- /server/linter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import _ast 3 | from SublimePythonIDE import pep8 4 | from SublimePythonIDE.sublime_python_errors import OffsetError, Pep8Error, Pep8Warning, PythonError 5 | import SublimePythonIDE.pyflakes.checker as pyflakes 6 | 7 | 8 | def pyflakes_check(code, encoding, filename, ignore=None): 9 | try: 10 | tree = compile(code.encode(encoding), filename, "exec", _ast.PyCF_ONLY_AST) 11 | except (SyntaxError, IndentationError) as value: 12 | msg = value.args[0] 13 | 14 | (lineno, offset, text) = value.lineno, value.offset, value.text 15 | 16 | # If there's an encoding problem with the file, the text is None. 17 | if text is None: 18 | # Avoid using msg, since for the only known case, it contains a 19 | # bogus message that claims the encoding the file declared was 20 | # unknown. 21 | if msg.startswith('duplicate argument'): 22 | arg = msg.split('duplicate argument ', 1)[1].split(' ', 1)[0] 23 | arg = arg.strip('\'"') 24 | error = pyflakes.messages.DuplicateArgument( 25 | filename, lineno, arg 26 | ) 27 | else: 28 | error = PythonError(filename, lineno, msg) 29 | else: 30 | line = text.splitlines()[-1] 31 | 32 | if offset is not None: 33 | offset = offset - (len(text) - len(line)) 34 | 35 | if offset is not None: 36 | error = OffsetError(filename, lineno, msg, offset) 37 | else: 38 | error = PythonError(filename, lineno, msg) 39 | return [error] 40 | except ValueError as e: 41 | return [PythonError(filename, 1, e.args[0])] 42 | else: 43 | # Okay, it's syntactically valid. Now check it. 44 | w = pyflakes.Checker(tree, filename, builtins=ignore) 45 | return w.messages 46 | 47 | 48 | def pep8_check(code, filename, ignore=None, max_line_length=pep8.MAX_LINE_LENGTH): 49 | messages = [] 50 | _lines = code.split('\n') 51 | 52 | if _lines: 53 | class SublimeLinterReport(pep8.BaseReport): 54 | def error(self, line_number, offset, text, check): 55 | """Report an error, according to options.""" 56 | code = text[:4] 57 | message = text[5:] 58 | 59 | if self._ignore_code(code): 60 | return 61 | if code in self.counters: 62 | self.counters[code] += 1 63 | else: 64 | self.counters[code] = 1 65 | self.messages[code] = message 66 | 67 | # Don't care about expected errors or warnings 68 | if code in self.expected: 69 | return 70 | 71 | self.file_errors += 1 72 | self.total_errors += 1 73 | 74 | if code.startswith('E'): 75 | messages.append(Pep8Error( 76 | filename, line_number, offset, code, message) 77 | ) 78 | else: 79 | messages.append(Pep8Warning( 80 | filename, line_number, offset, code, message) 81 | ) 82 | 83 | return code 84 | 85 | _ignore = ignore + pep8.DEFAULT_IGNORE.split(',') 86 | 87 | options = pep8.StyleGuide( 88 | reporter=SublimeLinterReport, ignore=_ignore).options 89 | options.max_line_length = max_line_length 90 | 91 | good_lines = [l + '\n' for l in _lines] 92 | good_lines[-1] = good_lines[-1].rstrip('\n') 93 | 94 | if not good_lines[-1]: 95 | good_lines = good_lines[:-1] 96 | 97 | try: 98 | pep8.Checker(filename, good_lines, options=options).check_all() 99 | except Exception as e: 100 | print("An exception occured when running pep8 checker: %s" % e) 101 | 102 | return messages 103 | 104 | 105 | def do_linting(lint_settings, code, encoding, filename): 106 | 107 | errors = [] 108 | 109 | if lint_settings.get("pep8", True): 110 | params = { 111 | 'ignore': lint_settings.get('pep8_ignore', []), 112 | 'max_line_length': lint_settings.get( 113 | 'pep8_max_line_length', None) or pep8.MAX_LINE_LENGTH, 114 | } 115 | errors.extend(pep8_check( 116 | code, filename, **params) 117 | ) 118 | 119 | pyflakes_ignore = lint_settings.get('pyflakes_ignore', None) 120 | pyflakes_disabled = lint_settings.get('pyflakes_disabled', False) 121 | 122 | if not pyflakes_disabled: 123 | errors.extend(pyflakes_check(code, encoding, filename, pyflakes_ignore)) 124 | 125 | return errors 126 | -------------------------------------------------------------------------------- /sublime_python_errors.py: -------------------------------------------------------------------------------- 1 | import SublimePythonIDE.pyflakes 2 | import SublimePythonIDE.pyflakes.messages 3 | 4 | 5 | SublimePythonIDE.pyflakes.messages.Message.__str__ = ( 6 | lambda self: self.message % self.message_args 7 | ) 8 | 9 | 10 | class PyflakesLoc: 11 | """ Error location data for pyflakes. 12 | 13 | pyflakes 0.7 wants loc as {lineno, col_offset} object 14 | we ducktype it here. Apparently AST code 15 | has been upgraded in some point? 16 | 17 | Online lineno attribute is required. 18 | """ 19 | 20 | def __init__(self, lineno): 21 | self.lineno = lineno 22 | 23 | 24 | class PythonLintError(SublimePythonIDE.pyflakes.messages.Message): 25 | 26 | def __init__( 27 | self, filename, loc, level, message, 28 | message_args, offset=0, text=None): 29 | 30 | super(PythonLintError, self).__init__(filename, PyflakesLoc(loc)) 31 | self.level = level 32 | self.message = message 33 | self.message_args = message_args 34 | self.offset = offset 35 | if text is not None: 36 | self.text = text 37 | 38 | 39 | class Pep8Error(PythonLintError): 40 | 41 | def __init__(self, filename, loc, offset, code, text): 42 | # PEP 8 Errors are downgraded to "warnings" 43 | super(Pep8Error, self).__init__( 44 | filename, loc, 'W', '[W] PEP 8 (%s): %s', 45 | (code, text), offset=offset, text=text 46 | ) 47 | 48 | 49 | class Pep8Warning(PythonLintError): 50 | 51 | def __init__(self, filename, loc, offset, code, text): 52 | # PEP 8 Warnings are downgraded to "violations" 53 | super(Pep8Warning, self).__init__( 54 | filename, loc, 'V', '[V] PEP 8 (%s): %s', 55 | (code, text), offset=offset, text=text 56 | ) 57 | 58 | 59 | class OffsetError(PythonLintError): 60 | 61 | def __init__(self, filename, loc, text, offset): 62 | super(OffsetError, self).__init__( 63 | filename, loc, 'E', '[E] %r', (text,), offset=offset + 1, text=text 64 | ) 65 | 66 | 67 | class PythonError(PythonLintError): 68 | 69 | def __init__(self, filename, loc, text): 70 | super(PythonError, self).__init__( 71 | filename, loc, 'E', '[E] %r', (text,), text=text 72 | ) 73 | --------------------------------------------------------------------------------