From cb51b09254efac0b2c22130815198fab487db54f Mon Sep 17 00:00:00 2001 From: Morten Linderud Date: Sun, 29 Mar 2020 21:36:08 +0200 Subject: [PATCH 01/23] Changed towards jedi 0.16 Signed-off-by: Morten Linderud --- pyls/plugins/jedi_completion.py | 10 +++++++--- pyls/workspace.py | 9 ++------- setup.py | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index caa543a1..9106c3c1 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -51,7 +51,11 @@ @hookimpl def pyls_completions(config, document, position): try: - definitions = document.jedi_script(position).completions() + code_position = {} + if position: + code_position = {'line': position['line'] + 1, + 'column': _utils.clip_column(position['character'], document.lines, position['line'])} + definitions = document.jedi_script().complete(**code_position) except AttributeError as e: if 'CompiledObject' in str(e): # Needed to handle missing CompiledObject attribute @@ -69,7 +73,7 @@ def pyls_completions(config, document, position): settings = config.plugin_settings('jedi_completion', document_path=document.path) should_include_params = settings.get('include_params') include_params = snippet_support and should_include_params and use_snippets(document, position) - return [_format_completion(d, include_params) for d in definitions] or None + return [_format_completion(signature, include_params) for d in definitions for signature in d.get_signatures()] or None def is_exception_class(name): @@ -173,7 +177,7 @@ def _label(definition): def _detail(definition): try: return definition.parent().full_name or '' - except AttributeError: + except (AttributeError, TypeError): return definition.full_name or '' diff --git a/pyls/workspace.py b/pyls/workspace.py index a58b76a2..f5c72375 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -237,16 +237,11 @@ def jedi_script(self, position=None): environment = self.get_enviroment(environment_path) if environment_path else None kwargs = { - 'source': self.source, - 'path': self.path, - 'sys_path': sys_path, + 'code': self.source, 'environment': environment, + 'project': jedi.api.Project(self.path, sys_path=sys_path), } - if position: - kwargs['line'] = position['line'] + 1 - kwargs['column'] = _utils.clip_column(position['character'], self.lines, position['line']) - return jedi.Script(**kwargs) def get_enviroment(self, environment_path=None): diff --git a/setup.py b/setup.py index a56416a0..8120f91a 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ 'configparser; python_version<"3.0"', 'future>=0.14.0; python_version<"3"', 'backports.functools_lru_cache; python_version<"3.2"', - 'jedi>=0.14.1,<0.16', + 'jedi>=0.14.1', 'python-jsonrpc-server>=0.3.2', 'pluggy', 'ujson<=1.35; platform_system!="Windows"' From 7ca854bc87937e153be0e4bffcd6d5afe7ce2c92 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Fri, 10 Apr 2020 00:43:16 +0200 Subject: [PATCH 02/23] remove deprecated params call --- pyls/plugins/jedi_completion.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index 9106c3c1..5c9c358c 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -53,18 +53,22 @@ def pyls_completions(config, document, position): try: code_position = {} if position: - code_position = {'line': position['line'] + 1, - 'column': _utils.clip_column(position['character'], document.lines, position['line'])} - definitions = document.jedi_script().complete(**code_position) + code_position = { + 'line': position['line'] + 1, + 'column': _utils.clip_column(position['character'], + document.lines, + position['line'])} + completions = document.jedi_script().complete(**code_position) except AttributeError as e: if 'CompiledObject' in str(e): # Needed to handle missing CompiledObject attribute # 'sub_modules_dict' - definitions = None + # TODO: probably not needed for new Complete objects + completions = None else: raise e - if not definitions: + if not completions: return None completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) @@ -73,7 +77,7 @@ def pyls_completions(config, document, position): settings = config.plugin_settings('jedi_completion', document_path=document.path) should_include_params = settings.get('include_params') include_params = snippet_support and should_include_params and use_snippets(document, position) - return [_format_completion(signature, include_params) for d in definitions for signature in d.get_signatures()] or None + return [_format_completion(c, include_params) for c in completions] or None def is_exception_class(name): @@ -142,9 +146,9 @@ def _format_completion(d, include_params=True): path = path.replace('/', '\\/') completion['insertText'] = path - if (include_params and hasattr(d, 'params') and d.params and - not is_exception_class(d.name)): - positional_args = [param for param in d.params + sig = d.get_signatures() + if (include_params and sig and not is_exception_class(d.name)): + positional_args = [param for param in sig[0].params if '=' not in param.description and param.name not in {'/', '*'}] @@ -167,8 +171,9 @@ def _format_completion(d, include_params=True): def _label(definition): - if definition.type in ('function', 'method') and hasattr(definition, 'params'): - params = ', '.join([param.name for param in definition.params]) + sig = definition.get_signatures() + if definition.type in ('function', 'method') and sig: + params = ', '.join([param.name for param in sig[0].params]) return '{}({})'.format(definition.name, params) return definition.name From b1e08e1eab69512d34420d8b29d79fd427afa255 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Fri, 10 Apr 2020 00:43:41 +0200 Subject: [PATCH 03/23] remove deprecated names call --- pyls/workspace.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index f5c72375..05ca83ec 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -213,16 +213,9 @@ def word_at_position(self, position): return m_start[0] + m_end[-1] def jedi_names(self, all_scopes=False, definitions=True, references=False): - environment_path = None - if self._config: - jedi_settings = self._config.plugin_settings('jedi', document_path=self.path) - environment_path = jedi_settings.get('environment') - environment = self.get_enviroment(environment_path) if environment_path else None - - return jedi.api.names( - source=self.source, path=self.path, all_scopes=all_scopes, - definitions=definitions, references=references, environment=environment, - ) + script = self.jedi_script() + return script.get_names(all_scopes=all_scopes, definitions=definitions, + references=references) def jedi_script(self, position=None): extra_paths = [] From 9e8d7fdab8b4fa53fbbd0211b720506ba08ae566 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Wed, 15 Apr 2020 18:08:27 +0200 Subject: [PATCH 04/23] convert position into jedi line, column fix path and project parameters for jedi_script remove deprecated usages() calls --- pyls/_utils.py | 11 +++++++++++ pyls/plugins/definition.py | 8 +++++--- pyls/plugins/highlight.py | 5 +++-- pyls/plugins/hover.py | 3 ++- pyls/plugins/jedi_completion.py | 8 +------- pyls/plugins/references.py | 6 +++--- pyls/plugins/signature.py | 3 ++- pyls/workspace.py | 8 +++++++- 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/pyls/_utils.py b/pyls/_utils.py index 919bf1c5..478beda0 100644 --- a/pyls/_utils.py +++ b/pyls/_utils.py @@ -152,6 +152,17 @@ def clip_column(column, lines, line_number): return min(column, max_column) +def position_to_jedi_linecolumn(document, position): + """Convert the format 'line', 'character' to 'line', 'column'""" + code_position = {} + if position: + code_position = {'line': position['line'] + 1, + 'column': clip_column(position['character'], + document.lines, + position['line'])} + return code_position + + if os.name == 'nt': import ctypes diff --git a/pyls/plugins/definition.py b/pyls/plugins/definition.py index 8ec3b1ad..d4c13179 100644 --- a/pyls/plugins/definition.py +++ b/pyls/plugins/definition.py @@ -1,6 +1,6 @@ # Copyright 2017 Palantir Technologies, Inc. import logging -from pyls import hookimpl, uris +from pyls import hookimpl, uris, _utils log = logging.getLogger(__name__) @@ -8,9 +8,11 @@ @hookimpl def pyls_definitions(config, document, position): settings = config.plugin_settings('jedi_definition') - definitions = document.jedi_script(position).goto_assignments( + code_position = _utils.position_to_jedi_linecolumn(document, position) + definitions = document.jedi_script().goto( follow_imports=settings.get('follow_imports', True), - follow_builtin_imports=settings.get('follow_builtin_imports', True)) + follow_builtin_imports=settings.get('follow_builtin_imports', True), + **code_position) return [ { diff --git a/pyls/plugins/highlight.py b/pyls/plugins/highlight.py index 839ffb26..4c4c195c 100644 --- a/pyls/plugins/highlight.py +++ b/pyls/plugins/highlight.py @@ -1,13 +1,14 @@ # Copyright 2017 Palantir Technologies, Inc. import logging -from pyls import hookimpl, lsp +from pyls import hookimpl, lsp, _utils log = logging.getLogger(__name__) @hookimpl def pyls_document_highlight(document, position): - usages = document.jedi_script(position).usages() + code_position = _utils.position_to_jedi_linecolumn(document, position) + usages = document.jedi_script().get_references(**code_position) def is_valid(definition): return definition.line is not None and definition.column is not None diff --git a/pyls/plugins/hover.py b/pyls/plugins/hover.py index a98c0ea0..b8ff749d 100644 --- a/pyls/plugins/hover.py +++ b/pyls/plugins/hover.py @@ -9,7 +9,8 @@ @hookimpl def pyls_hover(document, position): - definitions = document.jedi_script(position).goto_definitions() + code_position = _utils.position_to_jedi_linecolumn(document, position) + definitions = document.jedi_script().infer(**code_position) word = document.word_at_position(position) if LooseVersion(_utils.JEDI_VERSION) >= LooseVersion('0.15.0'): diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index 5c9c358c..c8797539 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -51,13 +51,7 @@ @hookimpl def pyls_completions(config, document, position): try: - code_position = {} - if position: - code_position = { - 'line': position['line'] + 1, - 'column': _utils.clip_column(position['character'], - document.lines, - position['line'])} + code_position = _utils.position_to_jedi_linecolumn(document, position) completions = document.jedi_script().complete(**code_position) except AttributeError as e: if 'CompiledObject' in str(e): diff --git a/pyls/plugins/references.py b/pyls/plugins/references.py index 120cde41..4bd47c96 100644 --- a/pyls/plugins/references.py +++ b/pyls/plugins/references.py @@ -1,14 +1,14 @@ # Copyright 2017 Palantir Technologies, Inc. import logging -from pyls import hookimpl, uris +from pyls import hookimpl, uris, _utils log = logging.getLogger(__name__) @hookimpl def pyls_references(document, position, exclude_declaration=False): - # Note that usages is not that great in a lot of cases: https://github.com/davidhalter/jedi/issues/744 - usages = document.jedi_script(position).usages() + code_position = _utils.position_to_jedi_linecolumn(document, position) + usages = document.jedi_script().get_references(**code_position) if exclude_declaration: # Filter out if the usage is the actual declaration of the thing diff --git a/pyls/plugins/signature.py b/pyls/plugins/signature.py index 6c509272..fff7a576 100644 --- a/pyls/plugins/signature.py +++ b/pyls/plugins/signature.py @@ -14,7 +14,8 @@ @hookimpl def pyls_signature_help(document, position): - signatures = document.jedi_script(position).call_signatures() + code_position = _utils.position_to_jedi_linecolumn(document, position) + signatures = document.jedi_script().get_signatures(**code_position) if not signatures: return {'signatures': []} diff --git a/pyls/workspace.py b/pyls/workspace.py index 05ca83ec..8e969e71 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -231,10 +231,16 @@ def jedi_script(self, position=None): kwargs = { 'code': self.source, + 'path': self.path, 'environment': environment, - 'project': jedi.api.Project(self.path, sys_path=sys_path), + 'project': jedi.api.Project(os.path.dirname(self.path), + sys_path=sys_path), } + if position: + # deprecated by Jedi to use in Script() constructor + kwargs += _utils.position_to_jedi_linecolumn(self, position) + return jedi.Script(**kwargs) def get_enviroment(self, environment_path=None): From 16a526b1cab9ef00eb298f2637392a0b132ed942 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Thu, 16 Apr 2020 11:45:54 +0200 Subject: [PATCH 05/23] jedi.Script keywords source vs code source is deprecated in 0.17.0 in favor of code but code did not exist in 0.16.0 --- pyls/workspace.py | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index 8e969e71..8b31c56d 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -230,7 +230,8 @@ def jedi_script(self, position=None): environment = self.get_enviroment(environment_path) if environment_path else None kwargs = { - 'code': self.source, + # 'source' is deprecated but 'code' was only introduced in 0.17.0 + 'source' if jedi.__version__ < "0.17.0" else 'code': self.source, 'path': self.path, 'environment': environment, 'project': jedi.api.Project(os.path.dirname(self.path), diff --git a/setup.py b/setup.py index 8120f91a..1070065b 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ 'configparser; python_version<"3.0"', 'future>=0.14.0; python_version<"3"', 'backports.functools_lru_cache; python_version<"3.2"', - 'jedi>=0.14.1', + 'jedi>=0.16.0', 'python-jsonrpc-server>=0.3.2', 'pluggy', 'ujson<=1.35; platform_system!="Windows"' From 551990f350532b8658dff76421ff234649fd3b7c Mon Sep 17 00:00:00 2001 From: bnavigator Date: Thu, 16 Apr 2020 11:48:17 +0200 Subject: [PATCH 06/23] don't expect isabs at first place sometimes jedi reports some keywords first --- test/plugins/test_completion.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index 57caa8b3..34ca9f55 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -58,7 +58,8 @@ def test_jedi_completion(config): items = pyls_jedi_completions(config, doc, com_position) assert items - assert items[0]['label'] == 'isabs(path)' + labels = [i['label'] for i in items] + assert 'isabs(path)' in labels # Test we don't throw with big character pyls_jedi_completions(config, doc, {'line': 1, 'character': 1000}) From afafa62b680a7f4762937b956bc2fee57126c56d Mon Sep 17 00:00:00 2001 From: bnavigator Date: Thu, 16 Apr 2020 12:28:53 +0200 Subject: [PATCH 07/23] check expected in all refs in builtin test --- test/plugins/test_references.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/plugins/test_references.py b/test/plugins/test_references.py index 7e7cbe75..2a897d68 100644 --- a/test/plugins/test_references.py +++ b/test/plugins/test_references.py @@ -75,5 +75,7 @@ def test_references_builtin(tmp_workspace): # pylint: disable=redefined-outer-n refs = pyls_references(doc2, position) assert len(refs) >= 1 - assert refs[0]['range']['start'] == {'line': 4, 'character': 7} - assert refs[0]['range']['end'] == {'line': 4, 'character': 19} + expected = {'start': {'line': 4, 'character': 7}, + 'end': {'line': 4, 'character': 19}} + ranges = [r['range'] for r in refs] + assert expected in ranges From 90e5d45cc11e46125aeda4da55c0dad475d4d556 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Thu, 16 Apr 2020 18:16:09 +0200 Subject: [PATCH 08/23] bump minimum jedi version to 0.17 --- pyls/_utils.py | 2 - pyls/plugins/hover.py | 65 +++++++++++++++------------------ pyls/workspace.py | 3 +- setup.py | 2 +- test/plugins/test_completion.py | 13 +------ test/plugins/test_hover.py | 28 ++++++-------- 6 files changed, 44 insertions(+), 69 deletions(-) diff --git a/pyls/_utils.py b/pyls/_utils.py index 478beda0..ada958de 100644 --- a/pyls/_utils.py +++ b/pyls/_utils.py @@ -140,8 +140,6 @@ def format_docstring(contents): """ contents = contents.replace('\t', u'\u00A0' * 4) contents = contents.replace(' ', u'\u00A0' * 2) - if LooseVersion(JEDI_VERSION) < LooseVersion('0.15.0'): - contents = contents.replace('*', '\\*') return contents diff --git a/pyls/plugins/hover.py b/pyls/plugins/hover.py index b8ff749d..1953d983 100644 --- a/pyls/plugins/hover.py +++ b/pyls/plugins/hover.py @@ -1,5 +1,5 @@ # Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion + import logging from pyls import hookimpl, _utils @@ -13,40 +13,33 @@ def pyls_hover(document, position): definitions = document.jedi_script().infer(**code_position) word = document.word_at_position(position) - if LooseVersion(_utils.JEDI_VERSION) >= LooseVersion('0.15.0'): - # Find first exact matching definition - definition = next((x for x in definitions if x.name == word), None) - - # Ensure a definition is used if only one is available - # even if the word doesn't match. An example of this case is 'np' - # where 'numpy' doesn't match with 'np'. Same for NumPy ufuncs - if len(definitions) == 1: - definition = definitions[0] - - if not definition: - return {'contents': ''} - - # raw docstring returns only doc, without signature - doc = _utils.format_docstring(definition.docstring(raw=True)) - - # Find first exact matching signature - signature = next((x.to_string() for x in definition.get_signatures() if x.name == word), '') - - contents = [] - if signature: - contents.append({ - 'language': 'python', - 'value': signature, - }) - if doc: - contents.append(doc) - if not contents: - return {'contents': ''} - return {'contents': contents} - else: - # Find an exact match for a completion - for d in definitions: - if d.name == word: - return {'contents': _utils.format_docstring(d.docstring()) or ''} + # Find first exact matching definition + definition = next((x for x in definitions if x.name == word), None) + + # Ensure a definition is used if only one is available + # even if the word doesn't match. An example of this case is 'np' + # where 'numpy' doesn't match with 'np'. Same for NumPy ufuncs + if len(definitions) == 1: + definition = definitions[0] + + if not definition: + return {'contents': ''} + # raw docstring returns only doc, without signature + doc = _utils.format_docstring(definition.docstring(raw=True)) + + # Find first exact matching signature + signature = next((x.to_string() for x in definition.get_signatures() + if x.name == word), '') + + contents = [] + if signature: + contents.append({ + 'language': 'python', + 'value': signature, + }) + if doc: + contents.append(doc) + if not contents: return {'contents': ''} + return {'contents': contents} diff --git a/pyls/workspace.py b/pyls/workspace.py index 8b31c56d..8e969e71 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -230,8 +230,7 @@ def jedi_script(self, position=None): environment = self.get_enviroment(environment_path) if environment_path else None kwargs = { - # 'source' is deprecated but 'code' was only introduced in 0.17.0 - 'source' if jedi.__version__ < "0.17.0" else 'code': self.source, + 'code': self.source, 'path': self.path, 'environment': environment, 'project': jedi.api.Project(os.path.dirname(self.path), diff --git a/setup.py b/setup.py index 1070065b..daec73f0 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ 'configparser; python_version<"3.0"', 'future>=0.14.0; python_version<"3"', 'backports.functools_lru_cache; python_version<"3.2"', - 'jedi>=0.16.0', + 'jedi>=0.17.0,<0.18.0', 'python-jsonrpc-server>=0.3.2', 'pluggy', 'ujson<=1.35; platform_system!="Windows"' diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index 34ca9f55..11d31055 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -134,16 +134,9 @@ def test_pyqt_completion(config): doc = Document(DOC_URI, doc_pyqt) completions = pyls_jedi_completions(config, doc, com_position) - # Test we don't throw an error for Jedi < 0.15.2 and get completions - # for Jedi 0.15.2+ - if LooseVersion(JEDI_VERSION) < LooseVersion('0.15.2'): - assert completions is None - else: - assert completions is not None + assert completions is not None -@pytest.mark.skipif(LooseVersion('0.15.0') <= LooseVersion(JEDI_VERSION) < LooseVersion('0.15.2'), - reason='This test fails with Jedi 0.15.0 and 0.15.1') def test_numpy_completions(config): doc_numpy = "import numpy as np; np." com_position = {'line': 0, 'character': len(doc_numpy)} @@ -154,8 +147,6 @@ def test_numpy_completions(config): assert any(['array' in i['label'] for i in items]) -@pytest.mark.skipif(LooseVersion('0.15.0') <= LooseVersion(JEDI_VERSION) < LooseVersion('0.15.2'), - reason='This test fails with Jedi 0.15.0 and 0.15.1') def test_pandas_completions(config): doc_pandas = "import pandas as pd; pd." com_position = {'line': 0, 'character': len(doc_pandas)} @@ -176,8 +167,6 @@ def test_matplotlib_completions(config): assert any(['plot' in i['label'] for i in items]) -@pytest.mark.skipif(LooseVersion(JEDI_VERSION) < LooseVersion('0.15.2'), - reason='This test fails with Jedi 0.15.1 or less') def test_snippets_completion(config): doc_snippets = 'from collections import defaultdict \na=defaultdict' com_position = {'line': 0, 'character': 35} diff --git a/test/plugins/test_hover.py b/test/plugins/test_hover.py index 4ae29cd9..2815f940 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -35,22 +35,21 @@ def test_numpy_hover(): doc = Document(DOC_URI, NUMPY_DOC) - if LooseVersion(_utils.JEDI_VERSION) >= LooseVersion('0.15.0'): - contents = '' - assert contents in pyls_hover(doc, no_hov_position)['contents'] + contents = '' + assert contents in pyls_hover(doc, no_hov_position)['contents'] - contents = 'NumPy\n=====\n\nProvides\n' - assert contents in pyls_hover(doc, numpy_hov_position_1)['contents'][0] + contents = 'NumPy\n=====\n\nProvides\n' + assert contents in pyls_hover(doc, numpy_hov_position_1)['contents'][0] - contents = 'NumPy\n=====\n\nProvides\n' - assert contents in pyls_hover(doc, numpy_hov_position_2)['contents'][0] + contents = 'NumPy\n=====\n\nProvides\n' + assert contents in pyls_hover(doc, numpy_hov_position_2)['contents'][0] - contents = 'NumPy\n=====\n\nProvides\n' - assert contents in pyls_hover(doc, numpy_hov_position_3)['contents'][0] + contents = 'NumPy\n=====\n\nProvides\n' + assert contents in pyls_hover(doc, numpy_hov_position_3)['contents'][0] - contents = 'Trigonometric sine, element-wise.\n\n' - assert contents in pyls_hover( - doc, numpy_sin_hov_position)['contents'][0] + contents = 'Trigonometric sine, element-wise.\n\n' + assert contents in pyls_hover( + doc, numpy_sin_hov_position)['contents'][0] def test_hover(): @@ -61,10 +60,7 @@ def test_hover(): doc = Document(DOC_URI, DOC) - if LooseVersion(_utils.JEDI_VERSION) >= LooseVersion('0.15.0'): - contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] - else: - contents = 'main()\n\nhello world' + contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] assert { 'contents': contents From c38ceb3bcb7510c68621a8797fcd8b57483bb821 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Thu, 16 Apr 2020 20:55:28 +0200 Subject: [PATCH 09/23] cleanup unused imports --- pyls/_utils.py | 1 - test/plugins/test_completion.py | 2 -- test/plugins/test_hover.py | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pyls/_utils.py b/pyls/_utils.py index ada958de..1d3b54ef 100644 --- a/pyls/_utils.py +++ b/pyls/_utils.py @@ -1,5 +1,4 @@ # Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion import functools import inspect import logging diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index 11d31055..e1441837 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -1,5 +1,4 @@ # Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion import os import sys @@ -7,7 +6,6 @@ import pytest from pyls import uris, lsp -from pyls._utils import JEDI_VERSION from pyls.workspace import Document from pyls.plugins.jedi_completion import pyls_completions as pyls_jedi_completions from pyls.plugins.rope_completion import pyls_completions as pyls_rope_completions diff --git a/test/plugins/test_hover.py b/test/plugins/test_hover.py index 2815f940..6e200fab 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -1,7 +1,6 @@ # Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion -from pyls import uris, _utils +from pyls import uris from pyls.plugins.hover import pyls_hover from pyls.workspace import Document From 47e25f7cebb309b47475cfa033ad0722a03d775d Mon Sep 17 00:00:00 2001 From: bnavigator Date: Sat, 18 Apr 2020 13:52:53 +0200 Subject: [PATCH 10/23] skip test_references_builtin for PY2 --- test/plugins/test_references.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/plugins/test_references.py b/test/plugins/test_references.py index 2a897d68..82d682a5 100644 --- a/test/plugins/test_references.py +++ b/test/plugins/test_references.py @@ -4,6 +4,7 @@ from pyls import uris from pyls.workspace import Document from pyls.plugins.references import pyls_references +from pyls._utils import PY2 DOC1_NAME = 'test1.py' @@ -66,6 +67,8 @@ def test_references(tmp_workspace): # pylint: disable=redefined-outer-name assert doc2_usage_ref['range']['end'] == {'line': 3, 'character': 9} +@pytest.mark.skipif(PY2, reason="Jedi sometimes fails while checking pylint " + "example files in the modules path") def test_references_builtin(tmp_workspace): # pylint: disable=redefined-outer-name # Over 'UnicodeError': position = {'line': 4, 'character': 7} From 688d4eeedf867c0a207f94af8b52c5da75f48364 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Wed, 29 Apr 2020 23:13:24 +0200 Subject: [PATCH 11/23] remove TypeError in _detail again Thanks for the review @E1k3 --- pyls/plugins/jedi_completion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index c8797539..443217ec 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -176,7 +176,7 @@ def _label(definition): def _detail(definition): try: return definition.parent().full_name or '' - except (AttributeError, TypeError): + except AttributeError: return definition.full_name or '' From e26bef5c0d840b6e71c216ee5e8b8fd332940fee Mon Sep 17 00:00:00 2001 From: bnavigator Date: Fri, 8 May 2020 12:35:44 +0200 Subject: [PATCH 12/23] cosmetics from review comments --- pyls/_utils.py | 11 ++++++++--- pyls/plugins/hover.py | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pyls/_utils.py b/pyls/_utils.py index 1d3b54ef..8abda246 100644 --- a/pyls/_utils.py +++ b/pyls/_utils.py @@ -143,14 +143,19 @@ def format_docstring(contents): def clip_column(column, lines, line_number): - # Normalise the position as per the LSP that accepts character positions > line length - # https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#position + """Normalise the position as per the LSP that accepts character positions > line length + + https://microsoft.github.io/language-server-protocol/specification#position + """ max_column = len(lines[line_number].rstrip('\r\n')) if len(lines) > line_number else 0 return min(column, max_column) def position_to_jedi_linecolumn(document, position): - """Convert the format 'line', 'character' to 'line', 'column'""" + """Convert the LSP format 'line', 'character' to Jedi's 'line', 'column' + + https://microsoft.github.io/language-server-protocol/specification#position + """ code_position = {} if position: code_position = {'line': position['line'] + 1, diff --git a/pyls/plugins/hover.py b/pyls/plugins/hover.py index 1953d983..9332a52d 100644 --- a/pyls/plugins/hover.py +++ b/pyls/plugins/hover.py @@ -38,8 +38,11 @@ def pyls_hover(document, position): 'language': 'python', 'value': signature, }) + if doc: contents.append(doc) + if not contents: return {'contents': ''} + return {'contents': contents} From 65322ada2fb63a31afc1863978feaa895acb52f0 Mon Sep 17 00:00:00 2001 From: bnavigator Date: Fri, 8 May 2020 12:38:23 +0200 Subject: [PATCH 13/23] remove try..catch of jedi completion. Handled by upstream now: davidhalter/jedi#1452 --- pyls/plugins/jedi_completion.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index 443217ec..7ef7d6af 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -50,17 +50,9 @@ @hookimpl def pyls_completions(config, document, position): - try: - code_position = _utils.position_to_jedi_linecolumn(document, position) - completions = document.jedi_script().complete(**code_position) - except AttributeError as e: - if 'CompiledObject' in str(e): - # Needed to handle missing CompiledObject attribute - # 'sub_modules_dict' - # TODO: probably not needed for new Complete objects - completions = None - else: - raise e + """Get formatted completions for current code position""" + code_position = _utils.position_to_jedi_linecolumn(document, position) + completions = document.jedi_script().complete(**code_position) if not completions: return None From 22211f27879becfd64c8607ed13404a5241a53fb Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 9 May 2020 20:20:41 +0200 Subject: [PATCH 14/23] minor comment change [skip ci] Co-authored-by: Carlos Cordoba --- pyls/workspace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index 8e969e71..0e51b61f 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -238,7 +238,7 @@ def jedi_script(self, position=None): } if position: - # deprecated by Jedi to use in Script() constructor + # Deprecated by Jedi to use in Script() constructor kwargs += _utils.position_to_jedi_linecolumn(self, position) return jedi.Script(**kwargs) From edf9a1ee4f0520d759b89ca4a6c102e81caa5a8d Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 13:29:38 -0500 Subject: [PATCH 15/23] Fix some style issues --- pyls/_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyls/_utils.py b/pyls/_utils.py index 8abda246..b1a3bd96 100644 --- a/pyls/_utils.py +++ b/pyls/_utils.py @@ -143,7 +143,8 @@ def format_docstring(contents): def clip_column(column, lines, line_number): - """Normalise the position as per the LSP that accepts character positions > line length + """ + Normalise the position as per the LSP that accepts character positions > line length https://microsoft.github.io/language-server-protocol/specification#position """ @@ -152,7 +153,8 @@ def clip_column(column, lines, line_number): def position_to_jedi_linecolumn(document, position): - """Convert the LSP format 'line', 'character' to Jedi's 'line', 'column' + """ + Convert the LSP format 'line', 'character' to Jedi's 'line', 'column' https://microsoft.github.io/language-server-protocol/specification#position """ From e174216b86d8aaa1efc15e4ebf535e5277c32ba6 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 9 May 2020 21:09:18 +0200 Subject: [PATCH 16/23] take project path from internal _workspace if available Taken from #801 --- pyls/workspace.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index 0e51b61f..b2eea203 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -229,12 +229,12 @@ def jedi_script(self, position=None): sys_path = self.sys_path(environment_path) + extra_paths environment = self.get_enviroment(environment_path) if environment_path else None + project_path = self._workspace.root_path if self._workspace else os.path.dirname(self.path) kwargs = { 'code': self.source, 'path': self.path, 'environment': environment, - 'project': jedi.api.Project(os.path.dirname(self.path), - sys_path=sys_path), + 'project': jedi.Project(path=project_path, sys_path=sys_path), } if position: From 1ad6229fe85f8bc1e58d53a7adc9ee9d9d4d8a4a Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Sat, 9 May 2020 21:29:33 +0200 Subject: [PATCH 17/23] test for root_path attribute in jedi_script() --- pyls/workspace.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index b2eea203..aa34ff63 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -226,10 +226,15 @@ def jedi_script(self, position=None): environment_path = jedi_settings.get('environment') extra_paths = jedi_settings.get('extra_paths') or [] - sys_path = self.sys_path(environment_path) + extra_paths environment = self.get_enviroment(environment_path) if environment_path else None - project_path = self._workspace.root_path if self._workspace else os.path.dirname(self.path) + if hasattr(self._workspace, 'root_path'): + project_path = self._workspace.root_path + else: + project_path = os.path.dirname(self.path) + + sys_path = self.sys_path(environment_path) + extra_paths + kwargs = { 'code': self.source, 'path': self.path, From 56a4be5fab31ff4d1a7c48e15d659a9a28d5dfc6 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 15:04:59 -0500 Subject: [PATCH 18/23] Always use workspace.root_path for Jedi's project path --- pyls/workspace.py | 7 +------ test/plugins/test_completion.py | 30 +++++++++++++++--------------- test/test_utils.py | 3 +++ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index aa34ff63..1db33aee 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -227,13 +227,8 @@ def jedi_script(self, position=None): extra_paths = jedi_settings.get('extra_paths') or [] environment = self.get_enviroment(environment_path) if environment_path else None - - if hasattr(self._workspace, 'root_path'): - project_path = self._workspace.root_path - else: - project_path = os.path.dirname(self.path) - sys_path = self.sys_path(environment_path) + extra_paths + project_path = self._workspace.root_path kwargs = { 'code': self.source, diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index e1441837..83fe916e 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -52,7 +52,7 @@ def test_rope_import_completion(config, workspace): def test_jedi_completion(config): # Over 'i' in os.path.isabs(...) com_position = {'line': 1, 'character': 15} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -77,7 +77,7 @@ def test_rope_completion(config, workspace): def test_jedi_completion_ordering(config): # Over the blank line com_position = {'line': 8, 'character': 0} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) completions = pyls_jedi_completions(config, doc, com_position) items = {c['label']: c['sortText'] for c in completions} @@ -89,7 +89,7 @@ def test_jedi_completion_ordering(config): def test_jedi_property_completion(config): # Over the 'w' in 'print Hello().world' com_position = {'line': 18, 'character': 15} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) completions = pyls_jedi_completions(config, doc, com_position) items = {c['label']: c['sortText'] for c in completions} @@ -101,7 +101,7 @@ def test_jedi_property_completion(config): def test_jedi_method_completion(config): # Over the 'y' in 'print Hello().every' com_position = {'line': 20, 'character': 19} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) config.capabilities['textDocument'] = {'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -129,7 +129,7 @@ def test_pyqt_completion(config): # Over 'QA' in 'from PyQt5.QtWidgets import QApplication' doc_pyqt = "from PyQt5.QtWidgets import QA" com_position = {'line': 0, 'character': len(doc_pyqt)} - doc = Document(DOC_URI, doc_pyqt) + doc = Document(DOC_URI, doc_pyqt, workspace=MockWorkspace()) completions = pyls_jedi_completions(config, doc, com_position) assert completions is not None @@ -138,7 +138,7 @@ def test_pyqt_completion(config): def test_numpy_completions(config): doc_numpy = "import numpy as np; np." com_position = {'line': 0, 'character': len(doc_numpy)} - doc = Document(DOC_URI, doc_numpy) + doc = Document(DOC_URI, doc_numpy, workspace=MockWorkspace()) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -148,7 +148,7 @@ def test_numpy_completions(config): def test_pandas_completions(config): doc_pandas = "import pandas as pd; pd." com_position = {'line': 0, 'character': len(doc_pandas)} - doc = Document(DOC_URI, doc_pandas) + doc = Document(DOC_URI, doc_pandas, workspace=MockWorkspace()) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -158,7 +158,7 @@ def test_pandas_completions(config): def test_matplotlib_completions(config): doc_mpl = "import matplotlib.pyplot as plt; plt." com_position = {'line': 0, 'character': len(doc_mpl)} - doc = Document(DOC_URI, doc_mpl) + doc = Document(DOC_URI, doc_mpl, workspace=MockWorkspace()) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -168,7 +168,7 @@ def test_matplotlib_completions(config): def test_snippets_completion(config): doc_snippets = 'from collections import defaultdict \na=defaultdict' com_position = {'line': 0, 'character': 35} - doc = Document(DOC_URI, doc_snippets) + doc = Document(DOC_URI, doc_snippets, workspace=MockWorkspace()) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -183,7 +183,7 @@ def test_snippets_completion(config): def test_snippet_parsing(config): doc = 'import numpy as np\nnp.logical_and' completion_position = {'line': 1, 'character': 14} - doc = Document(DOC_URI, doc) + doc = Document(DOC_URI, doc, workspace=MockWorkspace()) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -194,7 +194,7 @@ def test_snippet_parsing(config): def test_multiline_import_snippets(config): document = 'from datetime import(\n date,\n datetime)\na=date' - doc = Document(DOC_URI, document) + doc = Document(DOC_URI, document, workspace=MockWorkspace()) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -210,7 +210,7 @@ def test_multiline_import_snippets(config): def test_multiline_snippets(config): document = 'from datetime import\\\n date,\\\n datetime \na=date' - doc = Document(DOC_URI, document) + doc = Document(DOC_URI, document, workspace=MockWorkspace()) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -230,13 +230,13 @@ def test_multistatement_snippet(config): config.update({'plugins': {'jedi_completion': {'include_params': True}}}) document = 'a = 1; from datetime import date' - doc = Document(DOC_URI, document) + doc = Document(DOC_URI, document, workspace=MockWorkspace()) position = {'line': 0, 'character': len(document)} completions = pyls_jedi_completions(config, doc, position) assert completions[0]['insertText'] == 'date' document = 'from datetime import date; a = date' - doc = Document(DOC_URI, document) + doc = Document(DOC_URI, document, workspace=MockWorkspace()) position = {'line': 0, 'character': len(document)} completions = pyls_jedi_completions(config, doc, position) assert completions[0]['insertText'] == 'date(${1:year}, ${2:month}, ${3:day})$0' @@ -256,7 +256,7 @@ def spam(): # Content of doc to test completion doc_content = """import foo foo.s""" - doc = Document(DOC_URI, doc_content) + doc = Document(DOC_URI, doc_content, workspace=MockWorkspace()) # After 'foo.s' without extra paths com_position = {'line': 1, 'character': 5} diff --git a/test/test_utils.py b/test/test_utils.py index d27f24ba..e6f6e56a 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -17,6 +17,9 @@ def __init__(self): # This is to avoid pyling tests of the variable not being used sys.stdout.write(str(self._environments)) + # This necessary for the new Jedi 0.17+ API. + self.root_path = '' + def test_debounce(): interval = 0.1 From 7debe28e92bb319ec5d00f07cc03d5a91e1f1e25 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 15:39:24 -0500 Subject: [PATCH 19/23] Use the workspace fixture to fix failing tests --- test/plugins/test_completion.py | 61 ++++++++++++++++---------------- test/plugins/test_definitions.py | 12 +++---- test/plugins/test_highlight.py | 8 ++--- test/plugins/test_hover.py | 8 ++--- test/plugins/test_references.py | 6 ++-- test/plugins/test_signature.py | 12 +++---- test/plugins/test_symbols.py | 8 ++--- 7 files changed, 59 insertions(+), 56 deletions(-) diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index 83fe916e..0fbb7631 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -2,7 +2,6 @@ import os import sys -from test.test_utils import MockWorkspace import pytest from pyls import uris, lsp @@ -10,6 +9,8 @@ from pyls.plugins.jedi_completion import pyls_completions as pyls_jedi_completions from pyls.plugins.rope_completion import pyls_completions as pyls_rope_completions +from test.test_utils import MockWorkspace + PY2 = sys.version[0] == '2' LINUX = sys.platform.startswith('linux') @@ -49,10 +50,10 @@ def test_rope_import_completion(config, workspace): assert items is None -def test_jedi_completion(config): +def test_jedi_completion(config, workspace): # Over 'i' in os.path.isabs(...) com_position = {'line': 1, 'character': 15} - doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) + doc = Document(DOC_URI, DOC, workspace=workspace) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -74,10 +75,10 @@ def test_rope_completion(config, workspace): assert items[0]['label'] == 'isabs' -def test_jedi_completion_ordering(config): +def test_jedi_completion_ordering(config, workspace): # Over the blank line com_position = {'line': 8, 'character': 0} - doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) + doc = Document(DOC_URI, DOC, workspace=workspace) completions = pyls_jedi_completions(config, doc, com_position) items = {c['label']: c['sortText'] for c in completions} @@ -86,10 +87,10 @@ def test_jedi_completion_ordering(config): assert items['hello()'] < items['_a_hello()'] -def test_jedi_property_completion(config): +def test_jedi_property_completion(config, workspace): # Over the 'w' in 'print Hello().world' com_position = {'line': 18, 'character': 15} - doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) + doc = Document(DOC_URI, DOC, workspace=workspace) completions = pyls_jedi_completions(config, doc, com_position) items = {c['label']: c['sortText'] for c in completions} @@ -98,10 +99,10 @@ def test_jedi_property_completion(config): assert 'world' in list(items.keys())[0] -def test_jedi_method_completion(config): +def test_jedi_method_completion(config, workspace): # Over the 'y' in 'print Hello().every' com_position = {'line': 20, 'character': 19} - doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) + doc = Document(DOC_URI, DOC, workspace=workspace) config.capabilities['textDocument'] = {'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -125,50 +126,50 @@ def test_jedi_method_completion(config): @pytest.mark.skipif(PY2 or (sys.platform.startswith('linux') and os.environ.get('CI') is not None), reason="Test in Python 3 and not on CIs on Linux because wheels don't work on them.") -def test_pyqt_completion(config): +def test_pyqt_completion(config, workspace): # Over 'QA' in 'from PyQt5.QtWidgets import QApplication' doc_pyqt = "from PyQt5.QtWidgets import QA" com_position = {'line': 0, 'character': len(doc_pyqt)} - doc = Document(DOC_URI, doc_pyqt, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc_pyqt, workspace=workspace) completions = pyls_jedi_completions(config, doc, com_position) assert completions is not None -def test_numpy_completions(config): +def test_numpy_completions(config, workspace): doc_numpy = "import numpy as np; np." com_position = {'line': 0, 'character': len(doc_numpy)} - doc = Document(DOC_URI, doc_numpy, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc_numpy, workspace=workspace) items = pyls_jedi_completions(config, doc, com_position) assert items assert any(['array' in i['label'] for i in items]) -def test_pandas_completions(config): +def test_pandas_completions(config, workspace): doc_pandas = "import pandas as pd; pd." com_position = {'line': 0, 'character': len(doc_pandas)} - doc = Document(DOC_URI, doc_pandas, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc_pandas, workspace=workspace) items = pyls_jedi_completions(config, doc, com_position) assert items assert any(['DataFrame' in i['label'] for i in items]) -def test_matplotlib_completions(config): +def test_matplotlib_completions(config, workspace): doc_mpl = "import matplotlib.pyplot as plt; plt." com_position = {'line': 0, 'character': len(doc_mpl)} - doc = Document(DOC_URI, doc_mpl, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc_mpl, workspace=workspace) items = pyls_jedi_completions(config, doc, com_position) assert items assert any(['plot' in i['label'] for i in items]) -def test_snippets_completion(config): +def test_snippets_completion(config, workspace): doc_snippets = 'from collections import defaultdict \na=defaultdict' com_position = {'line': 0, 'character': 35} - doc = Document(DOC_URI, doc_snippets, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc_snippets, workspace=workspace) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -180,10 +181,10 @@ def test_snippets_completion(config): assert completions[0]['insertText'] == 'defaultdict($0)' -def test_snippet_parsing(config): +def test_snippet_parsing(config, workspace): doc = 'import numpy as np\nnp.logical_and' completion_position = {'line': 1, 'character': 14} - doc = Document(DOC_URI, doc, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc, workspace=workspace) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -192,9 +193,9 @@ def test_snippet_parsing(config): assert completions[0]['insertText'] == out -def test_multiline_import_snippets(config): +def test_multiline_import_snippets(config, workspace): document = 'from datetime import(\n date,\n datetime)\na=date' - doc = Document(DOC_URI, document, workspace=MockWorkspace()) + doc = Document(DOC_URI, document, workspace=workspace) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -208,9 +209,9 @@ def test_multiline_import_snippets(config): assert completions[0]['insertText'] == 'datetime' -def test_multiline_snippets(config): +def test_multiline_snippets(config, workspace): document = 'from datetime import\\\n date,\\\n datetime \na=date' - doc = Document(DOC_URI, document, workspace=MockWorkspace()) + doc = Document(DOC_URI, document, workspace=workspace) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -224,25 +225,25 @@ def test_multiline_snippets(config): assert completions[0]['insertText'] == 'datetime' -def test_multistatement_snippet(config): +def test_multistatement_snippet(config, workspace): config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) document = 'a = 1; from datetime import date' - doc = Document(DOC_URI, document, workspace=MockWorkspace()) + doc = Document(DOC_URI, document, workspace=workspace) position = {'line': 0, 'character': len(document)} completions = pyls_jedi_completions(config, doc, position) assert completions[0]['insertText'] == 'date' document = 'from datetime import date; a = date' - doc = Document(DOC_URI, document, workspace=MockWorkspace()) + doc = Document(DOC_URI, document, workspace=workspace) position = {'line': 0, 'character': len(document)} completions = pyls_jedi_completions(config, doc, position) assert completions[0]['insertText'] == 'date(${1:year}, ${2:month}, ${3:day})$0' -def test_jedi_completion_extra_paths(config, tmpdir): +def test_jedi_completion_extra_paths(config, tmpdir, workspace): # Create a tempfile with some content and pass to extra_paths temp_doc_content = ''' def spam(): @@ -256,7 +257,7 @@ def spam(): # Content of doc to test completion doc_content = """import foo foo.s""" - doc = Document(DOC_URI, doc_content, workspace=MockWorkspace()) + doc = Document(DOC_URI, doc_content, workspace=workspace) # After 'foo.s' without extra paths com_position = {'line': 1, 'character': 5} diff --git a/test/plugins/test_definitions.py b/test/plugins/test_definitions.py index e2db9c6f..f4fa97c6 100644 --- a/test/plugins/test_definitions.py +++ b/test/plugins/test_definitions.py @@ -20,7 +20,7 @@ def add_member(self, id, name): """ -def test_definitions(config): +def test_definitions(config, workspace): # Over 'a' in print a cursor_pos = {'line': 3, 'character': 6} @@ -30,20 +30,20 @@ def test_definitions(config): 'end': {'line': 0, 'character': 5} } - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) -def test_builtin_definition(config): +def test_builtin_definition(config, workspace): # Over 'i' in dict cursor_pos = {'line': 8, 'character': 24} # No go-to def for builtins - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) assert not pyls_definitions(config, doc, cursor_pos) -def test_assignment(config): +def test_assignment(config, workspace): # Over 's' in self.members[id] cursor_pos = {'line': 11, 'character': 19} @@ -53,5 +53,5 @@ def test_assignment(config): 'end': {'line': 8, 'character': 20} } - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) diff --git a/test/plugins/test_highlight.py b/test/plugins/test_highlight.py index 41e9075b..9860d3be 100644 --- a/test/plugins/test_highlight.py +++ b/test/plugins/test_highlight.py @@ -10,11 +10,11 @@ """ -def test_highlight(): +def test_highlight(workspace): # Over 'a' in a.startswith cursor_pos = {'line': 1, 'character': 0} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) assert pyls_document_highlight(doc, cursor_pos) == [{ 'range': { 'start': {'line': 0, 'character': 0}, @@ -37,10 +37,10 @@ def test_highlight(): ''' -def test_sys_highlight(): +def test_sys_highlight(workspace): cursor_pos = {'line': 0, 'character': 8} - doc = Document(DOC_URI, SYS_DOC) + doc = Document(DOC_URI, SYS_DOC, workspace=workspace) assert pyls_document_highlight(doc, cursor_pos) == [{ 'range': { 'start': {'line': 0, 'character': 7}, diff --git a/test/plugins/test_hover.py b/test/plugins/test_hover.py index 6e200fab..0877e2ee 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -20,7 +20,7 @@ def main(): """ -def test_numpy_hover(): +def test_numpy_hover(workspace): # Over the blank line no_hov_position = {'line': 1, 'character': 0} # Over 'numpy' in import numpy as np @@ -32,7 +32,7 @@ def test_numpy_hover(): # Over 'sin' in np.sin numpy_sin_hov_position = {'line': 3, 'character': 4} - doc = Document(DOC_URI, NUMPY_DOC) + doc = Document(DOC_URI, NUMPY_DOC, workspace=workspace) contents = '' assert contents in pyls_hover(doc, no_hov_position)['contents'] @@ -51,13 +51,13 @@ def test_numpy_hover(): doc, numpy_sin_hov_position)['contents'][0] -def test_hover(): +def test_hover(workspace): # Over 'main' in def main(): hov_position = {'line': 2, 'character': 6} # Over the blank second line no_hov_position = {'line': 1, 'character': 0} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] diff --git a/test/plugins/test_references.py b/test/plugins/test_references.py index 82d682a5..4ad7c111 100644 --- a/test/plugins/test_references.py +++ b/test/plugins/test_references.py @@ -1,6 +1,8 @@ # Copyright 2017 Palantir Technologies, Inc. import os + import pytest + from pyls import uris from pyls.workspace import Document from pyls.plugins.references import pyls_references @@ -41,7 +43,7 @@ def test_references(tmp_workspace): # pylint: disable=redefined-outer-name # Over 'Test1' in class Test1(): position = {'line': 0, 'character': 8} DOC1_URI = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC1_NAME)) - doc1 = Document(DOC1_URI) + doc1 = Document(DOC1_URI, workspace=tmp_workspace) refs = pyls_references(doc1, position) @@ -73,7 +75,7 @@ def test_references_builtin(tmp_workspace): # pylint: disable=redefined-outer-n # Over 'UnicodeError': position = {'line': 4, 'character': 7} doc2_uri = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC2_NAME)) - doc2 = Document(doc2_uri) + doc2 = Document(doc2_uri, workspace=tmp_workspace) refs = pyls_references(doc2, position) assert len(refs) >= 1 diff --git a/test/plugins/test_signature.py b/test/plugins/test_signature.py index 01a439a2..e1cdd31b 100644 --- a/test/plugins/test_signature.py +++ b/test/plugins/test_signature.py @@ -39,19 +39,19 @@ def main(param1=None, """ -def test_no_signature(): +def test_no_signature(workspace): # Over blank line sig_position = {'line': 9, 'character': 0} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) sigs = signature.pyls_signature_help(doc, sig_position)['signatures'] assert not sigs -def test_signature(): +def test_signature(workspace): # Over '( ' in main( sig_position = {'line': 10, 'character': 5} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, DOC, workspace=workspace) sig_info = signature.pyls_signature_help(doc, sig_position) @@ -64,10 +64,10 @@ def test_signature(): assert sig_info['activeParameter'] == 0 -def test_multi_line_signature(): +def test_multi_line_signature(workspace): # Over '( ' in main( sig_position = {'line': 17, 'character': 5} - doc = Document(DOC_URI, MULTI_LINE_DOC) + doc = Document(DOC_URI, MULTI_LINE_DOC, workspace=workspace) sig_info = signature.pyls_signature_help(doc, sig_position) diff --git a/test/plugins/test_symbols.py b/test/plugins/test_symbols.py index fa6f7df1..0923a756 100644 --- a/test/plugins/test_symbols.py +++ b/test/plugins/test_symbols.py @@ -48,8 +48,8 @@ def sym(name): assert sym('a')['location']['range']['start'] == {'line': 2, 'character': 0} -def test_symbols(config): - doc = Document(DOC_URI, DOC) +def test_symbols(config, workspace): + doc = Document(DOC_URI, DOC, workspace=workspace) config.update({'plugins': {'jedi_symbols': {'all_scopes': False}}}) symbols = pyls_document_symbols(config, doc) @@ -73,8 +73,8 @@ def sym(name): assert sym('main')['location']['range']['end'] == {'line': 12, 'character': 0} -def test_symbols_all_scopes(config): - doc = Document(DOC_URI, DOC) +def test_symbols_all_scopes(config, workspace): + doc = Document(DOC_URI, DOC, workspace=workspace) symbols = pyls_document_symbols(config, doc) helper_check_symbols_all_scope(symbols) From a079d7fe4b48f962e0cfd5d79b0c9e2d93a1f6f5 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 15:44:04 -0500 Subject: [PATCH 20/23] Fix style issue --- test/plugins/test_completion.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index 0fbb7631..bcdf44fd 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -2,6 +2,7 @@ import os import sys +from test.test_utils import MockWorkspace import pytest from pyls import uris, lsp @@ -9,8 +10,6 @@ from pyls.plugins.jedi_completion import pyls_completions as pyls_jedi_completions from pyls.plugins.rope_completion import pyls_completions as pyls_rope_completions -from test.test_utils import MockWorkspace - PY2 = sys.version[0] == '2' LINUX = sys.platform.startswith('linux') From 9026ea888ad2d031a841d94166d96c795a42aacc Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 17:02:13 -0500 Subject: [PATCH 21/23] Make workspace a required argument for the Document class --- pyls/workspace.py | 4 ++-- test/fixtures.py | 4 ++-- test/plugins/test_autopep8_format.py | 12 +++++----- test/plugins/test_completion.py | 34 +++++++++++++-------------- test/plugins/test_definitions.py | 6 ++--- test/plugins/test_flake8_lint.py | 9 ++++--- test/plugins/test_folding.py | 8 +++---- test/plugins/test_highlight.py | 4 ++-- test/plugins/test_hover.py | 4 ++-- test/plugins/test_mccabe_lint.py | 8 +++---- test/plugins/test_pycodestyle_lint.py | 4 ++-- test/plugins/test_pydocstyle_lint.py | 16 ++++++------- test/plugins/test_pyflakes_lint.py | 16 ++++++------- test/plugins/test_pylint_lint.py | 11 +++++---- test/plugins/test_references.py | 4 ++-- test/plugins/test_rope_rename.py | 2 +- test/plugins/test_signature.py | 6 ++--- test/plugins/test_symbols.py | 6 ++--- test/plugins/test_yapf_format.py | 16 ++++++------- test/test_document.py | 22 ++++++++--------- 20 files changed, 100 insertions(+), 96 deletions(-) diff --git a/pyls/workspace.py b/pyls/workspace.py index 1db33aee..974dfb29 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -112,8 +112,8 @@ def _create_document(self, doc_uri, source=None, version=None): class Document(object): - def __init__(self, uri, source=None, version=None, local=True, extra_sys_path=None, rope_project_builder=None, - config=None, workspace=None): + def __init__(self, uri, workspace, source=None, version=None, local=True, extra_sys_path=None, + rope_project_builder=None, config=None): self.uri = uri self.version = version self.path = uris.to_fs_path(uri) diff --git a/test/fixtures.py b/test/fixtures.py index 4e915e17..764b3d13 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -48,5 +48,5 @@ def config(workspace): # pylint: disable=redefined-outer-name @pytest.fixture -def doc(): - return Document(DOC_URI, DOC) +def doc(workspace): + return Document(DOC_URI, workspace, DOC) diff --git a/test/plugins/test_autopep8_format.py b/test/plugins/test_autopep8_format.py index 09c769ae..8138952d 100644 --- a/test/plugins/test_autopep8_format.py +++ b/test/plugins/test_autopep8_format.py @@ -16,16 +16,16 @@ def func(): GOOD_DOC = """A = ['hello', 'world']\n""" -def test_format(config): - doc = Document(DOC_URI, DOC) +def test_format(config, workspace): + doc = Document(DOC_URI, workspace, DOC) res = pyls_format_document(config, doc) assert len(res) == 1 assert res[0]['newText'] == "a = 123\n\n\ndef func():\n pass\n" -def test_range_format(config): - doc = Document(DOC_URI, DOC) +def test_range_format(config, workspace): + doc = Document(DOC_URI, workspace, DOC) def_range = { 'start': {'line': 0, 'character': 0}, @@ -39,6 +39,6 @@ def test_range_format(config): assert res[0]['newText'] == "a = 123\n\n\n\n\ndef func():\n pass\n" -def test_no_change(config): - doc = Document(DOC_URI, GOOD_DOC) +def test_no_change(config, workspace): + doc = Document(DOC_URI, workspace, GOOD_DOC) assert not pyls_format_document(config, doc) diff --git a/test/plugins/test_completion.py b/test/plugins/test_completion.py index bcdf44fd..6983d796 100644 --- a/test/plugins/test_completion.py +++ b/test/plugins/test_completion.py @@ -44,7 +44,7 @@ def everyone(self, a, b, c=None, d=2): def test_rope_import_completion(config, workspace): com_position = {'line': 0, 'character': 7} - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, workspace, DOC) items = pyls_rope_completions(config, workspace, doc, com_position) assert items is None @@ -52,7 +52,7 @@ def test_rope_import_completion(config, workspace): def test_jedi_completion(config, workspace): # Over 'i' in os.path.isabs(...) com_position = {'line': 1, 'character': 15} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -77,7 +77,7 @@ def test_rope_completion(config, workspace): def test_jedi_completion_ordering(config, workspace): # Over the blank line com_position = {'line': 8, 'character': 0} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) completions = pyls_jedi_completions(config, doc, com_position) items = {c['label']: c['sortText'] for c in completions} @@ -89,7 +89,7 @@ def test_jedi_completion_ordering(config, workspace): def test_jedi_property_completion(config, workspace): # Over the 'w' in 'print Hello().world' com_position = {'line': 18, 'character': 15} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) completions = pyls_jedi_completions(config, doc, com_position) items = {c['label']: c['sortText'] for c in completions} @@ -101,7 +101,7 @@ def test_jedi_property_completion(config, workspace): def test_jedi_method_completion(config, workspace): # Over the 'y' in 'print Hello().every' com_position = {'line': 20, 'character': 19} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) config.capabilities['textDocument'] = {'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -129,7 +129,7 @@ def test_pyqt_completion(config, workspace): # Over 'QA' in 'from PyQt5.QtWidgets import QApplication' doc_pyqt = "from PyQt5.QtWidgets import QA" com_position = {'line': 0, 'character': len(doc_pyqt)} - doc = Document(DOC_URI, doc_pyqt, workspace=workspace) + doc = Document(DOC_URI, workspace, doc_pyqt) completions = pyls_jedi_completions(config, doc, com_position) assert completions is not None @@ -138,7 +138,7 @@ def test_pyqt_completion(config, workspace): def test_numpy_completions(config, workspace): doc_numpy = "import numpy as np; np." com_position = {'line': 0, 'character': len(doc_numpy)} - doc = Document(DOC_URI, doc_numpy, workspace=workspace) + doc = Document(DOC_URI, workspace, doc_numpy) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -148,7 +148,7 @@ def test_numpy_completions(config, workspace): def test_pandas_completions(config, workspace): doc_pandas = "import pandas as pd; pd." com_position = {'line': 0, 'character': len(doc_pandas)} - doc = Document(DOC_URI, doc_pandas, workspace=workspace) + doc = Document(DOC_URI, workspace, doc_pandas) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -158,7 +158,7 @@ def test_pandas_completions(config, workspace): def test_matplotlib_completions(config, workspace): doc_mpl = "import matplotlib.pyplot as plt; plt." com_position = {'line': 0, 'character': len(doc_mpl)} - doc = Document(DOC_URI, doc_mpl, workspace=workspace) + doc = Document(DOC_URI, workspace, doc_mpl) items = pyls_jedi_completions(config, doc, com_position) assert items @@ -168,7 +168,7 @@ def test_matplotlib_completions(config, workspace): def test_snippets_completion(config, workspace): doc_snippets = 'from collections import defaultdict \na=defaultdict' com_position = {'line': 0, 'character': 35} - doc = Document(DOC_URI, doc_snippets, workspace=workspace) + doc = Document(DOC_URI, workspace, doc_snippets) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -183,7 +183,7 @@ def test_snippets_completion(config, workspace): def test_snippet_parsing(config, workspace): doc = 'import numpy as np\nnp.logical_and' completion_position = {'line': 1, 'character': 14} - doc = Document(DOC_URI, doc, workspace=workspace) + doc = Document(DOC_URI, workspace, doc) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -194,7 +194,7 @@ def test_snippet_parsing(config, workspace): def test_multiline_import_snippets(config, workspace): document = 'from datetime import(\n date,\n datetime)\na=date' - doc = Document(DOC_URI, document, workspace=workspace) + doc = Document(DOC_URI, workspace, document) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -210,7 +210,7 @@ def test_multiline_import_snippets(config, workspace): def test_multiline_snippets(config, workspace): document = 'from datetime import\\\n date,\\\n datetime \na=date' - doc = Document(DOC_URI, document, workspace=workspace) + doc = Document(DOC_URI, workspace, document) config.capabilities['textDocument'] = { 'completion': {'completionItem': {'snippetSupport': True}}} config.update({'plugins': {'jedi_completion': {'include_params': True}}}) @@ -230,13 +230,13 @@ def test_multistatement_snippet(config, workspace): config.update({'plugins': {'jedi_completion': {'include_params': True}}}) document = 'a = 1; from datetime import date' - doc = Document(DOC_URI, document, workspace=workspace) + doc = Document(DOC_URI, workspace, document) position = {'line': 0, 'character': len(document)} completions = pyls_jedi_completions(config, doc, position) assert completions[0]['insertText'] == 'date' document = 'from datetime import date; a = date' - doc = Document(DOC_URI, document, workspace=workspace) + doc = Document(DOC_URI, workspace, document) position = {'line': 0, 'character': len(document)} completions = pyls_jedi_completions(config, doc, position) assert completions[0]['insertText'] == 'date(${1:year}, ${2:month}, ${3:day})$0' @@ -256,7 +256,7 @@ def spam(): # Content of doc to test completion doc_content = """import foo foo.s""" - doc = Document(DOC_URI, doc_content, workspace=workspace) + doc = Document(DOC_URI, workspace, doc_content) # After 'foo.s' without extra paths com_position = {'line': 1, 'character': 5} @@ -278,7 +278,7 @@ def test_jedi_completion_environment(config): # Content of doc to test completion doc_content = '''import logh ''' - doc = Document(DOC_URI, doc_content, workspace=MockWorkspace()) + doc = Document(DOC_URI, MockWorkspace(), doc_content) # After 'import logh' with default environment com_position = {'line': 0, 'character': 11} diff --git a/test/plugins/test_definitions.py b/test/plugins/test_definitions.py index f4fa97c6..660741f6 100644 --- a/test/plugins/test_definitions.py +++ b/test/plugins/test_definitions.py @@ -30,7 +30,7 @@ def test_definitions(config, workspace): 'end': {'line': 0, 'character': 5} } - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) @@ -39,7 +39,7 @@ def test_builtin_definition(config, workspace): cursor_pos = {'line': 8, 'character': 24} # No go-to def for builtins - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) assert not pyls_definitions(config, doc, cursor_pos) @@ -53,5 +53,5 @@ def test_assignment(config, workspace): 'end': {'line': 8, 'character': 20} } - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) diff --git a/test/plugins/test_flake8_lint.py b/test/plugins/test_flake8_lint.py index d4858f8e..9fdbb6a4 100644 --- a/test/plugins/test_flake8_lint.py +++ b/test/plugins/test_flake8_lint.py @@ -3,10 +3,13 @@ import os from mock import patch +from test.test_utils import MockWorkspace + from pyls import lsp, uris from pyls.plugins import flake8_lint from pyls.workspace import Document + DOC_URI = uris.from_fs_path(__file__) DOC = """import pyls @@ -23,16 +26,16 @@ def temp_document(doc_text): name = temp_file.name temp_file.write(doc_text) temp_file.close() - doc = Document(uris.from_fs_path(name)) + doc = Document(uris.from_fs_path(name), MockWorkspace()) return name, doc -def test_flake8_no_checked_file(config): +def test_flake8_no_checked_file(config, workspace): # A bad uri or a non-saved file may cause the flake8 linter to do nothing. # In this situtation, the linter will return an empty list. - doc = Document('', DOC) + doc = Document('', DOC, workspace) diags = flake8_lint.pyls_lint(config, doc) assert diags == [] diff --git a/test/plugins/test_folding.py b/test/plugins/test_folding.py index ec6dd316..05f0cdd8 100644 --- a/test/plugins/test_folding.py +++ b/test/plugins/test_folding.py @@ -111,8 +111,8 @@ class A(: """) -def test_folding(): - doc = Document(DOC_URI, DOC) +def test_folding(workspace): + doc = Document(DOC_URI, workspace, DOC) ranges = pyls_folding_range(doc) expected = [{'startLine': 1, 'endLine': 6}, {'startLine': 2, 'endLine': 3}, @@ -149,8 +149,8 @@ def test_folding(): assert ranges == expected -def test_folding_syntax_error(): - doc = Document(DOC_URI, SYNTAX_ERR) +def test_folding_syntax_error(workspace): + doc = Document(DOC_URI, workspace, SYNTAX_ERR) ranges = pyls_folding_range(doc) expected = [{'startLine': 1, 'endLine': 6}, {'startLine': 2, 'endLine': 3}, diff --git a/test/plugins/test_highlight.py b/test/plugins/test_highlight.py index 9860d3be..40bf52f2 100644 --- a/test/plugins/test_highlight.py +++ b/test/plugins/test_highlight.py @@ -14,7 +14,7 @@ def test_highlight(workspace): # Over 'a' in a.startswith cursor_pos = {'line': 1, 'character': 0} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) assert pyls_document_highlight(doc, cursor_pos) == [{ 'range': { 'start': {'line': 0, 'character': 0}, @@ -40,7 +40,7 @@ def test_highlight(workspace): def test_sys_highlight(workspace): cursor_pos = {'line': 0, 'character': 8} - doc = Document(DOC_URI, SYS_DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, SYS_DOC) assert pyls_document_highlight(doc, cursor_pos) == [{ 'range': { 'start': {'line': 0, 'character': 7}, diff --git a/test/plugins/test_hover.py b/test/plugins/test_hover.py index 0877e2ee..2302b865 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -32,7 +32,7 @@ def test_numpy_hover(workspace): # Over 'sin' in np.sin numpy_sin_hov_position = {'line': 3, 'character': 4} - doc = Document(DOC_URI, NUMPY_DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, NUMPY_DOC) contents = '' assert contents in pyls_hover(doc, no_hov_position)['contents'] @@ -57,7 +57,7 @@ def test_hover(workspace): # Over the blank second line no_hov_position = {'line': 1, 'character': 0} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] diff --git a/test/plugins/test_mccabe_lint.py b/test/plugins/test_mccabe_lint.py index e5bc27f4..6fa4f0bf 100644 --- a/test/plugins/test_mccabe_lint.py +++ b/test/plugins/test_mccabe_lint.py @@ -12,11 +12,11 @@ \tpass""" -def test_mccabe(config): +def test_mccabe(config, workspace): old_settings = config.settings try: config.update({'plugins': {'mccabe': {'threshold': 1}}}) - doc = Document(DOC_URI, DOC) + doc = Document(DOC_URI, workspace, DOC) diags = mccabe_lint.pyls_lint(config, doc) assert all([d['source'] == 'mccabe' for d in diags]) @@ -32,6 +32,6 @@ def test_mccabe(config): config._settings = old_settings -def test_mccabe_syntax_error(config): - doc = Document(DOC_URI, DOC_SYNTAX_ERR) +def test_mccabe_syntax_error(config, workspace): + doc = Document(DOC_URI, workspace, DOC_SYNTAX_ERR) assert mccabe_lint.pyls_lint(config, doc) is None diff --git a/test/plugins/test_pycodestyle_lint.py b/test/plugins/test_pycodestyle_lint.py index eb1429b5..f2769a3d 100644 --- a/test/plugins/test_pycodestyle_lint.py +++ b/test/plugins/test_pycodestyle_lint.py @@ -20,8 +20,8 @@ def hello( ): """ -def test_pycodestyle(config): - doc = Document(DOC_URI, DOC) +def test_pycodestyle(config, workspace): + doc = Document(DOC_URI, workspace, DOC) diags = pycodestyle_lint.pyls_lint(config, doc) assert all([d['source'] == 'pycodestyle' for d in diags]) diff --git a/test/plugins/test_pydocstyle_lint.py b/test/plugins/test_pydocstyle_lint.py index f1c32703..9ee7b289 100644 --- a/test/plugins/test_pydocstyle_lint.py +++ b/test/plugins/test_pydocstyle_lint.py @@ -16,8 +16,8 @@ def hello(): """ -def test_pydocstyle(config): - doc = Document(DOC_URI, DOC) +def test_pydocstyle(config, workspace): + doc = Document(DOC_URI, workspace, DOC) diags = pydocstyle_lint.pyls_lint(config, doc) assert all([d['source'] == 'pydocstyle' for d in diags]) @@ -35,22 +35,22 @@ def test_pydocstyle(config): } -def test_pydocstyle_test_document(config): +def test_pydocstyle_test_document(config, workspace): # The default --match argument excludes test_* documents. - doc = Document(TEST_DOC_URI, "") + doc = Document(TEST_DOC_URI, workspace, "") diags = pydocstyle_lint.pyls_lint(config, doc) assert not diags -def test_pydocstyle_empty_source(config): - doc = Document(DOC_URI, "") +def test_pydocstyle_empty_source(config, workspace): + doc = Document(DOC_URI, workspace, "") diags = pydocstyle_lint.pyls_lint(config, doc) assert diags[0]['message'] == 'D100: Missing docstring in public module' assert len(diags) == 1 -def test_pydocstyle_invalid_source(config): - doc = Document(DOC_URI, "bad syntax") +def test_pydocstyle_invalid_source(config, workspace): + doc = Document(DOC_URI, workspace, "bad syntax") diags = pydocstyle_lint.pyls_lint(config, doc) # We're unable to parse the file, so can't get any pydocstyle diagnostics assert not diags diff --git a/test/plugins/test_pyflakes_lint.py b/test/plugins/test_pyflakes_lint.py index cf824c08..aa968265 100644 --- a/test/plugins/test_pyflakes_lint.py +++ b/test/plugins/test_pyflakes_lint.py @@ -24,8 +24,8 @@ def hello(): """ -def test_pyflakes(): - doc = Document(DOC_URI, DOC) +def test_pyflakes(workspace): + doc = Document(DOC_URI, workspace, DOC) diags = pyflakes_lint.pyls_lint(doc) # One we're expecting is: @@ -36,8 +36,8 @@ def test_pyflakes(): assert unused_import['severity'] == lsp.DiagnosticSeverity.Warning -def test_syntax_error_pyflakes(): - doc = Document(DOC_URI, DOC_SYNTAX_ERR) +def test_syntax_error_pyflakes(workspace): + doc = Document(DOC_URI, workspace, DOC_SYNTAX_ERR) diag = pyflakes_lint.pyls_lint(doc)[0] assert diag['message'] == 'invalid syntax' @@ -45,8 +45,8 @@ def test_syntax_error_pyflakes(): assert diag['severity'] == lsp.DiagnosticSeverity.Error -def test_undefined_name_pyflakes(): - doc = Document(DOC_URI, DOC_UNDEFINED_NAME_ERR) +def test_undefined_name_pyflakes(workspace): + doc = Document(DOC_URI, workspace, DOC_UNDEFINED_NAME_ERR) diag = pyflakes_lint.pyls_lint(doc)[0] assert diag['message'] == 'undefined name \'b\'' @@ -54,8 +54,8 @@ def test_undefined_name_pyflakes(): assert diag['severity'] == lsp.DiagnosticSeverity.Error -def test_unicode_encoding(): - doc = Document(DOC_URI, DOC_ENCODING) +def test_unicode_encoding(workspace): + doc = Document(DOC_URI, workspace, DOC_ENCODING) diags = pyflakes_lint.pyls_lint(doc) assert len(diags) == 1 diff --git a/test/plugins/test_pylint_lint.py b/test/plugins/test_pylint_lint.py index b0d85fdc..c2bf1bca 100644 --- a/test/plugins/test_pylint_lint.py +++ b/test/plugins/test_pylint_lint.py @@ -4,6 +4,7 @@ import tempfile from test import py2_only, py3_only +from test.test_utils import MockWorkspace from pyls import lsp, uris from pyls.workspace import Document from pyls.plugins import pylint_lint @@ -29,7 +30,7 @@ def temp_document(doc_text): name = temp_file.name temp_file.write(doc_text) temp_file.close() - yield Document(uris.from_fs_path(name)) + yield Document(uris.from_fs_path(name), MockWorkspace()) finally: os.remove(name) @@ -72,12 +73,12 @@ def test_syntax_error_pylint_py2(config): assert diag['severity'] == lsp.DiagnosticSeverity.Error -def test_lint_free_pylint(config): +def test_lint_free_pylint(config, workspace): # Can't use temp_document because it might give us a file that doesn't # match pylint's naming requirements. We should be keeping this file clean # though, so it works for a test of an empty lint. assert not pylint_lint.pyls_lint( - config, Document(uris.from_fs_path(__file__)), True) + config, Document(uris.from_fs_path(__file__), workspace), True) def test_lint_caching(): @@ -108,10 +109,10 @@ def test_lint_caching(): assert not pylint_lint.PylintLinter.lint(doc, False, flags) -def test_per_file_caching(config): +def test_per_file_caching(config, workspace): # Ensure that diagnostics are cached per-file. with temp_document(DOC) as doc: assert pylint_lint.pyls_lint(config, doc, True) assert not pylint_lint.pyls_lint( - config, Document(uris.from_fs_path(__file__)), False) + config, Document(uris.from_fs_path(__file__), workspace), False) diff --git a/test/plugins/test_references.py b/test/plugins/test_references.py index 4ad7c111..d7ce40e0 100644 --- a/test/plugins/test_references.py +++ b/test/plugins/test_references.py @@ -43,7 +43,7 @@ def test_references(tmp_workspace): # pylint: disable=redefined-outer-name # Over 'Test1' in class Test1(): position = {'line': 0, 'character': 8} DOC1_URI = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC1_NAME)) - doc1 = Document(DOC1_URI, workspace=tmp_workspace) + doc1 = Document(DOC1_URI, tmp_workspace) refs = pyls_references(doc1, position) @@ -75,7 +75,7 @@ def test_references_builtin(tmp_workspace): # pylint: disable=redefined-outer-n # Over 'UnicodeError': position = {'line': 4, 'character': 7} doc2_uri = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC2_NAME)) - doc2 = Document(doc2_uri, workspace=tmp_workspace) + doc2 = Document(doc2_uri, tmp_workspace) refs = pyls_references(doc2, position) assert len(refs) >= 1 diff --git a/test/plugins/test_rope_rename.py b/test/plugins/test_rope_rename.py index b744ece2..12c6e9f1 100644 --- a/test/plugins/test_rope_rename.py +++ b/test/plugins/test_rope_rename.py @@ -29,7 +29,7 @@ def create_file(name, content): def test_rope_rename(tmp_workspace, config): # pylint: disable=redefined-outer-name position = {"line": 0, "character": 6} DOC_URI = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC_NAME)) - doc = Document(DOC_URI) + doc = Document(DOC_URI, tmp_workspace) result = pyls_rename(config, tmp_workspace, doc, position, "ShouldBeRenamed") assert len(result.keys()) == 1 diff --git a/test/plugins/test_signature.py b/test/plugins/test_signature.py index e1cdd31b..b6b5111a 100644 --- a/test/plugins/test_signature.py +++ b/test/plugins/test_signature.py @@ -42,7 +42,7 @@ def main(param1=None, def test_no_signature(workspace): # Over blank line sig_position = {'line': 9, 'character': 0} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) sigs = signature.pyls_signature_help(doc, sig_position)['signatures'] assert not sigs @@ -51,7 +51,7 @@ def test_no_signature(workspace): def test_signature(workspace): # Over '( ' in main( sig_position = {'line': 10, 'character': 5} - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) sig_info = signature.pyls_signature_help(doc, sig_position) @@ -67,7 +67,7 @@ def test_signature(workspace): def test_multi_line_signature(workspace): # Over '( ' in main( sig_position = {'line': 17, 'character': 5} - doc = Document(DOC_URI, MULTI_LINE_DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, MULTI_LINE_DOC) sig_info = signature.pyls_signature_help(doc, sig_position) diff --git a/test/plugins/test_symbols.py b/test/plugins/test_symbols.py index 0923a756..7bfb73ea 100644 --- a/test/plugins/test_symbols.py +++ b/test/plugins/test_symbols.py @@ -49,7 +49,7 @@ def sym(name): def test_symbols(config, workspace): - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) config.update({'plugins': {'jedi_symbols': {'all_scopes': False}}}) symbols = pyls_document_symbols(config, doc) @@ -74,14 +74,14 @@ def sym(name): def test_symbols_all_scopes(config, workspace): - doc = Document(DOC_URI, DOC, workspace=workspace) + doc = Document(DOC_URI, workspace, DOC) symbols = pyls_document_symbols(config, doc) helper_check_symbols_all_scope(symbols) @pytest.mark.skipif(PY2 or not LINUX or not CI, reason="tested on linux and python 3 only") def test_symbols_all_scopes_with_jedi_environment(config): - doc = Document(DOC_URI, DOC, workspace=MockWorkspace()) + doc = Document(DOC_URI, MockWorkspace(), DOC) # Update config extra environment env_path = '/tmp/pyenv/bin/python' diff --git a/test/plugins/test_yapf_format.py b/test/plugins/test_yapf_format.py index 4bf6be32..e3e198e6 100644 --- a/test/plugins/test_yapf_format.py +++ b/test/plugins/test_yapf_format.py @@ -19,16 +19,16 @@ GOOD_DOC = """A = ['hello', 'world']\n""" -def test_format(): - doc = Document(DOC_URI, DOC) +def test_format(workspace): + doc = Document(DOC_URI, workspace, DOC) res = pyls_format_document(doc) assert len(res) == 1 assert res[0]['newText'] == "A = ['h', 'w', 'a']\n\nB = ['h', 'w']\n" -def test_range_format(): - doc = Document(DOC_URI, DOC) +def test_range_format(workspace): + doc = Document(DOC_URI, workspace, DOC) def_range = { 'start': {'line': 0, 'character': 0}, @@ -42,17 +42,17 @@ def test_range_format(): assert res[0]['newText'] == "A = ['h', 'w', 'a']\n\nB = ['h',\n\n\n'w']\n" -def test_no_change(): - doc = Document(DOC_URI, GOOD_DOC) +def test_no_change(workspace): + doc = Document(DOC_URI, workspace, GOOD_DOC) assert not pyls_format_document(doc) -def test_config_file(tmpdir): +def test_config_file(tmpdir, workspace): # a config file in the same directory as the source file will be used conf = tmpdir.join('.style.yapf') conf.write('[style]\ncolumn_limit = 14') src = tmpdir.join('test.py') - doc = Document(uris.from_fs_path(src.strpath), DOC) + doc = Document(uris.from_fs_path(src.strpath), workspace, DOC) # A was split on multiple lines because of column_limit from config file assert pyls_format_document(doc)[0]['newText'] == "A = [\n 'h', 'w',\n 'a'\n]\n\nB = ['h', 'w']\n" diff --git a/test/test_document.py b/test/test_document.py index 4fd4ea2f..dc54613a 100644 --- a/test/test_document.py +++ b/test/test_document.py @@ -13,9 +13,9 @@ def test_document_lines(doc): assert doc.lines[0] == 'import sys\n' -def test_document_source_unicode(): - document_mem = Document(DOC_URI, u'my source') - document_disk = Document(DOC_URI) +def test_document_source_unicode(workspace): + document_mem = Document(DOC_URI, workspace, u'my source') + document_disk = Document(DOC_URI, workspace) assert isinstance(document_mem.source, type(document_disk.source)) @@ -41,8 +41,8 @@ def test_word_at_position(doc): assert doc.word_at_position({'line': 4, 'character': 0}) == '' -def test_document_empty_edit(): - doc = Document('file:///uri', u'') +def test_document_empty_edit(workspace): + doc = Document('file:///uri', workspace, u'') doc.apply_change({ 'range': { 'start': {'line': 0, 'character': 0}, @@ -53,8 +53,8 @@ def test_document_empty_edit(): assert doc.source == u'f' -def test_document_line_edit(): - doc = Document('file:///uri', u'itshelloworld') +def test_document_line_edit(workspace): + doc = Document('file:///uri', workspace, u'itshelloworld') doc.apply_change({ 'text': u'goodbye', 'range': { @@ -65,13 +65,13 @@ def test_document_line_edit(): assert doc.source == u'itsgoodbyeworld' -def test_document_multiline_edit(): +def test_document_multiline_edit(workspace): old = [ "def hello(a, b):\n", " print a\n", " print b\n" ] - doc = Document('file:///uri', u''.join(old)) + doc = Document('file:///uri', workspace, u''.join(old)) doc.apply_change({'text': u'print a, b', 'range': { 'start': {'line': 1, 'character': 4}, 'end': {'line': 2, 'character': 11} @@ -82,12 +82,12 @@ def test_document_multiline_edit(): ] -def test_document_end_of_file_edit(): +def test_document_end_of_file_edit(workspace): old = [ "print 'a'\n", "print 'b'\n" ] - doc = Document('file:///uri', u''.join(old)) + doc = Document('file:///uri', workspace, u''.join(old)) doc.apply_change({'text': u'o', 'range': { 'start': {'line': 2, 'character': 0}, 'end': {'line': 2, 'character': 0} From 3da9869dbfdcbf35afbbd0d6bdf4b936f002fefa Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 17:12:46 -0500 Subject: [PATCH 22/23] Fix pylint complaint --- test/plugins/test_flake8_lint.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/plugins/test_flake8_lint.py b/test/plugins/test_flake8_lint.py index 9fdbb6a4..326f93b9 100644 --- a/test/plugins/test_flake8_lint.py +++ b/test/plugins/test_flake8_lint.py @@ -1,10 +1,8 @@ # Copyright 2019 Palantir Technologies, Inc. import tempfile import os -from mock import patch - from test.test_utils import MockWorkspace - +from mock import patch from pyls import lsp, uris from pyls.plugins import flake8_lint from pyls.workspace import Document @@ -35,7 +33,7 @@ def test_flake8_no_checked_file(config, workspace): # A bad uri or a non-saved file may cause the flake8 linter to do nothing. # In this situtation, the linter will return an empty list. - doc = Document('', DOC, workspace) + doc = Document('', workspace, DOC) diags = flake8_lint.pyls_lint(config, doc) assert diags == [] From da659ae333ca99372a61888cf2e2581f349b9239 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 9 May 2020 17:18:44 -0500 Subject: [PATCH 23/23] Fix another pyling warning --- test/fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures.py b/test/fixtures.py index 764b3d13..08d57f07 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -48,5 +48,5 @@ def config(workspace): # pylint: disable=redefined-outer-name @pytest.fixture -def doc(workspace): +def doc(workspace): # pylint: disable=redefined-outer-name return Document(DOC_URI, workspace, DOC)