Skip to content

Add a plugin to provide autoimport functionality #199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
60c3101
initial autoimport work
bagel897 Apr 9, 2022
f71f4e6
provide suggestions
bagel897 Apr 17, 2022
fea8678
use str for sorting
bagel897 Apr 17, 2022
caa0e3c
textEdit to actually insert edits
bagel897 Apr 18, 2022
e5bb74c
use parso to decide to use autoimport
bagel897 Apr 18, 2022
95bf65e
use fixture on test suite, use new search_full api, ignore statments …
bagel897 Apr 22, 2022
60dbe47
ignore class, dots, import statements
bagel897 Apr 23, 2022
803455c
use thresholding for sorting
bagel897 Apr 27, 2022
b1fcbfe
implement document_did_save, adjust sorting
bagel897 Apr 27, 2022
8cb971c
update docs, place imports correctly.
bagel897 Apr 27, 2022
7ef14bd
update to use sqlite implementation
bagel897 May 4, 2022
fabac92
Merge branch 'develop' of https://github.com/python-lsp/python-lsp-se…
bagel897 May 25, 2022
bba1d16
clean up, bump rope to 1.1.1, make default disabled
bagel897 May 25, 2022
8f6f2ce
fix: schema order
bagel897 May 25, 2022
a363cc2
redo test suite
bagel897 May 25, 2022
a5304ab
use type hint
bagel897 May 25, 2022
e63cddd
Move autoimport object into workspace.
bagel897 May 26, 2022
a54c86a
format
bagel897 May 26, 2022
0c6b645
fix closing issues
bagel897 May 26, 2022
20d36de
Update pyproject.toml
bagel897 Jun 22, 2022
947b7ba
Merge branch 'develop' into autoimport
bagel897 Jun 22, 2022
163dd6e
Merge branch 'develop' of https://github.com/python-lsp/python-lsp-se…
bagel897 Jun 29, 2022
f951c48
fix: config
bagel897 Jul 3, 2022
3214d8f
fix: respect memory preference
bagel897 Jul 3, 2022
936b32d
Merge branch 'develop' of https://github.com/python-lsp/python-lsp-se…
bagel897 Jul 4, 2022
6009cfa
fix: pylint errors
bagel897 Jul 4, 2022
2f09dd6
Make test data persist
bagel897 Jul 4, 2022
f605a53
Merge branch 'develop' of https://github.com/python-lsp/python-lsp-se…
bagel897 Aug 27, 2022
e640c53
Switch to jedi get_names
bagel897 Aug 27, 2022
c3901ba
tests: use session scoped workspace
bagel897 Aug 27, 2022
36dee07
fix pylint errors
bagel897 Aug 27, 2022
332217f
Use MAX_SIZE, don't use tuple unpacking
bagel897 Aug 27, 2022
bb529ff
Use snake-cased name
bagel897 Nov 2, 2022
6664258
Update pylsp/config/schema.json
bagel897 Nov 2, 2022
f5a2992
Formatting changes
bagel897 Nov 3, 2022
76f68de
Add copyright headers
bagel897 Nov 3, 2022
a120188
Merge branch 'autoimport' of github.com:bageljrkhanofemus/python-lsp-…
bagel897 Nov 3, 2022
4bc83c9
Restore Optional Import
bagel897 Nov 3, 2022
bdbe5b1
update configuration
bagel897 Nov 3, 2022
a881498
Update dep names
bagel897 Nov 3, 2022
7f40c74
style: remove extra line
bagel897 Nov 3, 2022
72f3a7c
fix: single . handling
bagel897 Nov 3, 2022
9a461ba
style: reformat file
bagel897 Nov 3, 2022
6ecf97a
Fix another line length issue
bagel897 Nov 3, 2022
df80961
Fix style issue in pylsp/plugins/rope_autoimport.py
bagel897 Nov 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ This server can be configured using `workspace/didChangeConfiguration` method. E
| `pylsp.plugins.pylint.args` | `array` of non-unique `string` items | Arguments to pass to pylint. | `null` |
| `pylsp.plugins.pylint.executable` | `string` | Executable to run pylint with. Enabling this will run pylint on unsaved files via stdin. Can slow down workflow. Only works with python3. | `null` |
| `pylsp.plugins.rope_completion.enabled` | `boolean` | Enable or disable the plugin. | `false` |
| `pylsp.plugins.rope_autoimport.enabled` | `boolean` | Enable or disable the plugin. | `true` |
| `pylsp.plugins.rope_autoimport.enabled` | `boolean` | Enable or disable the plugin. | `false` |
| `pylsp.plugins.rope_completion.eager` | `boolean` | Resolve documentation and detail eagerly. | `false` |
| `pylsp.plugins.yapf.enabled` | `boolean` | Enable or disable the plugin. | `true` |
| `pylsp.rope.extensionModules` | `string` | Builtin and c-extension modules that are allowed to be imported and inspected by rope. | `null` |
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ As an example, to change the list of errors that pycodestyle will ignore, assumi
## LSP Server Features

* Auto Completion
* [Autoimport](docs/autoimport.md)
* Code Linting
* Signature Help
* Go to definition
Expand Down
9 changes: 5 additions & 4 deletions docs/autoimport.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Autoimport for pylsp
Requirements:
1. rope
2. ``pylsp.plugins.rope_autoimport.enabled`` is enabled
1. install ``python-lsp-server[rope]``
2. set ``pylsp.plugins.rope_autoimport.enabled`` to ``true``
## Startup
Autoimport will generate an autoimport sqllite3 database in .ropefolder/autoimport.db on startup.
This will take a few seconds but should be much quicker on future runs.
## Usage
Autoimport will provide suggestions to import names from everything in ``sys.path``. It will suggest modules, submodules, keywords, functions, and classes.
Autoimport will provide suggestions to import names from everything in ``sys.path``. You can change this by changing where pylsp is running or by setting rope's 'python_path' option.
It will suggest modules, submodules, keywords, functions, and classes.

Since autoimport inserts everything towards the end of the import group, its recommended you use the isort [plugin](https://github.com/paradoxxxzero/pyls-isort).

## Credits
- Most of the code was written by me, @bageljrkhanofemus
- [lyz-code](https://github.com/lyz-code/autoimport) for inspiration and some ideas
- [rope](https://github.com/python-rope/rope)
- [rope](https://github.com/python-rope/rope), especially @lieryan
- [pyright](https://github.com/Microsoft/pyright) for details on language server implementation
2 changes: 1 addition & 1 deletion pylsp/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@
"description": "Enable or disable the plugin."
},"pylsp.plugins.rope_autoimport.enabled": {
"type": "boolean",
"default": true,
"default": false,
"description": "Enable or disable the plugin."
},
"pylsp.plugins.rope_completion.eager": {
Expand Down
26 changes: 10 additions & 16 deletions pylsp/plugins/rope_autoimport.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import logging
from collections import OrderedDict
from functools import lru_cache
from typing import Generator, List, Set
from typing import Any, Dict, Generator, List, Set

import parso
from parso.python import tree
Expand All @@ -21,17 +20,12 @@


@hookimpl
def pylsp_settings():
def pylsp_settings() -> Dict[str, Dict[str, Dict[str, Any]]]:
# Default rope_completion to disabled
return {"plugins": {"rope_autoimport": {"enabled": True}}}
return {"plugins": {"rope_autoimport": {"enabled": False}}}


def deduplicate(input_list):
"""Remove duplicates from list."""
return list(OrderedDict.fromkeys(input_list))


def should_insert(expr: tree.BaseNode, word_node: tree.Leaf) -> bool:
def _should_insert(expr: tree.BaseNode, word_node: tree.Leaf) -> bool:
"""
Check if we should insert the word_node on the given expr.

Expand All @@ -52,11 +46,11 @@ def should_insert(expr: tree.BaseNode, word_node: tree.Leaf) -> bool:
if isinstance(first_child, (tree.PythonErrorNode, tree.PythonNode)):
# The tree will often include error nodes like this to indicate errors
# we want to ignore errors since the code is being written
return should_insert(first_child, word_node)
return handle_first_child(first_child, expr, word_node)
return _should_insert(first_child, word_node)
return _handle_first_child(first_child, expr, word_node)


def handle_first_child(
def _handle_first_child(
first_child: NodeOrLeaf, expr: tree.BaseNode, word_node: tree.Leaf
) -> bool:
"""Check if we suggest imports given the following first child."""
Expand Down Expand Up @@ -117,7 +111,7 @@ def _process_statements(
word: str,
autoimport: AutoImport,
document: Document,
) -> Generator:
) -> Generator[Dict[str, Any], None, None]:
for import_statement, name, source, itemkind in suggestions:
insert_line = autoimport.find_insertion_line(document.source) - 1
start = {"line": insert_line, "character": 0}
Expand Down Expand Up @@ -173,7 +167,7 @@ def pylsp_completions(
line = document.lines[position["line"]]
expr = parso.parse(line)
word_node = expr.get_leaf_for_position((1, position["character"]))
if not should_insert(expr, word_node):
if not _should_insert(expr, word_node):
return []
word = word_node.value
rope_config = config.settings(document_path=document.path).get("rope", {})
Expand Down Expand Up @@ -236,5 +230,5 @@ def pylsp_document_did_save(config: Config, workspace: Workspace, document: Docu
autoimport = AutoImport(rope_project, memory=False)
autoimport.generate_cache(resources=[rope_doucment])
# Might as well using saving the document as an indicator to regenerate the module cache
autoimport.generate_modules_cache()
autoimport.generate_modules_cache()
autoimport.close()
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ all = [
"pydocstyle>=2.0.0",
"pyflakes>=2.4.0,<2.5.0",
"pylint>=2.5.0",
"rope>=1.1.0",
"rope>=1.1.1",
"yapf",
]
autopep8 = ["autopep8>=1.6.0,<1.7.0"]
Expand All @@ -43,7 +43,7 @@ pycodestyle = ["pycodestyle>=2.8.0,<2.9.0"]
pydocstyle = ["pydocstyle>=2.0.0"]
pyflakes = ["pyflakes>=2.4.0,<2.5.0"]
pylint = ["pylint>=2.5.0"]
rope = ["rope>0.10.5"]
rope = ["rope>1.1.1"]
yapf = ["yapf"]
test = [
"pylint>=2.5.0",
Expand Down