Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-pylsp-rope for
openSUSE:Factory checked in at 2021-10-12 21:51:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pylsp-rope (Old)
and /work/SRC/openSUSE:Factory/.python-pylsp-rope.new.2443 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pylsp-rope"
Tue Oct 12 21:51:34 2021 rev:3 rq:924932 version:0.1.6
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pylsp-rope/python-pylsp-rope.changes
2021-10-05 22:34:30.358937560 +0200
+++
/work/SRC/openSUSE:Factory/.python-pylsp-rope.new.2443/python-pylsp-rope.changes
2021-10-12 21:51:34.940063177 +0200
@@ -1,0 +2,10 @@
+Tue Oct 12 05:16:48 UTC 2021 - Matej Cepl <[email protected]>
+
+- Update to 0.1.6:
+ - Fixed issue with missing typing-extensions dependency
+ - Add use functions refactoring
+ - Internal rewrites
+ - Add type annotation for many things
+ - Improve error handling during executeCommand()
+
+-------------------------------------------------------------------
Old:
----
pylsp-rope-0.1.4.tar.gz
New:
----
pylsp-rope-0.1.6.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pylsp-rope.spec ++++++
--- /var/tmp/diff_new_pack.wrUixP/_old 2021-10-12 21:51:35.424063870 +0200
+++ /var/tmp/diff_new_pack.wrUixP/_new 2021-10-12 21:51:35.432063882 +0200
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-pylsp-rope
-Version: 0.1.4
+Version: 0.1.6
Release: 0
Summary: Extended refactoring capabilities for Python LSP Server using
Rope
License: MIT
@@ -30,6 +30,7 @@
BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module wheel}
BuildRequires: python-rpm-macros
+BuildRequires: (python3-typing_extensions if python3-base <= 3.6)
# SECTION test requirements
BuildRequires: %{python_module python-lsp-server}
BuildRequires: %{python_module pytest}
++++++ pylsp-rope-0.1.4.tar.gz -> pylsp-rope-0.1.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/PKG-INFO
new/pylsp-rope-0.1.6/PKG-INFO
--- old/pylsp-rope-0.1.4/PKG-INFO 2021-10-05 05:14:48.619781300 +0200
+++ new/pylsp-rope-0.1.6/PKG-INFO 2021-10-12 04:16:42.299155200 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pylsp-rope
-Version: 0.1.4
+Version: 0.1.6
Summary: Extended refactoring capabilities for Python LSP Server using Rope.
Home-page: https://github.com/python-rope/pylsp-rope
Author: Lie Ryan
@@ -17,11 +17,14 @@
Requires-Python: >=3.6
Description-Content-Type: text/markdown
Provides-Extra: dev
+Provides-Extra: test
License-File: LICENSE
License-File: AUTHORS.txt
# pylsp-rope
+[](https://github.com/python-rope/pylsp-rope/actions/workflows/run-test.yml)
+
Extended refactoring capabilities for Python LSP Server using
[Rope](https://github.com/python-rope/rope).
@@ -58,6 +61,7 @@
- extract method (codeAction)
- extract variable (codeAction)
- inline method/variable/parameter (codeAction)
+- use function (codeAction)
- method to method object (codeAction)
- more to come...
@@ -68,19 +72,28 @@
### Extract method
-This refactoring works by triggering a CodeAction when selecting a block of
code.
+This refactoring works by triggering a CodeAction when selecting a block of
+code.
### Extract variable
-This refactoring works by triggering a CodeAction when selecting a Python
expression.
+This refactoring works by triggering a CodeAction when selecting a Python
+expression.
### Inline
-This refactoring works by triggering a CodeAction when the cursor is on a
resolvable Python identifier.
+This refactoring works by triggering a CodeAction when the cursor is on a
+resolvable Python identifier.
+
+### Use function
+
+This works by triggering a CodeAction when the cursor is on the function name
+of a `def` statement.
### Method to method object
-This refactoring works when the cursor is on a function definition.
+This works by triggering a CodeAction when the cursor is on the function name
+of a `def` statement.
## Caveat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/README.md
new/pylsp-rope-0.1.6/README.md
--- old/pylsp-rope-0.1.4/README.md 2021-10-05 03:45:00.000000000 +0200
+++ new/pylsp-rope-0.1.6/README.md 2021-10-12 04:04:46.000000000 +0200
@@ -1,5 +1,7 @@
# pylsp-rope
+[](https://github.com/python-rope/pylsp-rope/actions/workflows/run-test.yml)
+
Extended refactoring capabilities for Python LSP Server using
[Rope](https://github.com/python-rope/rope).
@@ -36,6 +38,7 @@
- extract method (codeAction)
- extract variable (codeAction)
- inline method/variable/parameter (codeAction)
+- use function (codeAction)
- method to method object (codeAction)
- more to come...
@@ -46,19 +49,28 @@
### Extract method
-This refactoring works by triggering a CodeAction when selecting a block of
code.
+This refactoring works by triggering a CodeAction when selecting a block of
+code.
### Extract variable
-This refactoring works by triggering a CodeAction when selecting a Python
expression.
+This refactoring works by triggering a CodeAction when selecting a Python
+expression.
### Inline
-This refactoring works by triggering a CodeAction when the cursor is on a
resolvable Python identifier.
+This refactoring works by triggering a CodeAction when the cursor is on a
+resolvable Python identifier.
+
+### Use function
+
+This works by triggering a CodeAction when the cursor is on the function name
+of a `def` statement.
### Method to method object
-This refactoring works when the cursor is on a function definition.
+This works by triggering a CodeAction when the cursor is on the function name
+of a `def` statement.
## Caveat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/commands.py
new/pylsp-rope-0.1.6/pylsp_rope/commands.py
--- old/pylsp-rope-0.1.4/pylsp_rope/commands.py 2021-10-05 03:38:45.000000000
+0200
+++ new/pylsp-rope-0.1.6/pylsp_rope/commands.py 2021-10-07 19:25:19.000000000
+0200
@@ -1,4 +1,5 @@
COMMAND_REFACTOR_EXTRACT_METHOD = "pylsp_rope.refactor.extract.method"
COMMAND_REFACTOR_EXTRACT_VARIABLE = "pylsp_rope.refactor.extract.variable"
COMMAND_REFACTOR_INLINE = "pylsp_rope.refactor.inline"
+COMMAND_REFACTOR_USE_FUNCTION = "pylsp_rope.refactor.use_function"
COMMAND_REFACTOR_METHOD_TO_METHOD_OBJECT =
"pylsp_rope.refactor.method_to_method_object"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/lsp_diff.py
new/pylsp-rope-0.1.6/pylsp_rope/lsp_diff.py
--- old/pylsp-rope-0.1.4/pylsp_rope/lsp_diff.py 2021-10-03 16:07:31.000000000
+0200
+++ new/pylsp-rope-0.1.6/pylsp_rope/lsp_diff.py 2021-10-10 12:33:41.000000000
+0200
@@ -1,16 +1,24 @@
import difflib
+from typing import Iterator, List, Tuple, cast
+
from pylsp_rope.text import Position
+from pylsp_rope.typing import TextEdit, Line, LineNumber
+
+
+_DifflibOpcode = Tuple[str, LineNumber, LineNumber, LineNumber, LineNumber]
-def _difflib_ops_to_text_edit_ops(ops, lines):
- op, start_old, end_old, start_new, end_new = ops
+def _difflib_ops_to_text_edit_ops(
+ opcode: _DifflibOpcode, lines: List[Line]
+) -> TextEdit:
+ op, start_old, end_old, start_new, end_new = opcode
if op == "replace" or op == "insert":
new_text = "".join(lines[start_new:end_new])
elif op == "delete":
new_text = ""
else:
- assert False, ops
+ assert False, opcode
return {
"range": {"start": Position(start_old), "end": Position(end_old)},
@@ -18,16 +26,18 @@
}
-def lsp_diff(lines_old, lines_new):
+def lsp_diff(lines_old: List[Line], lines_new: List[Line]) ->
Iterator[TextEdit]:
"""
Given two sequences of lines, produce a [TextEdit][1] changeset.
[1]:
https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textEdit
"""
matcher = difflib.SequenceMatcher(a=lines_old, b=lines_new)
- for ops in matcher.get_opcodes():
- if ops[0] == "equal":
+ for opcode in matcher.get_opcodes():
+ if opcode[0] == "equal":
continue
- text_edit_ops = _difflib_ops_to_text_edit_ops(ops, lines_new)
+ text_edit_ops = _difflib_ops_to_text_edit_ops(
+ cast(_DifflibOpcode, opcode), lines_new
+ )
yield text_edit_ops
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/plugin.py
new/pylsp-rope-0.1.6/pylsp_rope/plugin.py
--- old/pylsp-rope-0.1.4/pylsp_rope/plugin.py 2021-10-05 05:02:12.000000000
+0200
+++ new/pylsp-rope-0.1.6/pylsp_rope/plugin.py 2021-10-12 02:06:26.000000000
+0200
@@ -1,16 +1,19 @@
import ast
import logging
+from typing import List
-import rope.base.exceptions
from pylsp import hookimpl
-from rope.refactor import extract, inline, method_object
+from pylsp.lsp import MessageType
+from rope.refactor import extract, inline, method_object, usefunction
-from pylsp_rope import commands
+from pylsp_rope import typing, commands
from pylsp_rope.project import (
get_project,
get_resource,
+ get_resources,
apply_rope_changeset,
)
+from pylsp_rope.typing import DocumentUri, CodeActionKind
logger = logging.getLogger(__name__)
@@ -48,12 +51,14 @@
@hookimpl
-def pylsp_commands(config, workspace):
+def pylsp_commands(config, workspace) -> List[str]:
return [getattr(commands, cmd) for cmd in dir(commands) if not
cmd.startswith("_")]
@hookimpl
-def pylsp_code_actions(config, workspace, document, range, context):
+def pylsp_code_actions(
+ config, workspace, document, range, context
+) -> List[typing.CodeAction]:
logger.info("textDocument/codeAction: %s %s %s", document, range, context)
class info:
@@ -74,11 +79,22 @@
document_uri=document.uri,
range=range,
),
- "Inline method/variable": CommandRefactorInline(
+ "Inline method/variable/parameter": CommandRefactorInline(
workspace,
document_uri=document.uri,
position=info.position,
),
+ "Use function": CommandRefactorUseFunction(
+ workspace,
+ document_uri=document.uri,
+ position=info.position,
+ ),
+ "Use function for current file only": CommandRefactorUseFunction(
+ workspace,
+ document_uri=document.uri,
+ position=info.position,
+ documents=[document.uri],
+ ),
"To method object": CommandRefactorMethodToMethodObject(
workspace,
document_uri=document.uri,
@@ -97,50 +113,71 @@
def pylsp_execute_command(config, workspace, command, arguments):
logger.info("workspace/executeCommand: %s %s", command, arguments)
- commands = [
- CommandRefactorExtractMethod,
- CommandRefactorExtractVariable,
- CommandRefactorInline,
- CommandRefactorMethodToMethodObject,
- ]
+ commands = {cmd.name: cmd for cmd in Command.__subclasses__()}
- for cmd in commands:
- if command == cmd.name:
- cmd(workspace, **arguments[0])()
+ try:
+ return commands[command](workspace, **arguments[0])()
+ except Exception as exc:
+ logger.exception(
+ "Exception when doing workspace/executeCommand: %s",
+ str(exc),
+ exc_info=exc,
+ )
+ workspace.show_message(
+ f"pylsp-rope: {exc}",
+ msg_type=MessageType.Error,
+ )
class Command:
+ name: str
+ title: str
+ kind: CodeActionKind
+
def __init__(self, workspace, **arguments):
self.workspace = workspace
self.arguments = arguments
self.__dict__.update(**arguments)
+ def __call__(self):
+ pass
+
+ def validate(self, info):
+ pass
+
def is_valid(self, info):
try:
- is_valid = self._is_valid(info)
+ self.validate(info)
except Exception:
return False
else:
- return is_valid
+ return True
return False
- def _is_valid(self, info):
- return True
-
- def get_code_action(self, title):
+ def get_code_action(self, title: str) -> typing.CodeAction:
return {
"title": title,
"kind": self.kind,
"command": {
+ "title": title,
"command": self.name,
"arguments": [self.arguments],
},
}
+ @property # FIXME: backport cached_property
+ def project(self):
+ if not hasattr(self, "_project"):
+ self._project = get_project(self.workspace)
+ return self._project
+
class CommandRefactorExtractMethod(Command):
name = commands.COMMAND_REFACTOR_EXTRACT_METHOD
- kind = "refactor.extract"
+ kind: CodeActionKind = "refactor.extract"
+
+ document_uri: DocumentUri
+ range: typing.Range
# FIXME: requires rope.refactor.extract._ExceptionalConditionChecker for
proper checking
# def _is_valid(self, info):
@@ -150,7 +187,7 @@
current_document, resource = get_resource(self.workspace,
self.document_uri)
refactoring = extract.ExtractMethod(
- project=get_project(self.workspace),
+ project=self.project,
resource=resource,
start_offset=current_document.offset_at_position(self.range["start"]),
end_offset=current_document.offset_at_position(self.range["end"]),
@@ -163,18 +200,20 @@
class CommandRefactorExtractVariable(Command):
name = commands.COMMAND_REFACTOR_EXTRACT_VARIABLE
- kind = "refactor.extract"
+ kind: CodeActionKind = "refactor.extract"
- def _is_valid(self, info):
+ document_uri: DocumentUri
+ range: typing.Range
+
+ def validate(self, info):
# FIXME: requires rope.refactor.extract._ExceptionalConditionChecker
for proper checking
ast.parse(info.selected_text, mode="eval")
- return True
def __call__(self):
current_document, resource = get_resource(self.workspace,
self.document_uri)
refactoring = extract.ExtractVariable(
- project=get_project(self.workspace),
+ project=self.project,
resource=resource,
start_offset=current_document.offset_at_position(self.range["start"]),
end_offset=current_document.offset_at_position(self.range["end"]),
@@ -187,21 +226,23 @@
class CommandRefactorInline(Command):
name = commands.COMMAND_REFACTOR_INLINE
- kind = "refactor.inline"
+ kind: CodeActionKind = "refactor.inline"
+
+ document_uri: DocumentUri
+ position: typing.Range
- def _is_valid(self, info):
+ def validate(self, info):
inline.create_inline(
- project=get_project(self.workspace),
+ project=self.project,
resource=info.resource,
offset=info.current_document.offset_at_position(info.position),
)
- return True
def __call__(self):
current_document, resource = get_resource(self.workspace,
self.document_uri)
refactoring = inline.create_inline(
- project=get_project(self.workspace),
+ project=self.project,
resource=resource,
offset=current_document.offset_at_position(self.position),
)
@@ -209,15 +250,53 @@
apply_rope_changeset(self.workspace, rope_changeset)
+class CommandRefactorUseFunction(Command):
+ name = commands.COMMAND_REFACTOR_USE_FUNCTION
+ kind: CodeActionKind = "refactor"
+
+ document_uri: DocumentUri
+ position: typing.Range
+
+ def validate(self, info):
+ usefunction.UseFunction(
+ project=self.project,
+ resource=info.resource,
+ offset=info.current_document.offset_at_position(info.position),
+ )
+
+ def __call__(self):
+ current_document, resource = get_resource(self.workspace,
self.document_uri)
+
+ refactoring = usefunction.UseFunction(
+ project=self.project,
+ resource=resource,
+ offset=current_document.offset_at_position(self.position),
+ )
+ rope_changeset = refactoring.get_changes(
+ resources=get_resources(self.workspace, getattr(self, "documents",
None)),
+ )
+ apply_rope_changeset(self.workspace, rope_changeset)
+
+
class CommandRefactorMethodToMethodObject(Command):
name = commands.COMMAND_REFACTOR_METHOD_TO_METHOD_OBJECT
- kind = "refactor"
+ kind: CodeActionKind = "refactor.rewrite"
+
+ document_uri: DocumentUri
+ position: typing.Range
+
+ def validate(self, info):
+ method_object.MethodObject(
+ project=self.project,
+ resource=info.resource,
+ offset=info.current_document.offset_at_position(self.position),
+ )
def __call__(self):
current_document, resource = get_resource(self.workspace,
self.document_uri)
refactoring = method_object.MethodObject(
- project=get_project(self.workspace),
+ project=self.project,
resource=resource,
offset=current_document.offset_at_position(self.position),
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/project.py
new/pylsp-rope-0.1.6/pylsp_rope/project.py
--- old/pylsp-rope-0.1.4/pylsp_rope/project.py 2021-10-05 03:48:26.000000000
+0200
+++ new/pylsp-rope-0.1.6/pylsp_rope/project.py 2021-10-12 02:06:26.000000000
+0200
@@ -1,40 +1,54 @@
import logging
from functools import lru_cache
+from typing import List, Dict, Tuple
-from pylsp import uris
+from pylsp import uris, workspace
from rope.base import libutils
-from rope.base.project import Project
+from pylsp_rope import rope
from pylsp_rope.lsp_diff import lsp_diff
+from pylsp_rope.typing import WorkspaceEdit, DocumentUri, TextEdit, Line
logger = logging.getLogger(__name__)
@lru_cache(maxsize=None)
-def _get_project(workspace):
- project = Project(workspace.root_path)
+def _get_project(workspace) -> rope.Project:
+ project = rope.Project(workspace.root_path)
return project
-def get_project(workspace):
+def get_project(workspace) -> rope.Project:
project = _get_project(workspace)
project.validate()
return project
-def get_resource(workspace, document_uri):
+def get_resource(
+ workspace, document_uri: DocumentUri
+) -> Tuple[workspace.Document, rope.Resource]:
document = workspace.get_document(document_uri)
- resource = libutils.path_to_resource(get_project(workspace), document.path)
+ resource = libutils.path_to_resource(_get_project(workspace),
document.path)
return document, resource
-def get_document(workspace, resource):
+def get_resources(
+ workspace, documents: List[workspace.Document]
+) -> List[rope.Resource]:
+ if documents is None:
+ return None
+ return [get_resource(workspace, document_uri)[1] for document_uri in
documents]
+
+
+def get_document(workspace, resource: rope.Resource) -> workspace.Document:
return workspace.get_document(uris.from_fs_path(resource.real_path))
-def rope_changeset_to_workspace_changeset(workspace, rope_changeset):
- def _get_contents(change):
+def rope_changeset_to_workspace_edit(
+ workspace, rope_changeset: rope.ChangeSet
+) -> WorkspaceEdit:
+ def _get_contents(change: rope.Change) -> Tuple[List[Line], List[Line]]:
old = change.old_contents
new = change.new_contents
if old is None:
@@ -44,7 +58,7 @@
old = ""
return old.splitlines(keepends=True), new.splitlines(keepends=True)
- workspace_changeset = {}
+ workspace_changeset: Dict[DocumentUri, List[TextEdit]] = {}
for change in rope_changeset.changes:
lines_old, lines_new = _get_contents(change)
@@ -52,18 +66,16 @@
document_changes = workspace_changeset.setdefault(document.uri, [])
document_changes.extend(lsp_diff(lines_old, lines_new))
- return workspace_changeset
+ return {
+ "changes": workspace_changeset,
+ }
-def apply_rope_changeset(workspace, rope_changeset):
- workspace_changeset = rope_changeset_to_workspace_changeset(
+def apply_rope_changeset(workspace, rope_changeset: rope.ChangeSet) -> None:
+ workspace_edit = rope_changeset_to_workspace_edit(
workspace,
rope_changeset,
)
- workspace_edit = {
- "changes": workspace_changeset,
- }
-
logger.info("applying workspace edit: %s", workspace_edit)
workspace.apply_edit(workspace_edit)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/rope.py
new/pylsp-rope-0.1.6/pylsp_rope/rope.py
--- old/pylsp-rope-0.1.4/pylsp_rope/rope.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pylsp-rope-0.1.6/pylsp_rope/rope.py 2021-10-09 22:54:12.000000000
+0200
@@ -0,0 +1,11 @@
+from rope.base.change import ChangeSet, Change
+from rope.base.project import Project
+from rope.base.resources import Resource
+
+
+__all__ = [
+ "Change",
+ "ChangeSet",
+ "Project",
+ "Resource",
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/text.py
new/pylsp-rope-0.1.6/pylsp_rope/text.py
--- old/pylsp-rope-0.1.4/pylsp_rope/text.py 2021-10-02 12:38:30.000000000
+0200
+++ new/pylsp-rope-0.1.6/pylsp_rope/text.py 2021-10-12 04:04:46.000000000
+0200
@@ -1,11 +1,70 @@
-def Position(line, character=None, _default_character=0):
+from typing import Tuple, Union, overload, Optional
+
+from pylsp_rope import typing
+from pylsp_rope.typing import LineNumber, CharNumber, Literal
+
+
+START_OF_LINE: Literal["^"] = "^"
+END_OF_LINE: Literal["$"] = "$"
+
+
+AutoLineNumber = Union[LineNumber, int]
+AutoCharNumber = Union[CharNumber, int]
+
+
+_CharNumberOrMarker = Union[AutoCharNumber, Literal["^", "$"]]
+_PrimitiveLineCharNumber = Union[
+ AutoLineNumber, Tuple[AutoLineNumber, Optional[_CharNumberOrMarker]]
+]
+
+
+@overload
+def Position(
+ line: Tuple[AutoLineNumber, Optional[_CharNumberOrMarker]],
+ *,
+ _default_character: _CharNumberOrMarker = CharNumber(0),
+) -> typing.Position:
+ ...
+
+
+@overload
+def Position(
+ line: AutoLineNumber,
+ *,
+ _default_character: _CharNumberOrMarker = CharNumber(0),
+) -> typing.Position:
+ ...
+
+
+@overload
+def Position(
+ line: AutoLineNumber,
+ character: AutoCharNumber,
+) -> typing.Position:
+ ...
+
+
+@overload
+def Position(
+ line: AutoLineNumber,
+ character: Literal["^", "$"],
+) -> typing.Position:
+ ...
+
+
+def Position(
+ line: _PrimitiveLineCharNumber,
+ character: Optional[_CharNumberOrMarker] = None,
+ *,
+ _default_character: _CharNumberOrMarker = CharNumber(0),
+) -> typing.Position:
"""
Returns a
[Position](https://microsoft.github.io/language-server-protocol/specification#position)
object for a document.
`pos` can be:
- - Tuple[line, character] are passed directly to the object
+ - Tuple[LineNumber, CharNumber] are passed directly to the object
- int selects the start of the line
- "^" the first non-blank character of the line
- "$" the end of the line, which is the start of the next line
@@ -25,25 +84,31 @@
"""
if isinstance(line, tuple):
- assert (
- character is None
- ), "If `line` is a tuple, then `character` must not be supplied"
- line, character = line
+ # assert (
+ # character is None
+ # ), "If `line` is a tuple, then `character` must not be supplied"
+ lineno, character = line
+ else:
+ lineno = line
if character is None:
character = _default_character
if character == "$":
- line += 1
- character = 0
+ lineno = LineNumber(lineno + 1)
+ character = CharNumber(0)
+ assert character != "^", "not implemented yet"
return {
- "line": line,
+ "line": lineno,
"character": character,
}
-def Range(start, end=None):
+def Range(
+ start: _PrimitiveLineCharNumber,
+ end: Optional[_PrimitiveLineCharNumber] = None,
+) -> typing.Range:
"""
Returns a
[Range](https://microsoft.github.io/language-server-protocol/specification#range)
object for a document.
@@ -71,6 +136,6 @@
end = start
return {
- "start": Position(start, _default_character=0),
- "end": Position(end, _default_character="$"),
+ "start": Position(start, _default_character=CharNumber(0)),
+ "end": Position(end, _default_character=END_OF_LINE),
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope/typing.py
new/pylsp-rope-0.1.6/pylsp_rope/typing.py
--- old/pylsp-rope-0.1.4/pylsp_rope/typing.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pylsp-rope-0.1.6/pylsp_rope/typing.py 2021-10-12 04:04:46.000000000
+0200
@@ -0,0 +1,87 @@
+import sys
+from typing import List, Dict, Optional, NewType, Any
+
+
+if sys.version_info >= (3, 8):
+ from typing import TypedDict, Literal
+else:
+ from typing_extensions import TypedDict, Literal
+
+
+##########################
+### Standard LSP types ###
+##########################
+
+DocumentUri = NewType("DocumentUri", str)
+
+
+class Position(TypedDict):
+ line: int
+ character: int
+
+
+class Range(TypedDict):
+ start: Position
+ end: Position
+
+
+class TextEdit(TypedDict):
+ range: Range
+ newText: str
+
+
+class WorkspaceEdit(TypedDict):
+ changes: Optional[Dict[DocumentUri, List[TextEdit]]]
+ # documentChanges: ...
+ # changeAnnotations: ...
+
+
+class ApplyWorkspaceEditParams(TypedDict):
+ label: Optional[str]
+ edit: WorkspaceEdit
+
+
+class Command(TypedDict):
+ title: str
+ command: str
+ arguments: Optional[List[Any]]
+
+
+CodeActionKind = Literal[
+ "",
+ "quickfix",
+ "refactor",
+ "refactor.extract",
+ "refactor.inline",
+ "refactor.rewrite",
+ "source",
+ "source.organizeImports",
+ "source.fixAll",
+]
+
+
+class CodeAction(TypedDict):
+ title: str
+ kind: Optional[CodeActionKind]
+ # diagnostics: Optional[List[Diagnostic]]
+ # isPreferred: Optional[bool]
+ # disabled: Optional[_CodeActionDisabledReason]
+ # edit: Optional[WorkspaceEdit]
+ command: Optional[Command]
+ # data: Optional[Any]
+
+
+########################
+### pylsp-rope types ###
+########################
+
+DocumentContent = NewType("DocumentContent", str)
+Line = NewType("Line", str)
+LineNumber = NewType("LineNumber", int)
+CharNumber = NewType("CharNumber", int)
+
+
+class SimpleWorkspaceEdit(TypedDict):
+ """This is identical to WorkspaceEdit, but `changes` field is not
optional."""
+
+ changes: Dict[DocumentUri, List[TextEdit]]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope.egg-info/PKG-INFO
new/pylsp-rope-0.1.6/pylsp_rope.egg-info/PKG-INFO
--- old/pylsp-rope-0.1.4/pylsp_rope.egg-info/PKG-INFO 2021-10-05
05:14:48.000000000 +0200
+++ new/pylsp-rope-0.1.6/pylsp_rope.egg-info/PKG-INFO 2021-10-12
04:16:42.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pylsp-rope
-Version: 0.1.4
+Version: 0.1.6
Summary: Extended refactoring capabilities for Python LSP Server using Rope.
Home-page: https://github.com/python-rope/pylsp-rope
Author: Lie Ryan
@@ -17,11 +17,14 @@
Requires-Python: >=3.6
Description-Content-Type: text/markdown
Provides-Extra: dev
+Provides-Extra: test
License-File: LICENSE
License-File: AUTHORS.txt
# pylsp-rope
+[](https://github.com/python-rope/pylsp-rope/actions/workflows/run-test.yml)
+
Extended refactoring capabilities for Python LSP Server using
[Rope](https://github.com/python-rope/rope).
@@ -58,6 +61,7 @@
- extract method (codeAction)
- extract variable (codeAction)
- inline method/variable/parameter (codeAction)
+- use function (codeAction)
- method to method object (codeAction)
- more to come...
@@ -68,19 +72,28 @@
### Extract method
-This refactoring works by triggering a CodeAction when selecting a block of
code.
+This refactoring works by triggering a CodeAction when selecting a block of
+code.
### Extract variable
-This refactoring works by triggering a CodeAction when selecting a Python
expression.
+This refactoring works by triggering a CodeAction when selecting a Python
+expression.
### Inline
-This refactoring works by triggering a CodeAction when the cursor is on a
resolvable Python identifier.
+This refactoring works by triggering a CodeAction when the cursor is on a
+resolvable Python identifier.
+
+### Use function
+
+This works by triggering a CodeAction when the cursor is on the function name
+of a `def` statement.
### Method to method object
-This refactoring works when the cursor is on a function definition.
+This works by triggering a CodeAction when the cursor is on the function name
+of a `def` statement.
## Caveat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope.egg-info/SOURCES.txt
new/pylsp-rope-0.1.6/pylsp_rope.egg-info/SOURCES.txt
--- old/pylsp-rope-0.1.4/pylsp_rope.egg-info/SOURCES.txt 2021-10-05
05:14:48.000000000 +0200
+++ new/pylsp-rope-0.1.6/pylsp_rope.egg-info/SOURCES.txt 2021-10-12
04:16:42.000000000 +0200
@@ -10,7 +10,9 @@
pylsp_rope/lsp_diff.py
pylsp_rope/plugin.py
pylsp_rope/project.py
+pylsp_rope/rope.py
pylsp_rope/text.py
+pylsp_rope/typing.py
pylsp_rope.egg-info/PKG-INFO
pylsp_rope.egg-info/SOURCES.txt
pylsp_rope.egg-info/dependency_links.txt
@@ -26,10 +28,13 @@
test/test_lsp_diff.py
test/test_method_to_method_object.py
test/test_project.py
+test/test_usefunction.py
test/fixtures/function.py
test/fixtures/many_changes.py
test/fixtures/many_changes_inlined.py
test/fixtures/method_object.py
+test/fixtures/method_object_use_function.py
test/fixtures/simple.py
test/fixtures/simple_extract_method.py
-test/fixtures/simple_extract_variable.py
\ No newline at end of file
+test/fixtures/simple_extract_variable.py
+test/fixtures/use_function.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pylsp_rope.egg-info/requires.txt
new/pylsp-rope-0.1.6/pylsp_rope.egg-info/requires.txt
--- old/pylsp-rope-0.1.4/pylsp_rope.egg-info/requires.txt 2021-10-05
05:14:48.000000000 +0200
+++ new/pylsp-rope-0.1.6/pylsp_rope.egg-info/requires.txt 2021-10-12
04:16:42.000000000 +0200
@@ -1,6 +1,13 @@
python-lsp-server
rope
+[:python_version < "3.8"]
+typing-extensions
+
[dev]
+build
pytest
twine
+
+[test]
+pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/pyproject.toml
new/pylsp-rope-0.1.6/pyproject.toml
--- old/pylsp-rope-0.1.4/pyproject.toml 2021-10-02 16:59:30.000000000 +0200
+++ new/pylsp-rope-0.1.6/pyproject.toml 2021-10-12 02:48:36.000000000 +0200
@@ -1,2 +1,10 @@
[tool.black]
exclude = '.ropeproject|test/fixtures'
+
+
+[tool.mypy]
+python_version = "3.6"
+warn_return_any = true
+warn_unused_configs = true
+ignore_missing_imports = true
+check_untyped_defs = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/setup.cfg
new/pylsp-rope-0.1.6/setup.cfg
--- old/pylsp-rope-0.1.4/setup.cfg 2021-10-05 05:14:48.619781300 +0200
+++ new/pylsp-rope-0.1.6/setup.cfg 2021-10-12 04:16:42.299155200 +0200
@@ -1,6 +1,6 @@
[metadata]
name = pylsp-rope
-version = 0.1.4
+version = 0.1.6
author = Lie Ryan
author_email = [email protected]
url = https://github.com/python-rope/pylsp-rope
@@ -22,6 +22,7 @@
install_requires =
python-lsp-server
rope
+ typing-extensions; python_version < '3.8'
python_requires = >= 3.6
[options.entry_points]
@@ -29,8 +30,11 @@
[options.extras_require]
dev =
+ build
pytest
twine
+test =
+ pytest
[egg_info]
tag_build =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/fixtures/function.py
new/pylsp-rope-0.1.6/test/fixtures/function.py
--- old/pylsp-rope-0.1.4/test/fixtures/function.py 2021-10-05
05:04:03.000000000 +0200
+++ new/pylsp-rope-0.1.6/test/fixtures/function.py 2021-10-08
08:38:45.000000000 +0200
@@ -1,3 +1,7 @@
def add(a, b):
- print(f"{a} + {b} = {a + b}")
return a + b
+
+
+def main():
+ a, b = 10, 20
+ print(f"{a} + {b} = {a + b}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/fixtures/method_object.py
new/pylsp-rope-0.1.6/test/fixtures/method_object.py
--- old/pylsp-rope-0.1.4/test/fixtures/method_object.py 2021-10-05
05:04:03.000000000 +0200
+++ new/pylsp-rope-0.1.6/test/fixtures/method_object.py 2021-10-08
08:49:51.000000000 +0200
@@ -9,5 +9,9 @@
self.b = b
def __call__(self):
- print(f"{self.a} + {self.b} = {self.a + self.b}")
return self.a + self.b
+
+
+def main():
+ a, b = 10, 20
+ print(f"{a} + {b} = {a + b}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pylsp-rope-0.1.4/test/fixtures/method_object_use_function.py
new/pylsp-rope-0.1.6/test/fixtures/method_object_use_function.py
--- old/pylsp-rope-0.1.4/test/fixtures/method_object_use_function.py
1970-01-01 01:00:00.000000000 +0100
+++ new/pylsp-rope-0.1.6/test/fixtures/method_object_use_function.py
2021-10-08 08:50:22.000000000 +0200
@@ -0,0 +1,19 @@
+import function
+
+def add(a, b):
+ return NewMethodObject(a, b)()
+
+
+class NewMethodObject(object):
+
+ def __init__(self, a, b):
+ self.a = a
+ self.b = b
+
+ def __call__(self):
+ return function.add(self.a, self.b)
+
+
+def main():
+ a, b = 10, 20
+ print(f"{a} + {b} = {function.add(a, b)}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/fixtures/use_function.py
new/pylsp-rope-0.1.6/test/fixtures/use_function.py
--- old/pylsp-rope-0.1.4/test/fixtures/use_function.py 1970-01-01
01:00:00.000000000 +0100
+++ new/pylsp-rope-0.1.6/test/fixtures/use_function.py 2021-10-08
08:39:07.000000000 +0200
@@ -0,0 +1,7 @@
+def add(a, b):
+ return a + b
+
+
+def main():
+ a, b = 10, 20
+ print(f"{a} + {b} = {add(a, b)}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/helpers.py
new/pylsp-rope-0.1.6/test/helpers.py
--- old/pylsp-rope-0.1.4/test/helpers.py 2021-10-04 06:45:43.000000000
+0200
+++ new/pylsp-rope-0.1.6/test/helpers.py 2021-10-08 13:30:16.000000000
+0200
@@ -1,48 +1,90 @@
+from typing import (
+ Any,
+ Collection,
+ Dict,
+ List,
+)
from unittest.mock import ANY, call
+from pylsp.workspace import Document
+
+from pylsp_rope.typing import (
+ DocumentContent,
+ DocumentUri,
+ SimpleWorkspaceEdit,
+ TextEdit,
+)
from test.conftest import read_fixture_file
-def assert_code_actions_do_not_offer(response, command):
+def assert_code_actions_do_not_offer(response: Dict, command: str) -> None:
for action in response:
assert action["command"] != command, f"CodeAction should not offer
{action}"
-def assert_wholefile_changeset(document_changeset, target):
- assert len(document_changeset) == 1
- (change,) = document_changeset
+def assert_text_edits(document_edits: List[TextEdit], target: str) ->
DocumentContent:
new_text = read_fixture_file(target)
- assert change["newText"].strip() == new_text.strip()
- return new_text
+ for change in document_edits:
+ assert change["newText"] in new_text
+ return DocumentContent(new_text)
-def assert_changeset(document_changeset, target):
- new_text = read_fixture_file(target)
- for change in document_changeset:
- assert change["newText"] in new_text
- return new_text
+def assert_single_document_edit(
+ edit_request: Any, document: Document
+) -> List[TextEdit]:
+ workspace_edit = assert_is_apply_edit_request(edit_request)
+
+ document_uri: DocumentUri = document.uri
+ assert_modified_documents(
+ workspace_edit,
+ document_uris={document_uri},
+ )
+
+ assert len(workspace_edit["changes"]) == 1
+ document_edits = workspace_edit["changes"][document_uri]
+ assert isinstance(document_edits, list)
+ return document_edits
-def assert_single_document_edit(edit_request, document):
+def assert_is_apply_edit_request(edit_request: Any) -> SimpleWorkspaceEdit:
assert edit_request == call(
"workspace/applyEdit",
{
"edit": {
- "changes": {
- document.uri: ANY,
- },
+ "changes": ANY,
},
},
)
- (document_changeset,) = edit_request[0][1]["edit"]["changes"].values()
- for change in document_changeset:
- assert change == {
- "range": {
- "start": {"line": ANY, "character": ANY},
- "end": {"line": ANY, "character": ANY},
- },
- "newText": ANY,
- }
+ workspace_edit: SimpleWorkspaceEdit = edit_request[0][1]["edit"]
+ for document_uri, document_edits in workspace_edit["changes"].items():
+ assert is_document_uri(document_uri)
+ for change in document_edits:
+ assert change == {
+ "range": {
+ "start": {"line": ANY, "character": ANY},
+ "end": {"line": ANY, "character": ANY},
+ },
+ "newText": ANY,
+ }
+
+ return workspace_edit
+
+
+def is_document_uri(uri: DocumentUri) -> bool:
+ return isinstance(uri, str) and uri.startswith("file://")
+
+
+def assert_modified_documents(
+ workspace_edit: SimpleWorkspaceEdit,
+ document_uris: Collection[DocumentUri],
+) -> None:
+ assert workspace_edit["changes"].keys() == set(document_uris)
+
- return document_changeset
+def assert_unmodified_document(
+ workspace_edit: SimpleWorkspaceEdit,
+ document_uri: DocumentUri,
+) -> None:
+ assert is_document_uri(document_uri)
+ assert document_uri not in workspace_edit["changes"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/test_commands.py
new/pylsp-rope-0.1.6/test/test_commands.py
--- old/pylsp-rope-0.1.4/test/test_commands.py 2021-10-03 07:13:06.000000000
+0200
+++ new/pylsp-rope-0.1.6/test/test_commands.py 2021-10-07 19:25:17.000000000
+0200
@@ -1,4 +1,10 @@
-from pylsp_rope.plugin import pylsp_commands
+from unittest.mock import patch
+
+from pylsp.lsp import MessageType
+
+from pylsp_rope import commands
+from pylsp_rope.plugin import pylsp_commands, pylsp_execute_command
+from pylsp_rope.text import Position
def test_command_registration(config, workspace):
@@ -7,3 +13,38 @@
assert isinstance(commands, list)
assert all(isinstance(cmd, str) for cmd in commands)
assert all(cmd.startswith("pylsp_rope.") for cmd in commands)
+
+
+def test_command_error_handling(caplog, config, workspace, document):
+ """
+ pylsp_execute_command should never raise an error when executeCommand().
+
+ Instead, we'll show an error message to the user.
+ """
+
+ arguments = [
+ {
+ "document_uri": document.uri,
+ "position": Position(1),
+ },
+ ]
+
+ with patch(
+ "pylsp_rope.plugin.CommandRefactorInline.__call__",
+ side_effect=Exception("some unexpected exception"),
+ ):
+ pylsp_execute_command(
+ config,
+ workspace,
+ command=commands.COMMAND_REFACTOR_INLINE,
+ arguments=arguments,
+ )
+
+ workspace._endpoint.notify.assert_called_once_with(
+ "window/showMessage",
+ params={
+ "type": MessageType.Error,
+ "message": f"pylsp-rope: some unexpected exception",
+ },
+ )
+ assert "Traceback (most recent call last):" in caplog.text
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/test_extract.py
new/pylsp-rope-0.1.6/test/test_extract.py
--- old/pylsp-rope-0.1.4/test/test_extract.py 2021-10-05 04:03:13.000000000
+0200
+++ new/pylsp-rope-0.1.6/test/test_extract.py 2021-10-08 15:20:25.000000000
+0200
@@ -1,7 +1,7 @@
-from pylsp_rope import commands, plugin
+from pylsp_rope import commands, plugin, typing
from pylsp_rope.text import Range
from test.helpers import (
- assert_changeset,
+ assert_text_edits,
assert_code_actions_do_not_offer,
assert_single_document_edit,
)
@@ -21,10 +21,11 @@
context=code_action_context,
)
- expected = {
+ expected: typing.CodeAction = {
"title": "Extract variable",
"kind": "refactor.extract",
"command": {
+ "title": "Extract variable",
"command": commands.COMMAND_REFACTOR_EXTRACT_VARIABLE,
"arguments": [
{
@@ -37,6 +38,7 @@
assert expected in response
+ assert expected["command"] is not None
command = expected["command"]["command"]
arguments = expected["command"]["arguments"]
@@ -49,8 +51,8 @@
edit_request = workspace._endpoint.request.call_args
- document_changeset = assert_single_document_edit(edit_request, document)
- new_text = assert_changeset(document_changeset,
target="simple_extract_variable.py")
+ document_edits = assert_single_document_edit(edit_request, document)
+ new_text = assert_text_edits(document_edits,
target="simple_extract_variable.py")
assert "extracted_variable = " in new_text
@@ -87,10 +89,11 @@
context=code_action_context,
)
- expected = {
+ expected: typing.CodeAction = {
"title": "Extract method",
"kind": "refactor.extract",
"command": {
+ "title": "Extract method",
"command": commands.COMMAND_REFACTOR_EXTRACT_METHOD,
"arguments": [
{
@@ -103,6 +106,7 @@
assert expected in response
+ assert expected["command"] is not None
command = expected["command"]["command"]
arguments = expected["command"]["arguments"]
@@ -115,6 +119,6 @@
edit_request = workspace._endpoint.request.call_args
- document_changeset = assert_single_document_edit(edit_request, document)
- new_text = assert_changeset(document_changeset,
target="simple_extract_method.py")
+ document_edits = assert_single_document_edit(edit_request, document)
+ new_text = assert_text_edits(document_edits,
target="simple_extract_method.py")
assert "def extracted_method(" in new_text
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/test_inline.py
new/pylsp-rope-0.1.6/test/test_inline.py
--- old/pylsp-rope-0.1.4/test/test_inline.py 2021-10-04 08:39:46.000000000
+0200
+++ new/pylsp-rope-0.1.6/test/test_inline.py 2021-10-08 18:42:20.000000000
+0200
@@ -1,8 +1,8 @@
-from pylsp_rope import plugin, commands
+from pylsp_rope import commands, plugin, typing
from pylsp_rope.text import Range
from test.conftest import create_document
from test.helpers import (
- assert_changeset,
+ assert_text_edits,
assert_code_actions_do_not_offer,
assert_single_document_edit,
)
@@ -22,10 +22,11 @@
context=code_action_context,
)
- expected = {
- "title": "Inline method/variable",
+ expected: typing.CodeAction = {
+ "title": "Inline method/variable/parameter",
"kind": "refactor.inline",
"command": {
+ "title": "Inline method/variable/parameter",
"command": commands.COMMAND_REFACTOR_INLINE,
"arguments": [
{
@@ -38,6 +39,7 @@
assert expected in response
+ assert expected["command"] is not None
command = expected["command"]["command"]
arguments = expected["command"]["arguments"]
@@ -50,8 +52,8 @@
edit_request = workspace._endpoint.request.call_args
- document_changeset = assert_single_document_edit(edit_request, document)
- new_text = assert_changeset(document_changeset, target="simple.py")
+ document_edits = assert_single_document_edit(edit_request, document)
+ new_text = assert_text_edits(document_edits, target="simple.py")
assert "extracted_method" not in new_text
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pylsp-rope-0.1.4/test/test_method_to_method_object.py
new/pylsp-rope-0.1.6/test/test_method_to_method_object.py
--- old/pylsp-rope-0.1.4/test/test_method_to_method_object.py 2021-10-05
03:38:45.000000000 +0200
+++ new/pylsp-rope-0.1.6/test/test_method_to_method_object.py 2021-10-09
13:28:00.000000000 +0200
@@ -1,8 +1,8 @@
-from pylsp_rope import commands, plugin
+from pylsp_rope import commands, plugin, typing
from pylsp_rope.text import Range
from test.conftest import create_document
from test.helpers import (
- assert_changeset,
+ assert_text_edits,
assert_code_actions_do_not_offer,
assert_single_document_edit,
)
@@ -22,10 +22,11 @@
context=code_action_context,
)
- expected = {
+ expected: typing.CodeAction = {
"title": "To method object",
- "kind": "refactor",
+ "kind": "refactor.rewrite",
"command": {
+ "title": "To method object",
"command": commands.COMMAND_REFACTOR_METHOD_TO_METHOD_OBJECT,
"arguments": [
{
@@ -38,6 +39,7 @@
assert expected in response
+ assert expected["command"] is not None
command = expected["command"]["command"]
arguments = expected["command"]["arguments"]
@@ -50,7 +52,29 @@
edit_request = workspace._endpoint.request.call_args
- document_changeset = assert_single_document_edit(edit_request, document)
- new_text = assert_changeset(document_changeset, target="method_object.py")
+ document_edits = assert_single_document_edit(edit_request, document)
+ new_text = assert_text_edits(document_edits, target="method_object.py")
assert "class NewMethodObject(object)" in new_text
assert "NewMethodObject(a, b)()" in new_text
+
+
+def test_method_to_method_object_not_offered_when_selecting_unsuitable_range(
+ config, workspace, code_action_context
+):
+ document = create_document(workspace, "function.py")
+ line = 1
+ pos = document.lines[line].index("return")
+ selection = Range((line, pos), (line, pos))
+
+ response = plugin.pylsp_code_actions(
+ config=config,
+ workspace=workspace,
+ document=document,
+ range=selection,
+ context=code_action_context,
+ )
+
+ assert_code_actions_do_not_offer(
+ response,
+ command=commands.COMMAND_REFACTOR_INLINE,
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/test_project.py
new/pylsp-rope-0.1.6/test/test_project.py
--- old/pylsp-rope-0.1.4/test/test_project.py 2021-10-05 03:48:26.000000000
+0200
+++ new/pylsp-rope-0.1.6/test/test_project.py 2021-10-08 15:36:52.000000000
+0200
@@ -3,7 +3,7 @@
from pylsp_rope.project import (
get_project,
get_resource,
- rope_changeset_to_workspace_changeset,
+ rope_changeset_to_workspace_edit,
)
from test.conftest import create_document
@@ -11,12 +11,12 @@
def test_rope_changeset_to_workspace_changeset(workspace):
document = create_document(workspace, "many_changes.py")
rope_changeset = get_rope_changeset(workspace, document)
- workspace_changeset = rope_changeset_to_workspace_changeset(
+ workspace_edit = rope_changeset_to_workspace_edit(
workspace,
rope_changeset,
)
- assert workspace_changeset == {
+ assert workspace_edit["changes"] == {
document.uri: [
{
"range": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylsp-rope-0.1.4/test/test_usefunction.py
new/pylsp-rope-0.1.6/test/test_usefunction.py
--- old/pylsp-rope-0.1.4/test/test_usefunction.py 1970-01-01
01:00:00.000000000 +0100
+++ new/pylsp-rope-0.1.6/test/test_usefunction.py 2021-10-09
21:23:49.000000000 +0200
@@ -0,0 +1,127 @@
+from pylsp_rope import plugin, commands, typing
+from pylsp_rope.text import Range
+from test.conftest import create_document
+from test.helpers import (
+ assert_text_edits,
+ assert_is_apply_edit_request,
+ assert_modified_documents,
+ assert_unmodified_document,
+)
+
+
+def test_use_function_globally(config, workspace, code_action_context):
+ document = create_document(workspace, "function.py")
+ document2 = create_document(workspace, "method_object.py")
+ line = 0
+ pos = document.lines[line].index("def add") + 4
+ selection = Range((line, pos), (line, pos))
+
+ response = plugin.pylsp_code_actions(
+ config=config,
+ workspace=workspace,
+ document=document,
+ range=selection,
+ context=code_action_context,
+ )
+
+ expected: typing.CodeAction = {
+ "title": "Use function",
+ "kind": "refactor",
+ "command": {
+ "title": "Use function",
+ "command": commands.COMMAND_REFACTOR_USE_FUNCTION,
+ "arguments": [
+ {
+ "document_uri": document.uri,
+ "position": selection["start"],
+ },
+ ],
+ },
+ }
+
+ assert expected in response
+
+ assert expected["command"] is not None
+ command = expected["command"]["command"]
+ arguments = expected["command"]["arguments"]
+
+ response = plugin.pylsp_execute_command(
+ config=config,
+ workspace=workspace,
+ command=command,
+ arguments=arguments,
+ )
+
+ edit_request = workspace._endpoint.request.call_args
+
+ workspace_edit = assert_is_apply_edit_request(edit_request)
+ assert_modified_documents(workspace_edit, {document.uri, document2.uri})
+
+ new_text = assert_text_edits(
+ workspace_edit["changes"][document.uri], target="use_function.py"
+ )
+ assert "{add(a, b)}" in new_text
+
+ new_text = assert_text_edits(
+ workspace_edit["changes"][document2.uri],
target="method_object_use_function.py"
+ )
+ assert "import function" in new_text
+ assert "{function.add(a, b)}" in new_text
+
+
+def test_use_function_in_current_file(config, workspace, code_action_context):
+ document = create_document(workspace, "function.py")
+ document2 = create_document(workspace, "method_object.py")
+
+ line = 0
+ pos = document.lines[line].index("def add") + 4
+ selection = Range((line, pos), (line, pos))
+
+ response = plugin.pylsp_code_actions(
+ config=config,
+ workspace=workspace,
+ document=document,
+ range=selection,
+ context=code_action_context,
+ )
+
+ expected: typing.CodeAction = {
+ "title": "Use function for current file only",
+ "kind": "refactor",
+ "command": {
+ "title": "Use function for current file only",
+ "command": commands.COMMAND_REFACTOR_USE_FUNCTION,
+ "arguments": [
+ {
+ "document_uri": document.uri,
+ "position": selection["start"],
+ "documents": [document.uri],
+ },
+ ],
+ },
+ }
+
+ assert expected in response
+
+ assert expected["command"] is not None
+ command = expected["command"]["command"]
+ arguments = expected["command"]["arguments"]
+
+ response = plugin.pylsp_execute_command(
+ config=config,
+ workspace=workspace,
+ command=command,
+ arguments=arguments,
+ )
+
+ edit_request = workspace._endpoint.request.call_args
+
+ workspace_edit = assert_is_apply_edit_request(edit_request)
+ assert_modified_documents(workspace_edit, {document.uri})
+
+ new_text = assert_text_edits(
+ workspace_edit["changes"][document.uri], target="use_function.py"
+ )
+ assert "{add(a, b)}" in new_text
+
+ assert_unmodified_document(workspace_edit, document2.uri)