Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-python-lsp-server for openSUSE:Factory checked in at 2022-11-07 13:52:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-python-lsp-server (Old) and /work/SRC/openSUSE:Factory/.python-python-lsp-server.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-lsp-server" Mon Nov 7 13:52:07 2022 rev:16 rq:1034140 version:1.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-python-lsp-server/python-python-lsp-server.changes 2022-08-28 13:12:40.592598884 +0200 +++ /work/SRC/openSUSE:Factory/.python-python-lsp-server.new.1597/python-python-lsp-server.changes 2022-11-07 13:52:12.823977707 +0100 @@ -1,0 +2,14 @@ +Sun Nov 6 15:10:39 UTC 2022 - Ben Greiner <c...@bnavigator.de> + +- Update to 1.6.0 + * Migrate to MarkupContent and convert docstrings to Markdown by + default. + * Add support for flake8 version 5. + * Add function objects to Jedi completions. + * Don't include class and functions objects by default in Jedi + completions. +- Drop patches + * python-lsp-server-advanceflake8.patch + * python-lsp-server-pylint-syntax-error.patch + +------------------------------------------------------------------- Old: ---- python-lsp-server-1.5.0.tar.gz python-lsp-server-advanceflake8.patch python-lsp-server-pylint-syntax-error.patch New: ---- python-lsp-server-1.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-python-lsp-server.spec ++++++ --- /var/tmp/diff_new_pack.WyDVWo/_old 2022-11-07 13:52:14.439986791 +0100 +++ /var/tmp/diff_new_pack.WyDVWo/_new 2022-11-07 13:52:14.443986813 +0100 @@ -17,16 +17,12 @@ Name: python-python-lsp-server -Version: 1.5.0 +Version: 1.6.0 Release: 0 Summary: Python Language Server for the Language Server Protocol License: MIT URL: https://github.com/python-lsp/python-lsp-server Source: https://files.pythonhosted.org/packages/source/p/python-lsp-server/python-lsp-server-%{version}.tar.gz -# PATCH-FEATURE-UPSTREAM python-lsp-server-advanceflake8.patch gh#python-lsp/python-lsp-server#257 -Patch0: python-lsp-server-advanceflake8.patch -# PATCH-FEATURE-UPSTREAM python-lsp-server-pylint-syntax-error.patch gh#python-lsp/python-lsp-server#258 -Patch1: python-lsp-server-pylint-syntax-error.patch BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module pip} BuildRequires: %{python_module setuptools >= 61.2} @@ -35,9 +31,9 @@ BuildRequires: %{python_module wheel} BuildRequires: python-rpm-macros >= 20210628 # SECTION test requirements +BuildRequires: %{python_module docstring-to-markdown} BuildRequires: %{python_module PyQt5} BuildRequires: %{python_module autopep8 >= 1.6.0 with %python-autopep8 < 1.7.0} -# flake8 and its dependencies in a particular range, see Patch0 BuildRequires: %{python_module flake8 >= 5.0.0 with %python-flake8 < 5.1.0} BuildRequires: %{python_module flaky} BuildRequires: %{python_module jedi >= 0.17.2 with %python-jedi < 0.19.0} @@ -55,6 +51,7 @@ BuildRequires: %{python_module yapf} # /SECTION BuildRequires: fdupes +Requires: python-docstring-to-markdown Requires: python-pluggy >= 1.0.0 Requires: python-python-lsp-jsonrpc >= 1.0.0 Requires: python-setuptools >= 39.0.0 @@ -67,7 +64,7 @@ Suggests: python-rope >= 0.10.5 Suggests: python-yapf Suggests: python-whatthepatch -# SECTION flake8 pins -- see Patch0 +# SECTION flake8 pins Suggests: python-flake8 >= 5.0.0 Conflicts: python-flake8 >= 5.1.0 Suggests: python-mccabe >= 0.7.0 @@ -76,7 +73,7 @@ Conflicts: python-pycodestyle >= 2.10.0 Suggests: python-pyflakes >= 2.5.0 Conflicts: python-pyflakes >= 2.6.0 -# SECTION +# /SECTION BuildArch: noarch Requires(post): update-alternatives Requires(postun):update-alternatives ++++++ python-lsp-server-1.5.0.tar.gz -> python-lsp-server-1.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/CHANGELOG.md new/python-lsp-server-1.6.0/CHANGELOG.md --- old/python-lsp-server-1.5.0/CHANGELOG.md 2022-07-11 04:11:31.000000000 +0200 +++ new/python-lsp-server-1.6.0/CHANGELOG.md 2022-11-03 00:27:35.000000000 +0100 @@ -1,5 +1,51 @@ # History of changes +## Version 1.6.0 (2022/11/02) + +### New features + +* Migrate to MarkupContent and convert docstrings to Markdown by default. +* Add support for flake8 version 5. +* Add function objects to Jedi completions. +* Don't include class and functions objects by default in Jedi completions. + +### Issues Closed + +* [Issue 273](https://github.com/python-lsp/python-lsp-server/issues/273) - Completion result have "typeParameter" duplicates ([PR 274](https://github.com/python-lsp/python-lsp-server/pull/274) by [@airportyh](https://github.com/airportyh)) +* [Issue 265](https://github.com/python-lsp/python-lsp-server/issues/265) - Server warns when optional modules do not exist ([PR 266](https://github.com/python-lsp/python-lsp-server/pull/266) by [@doolio](https://github.com/doolio)) +* [Issue 264](https://github.com/python-lsp/python-lsp-server/issues/264) - Errors in CONFIGURATION.md? ([PR 267](https://github.com/python-lsp/python-lsp-server/pull/267) by [@doolio](https://github.com/doolio)) +* [Issue 263](https://github.com/python-lsp/python-lsp-server/issues/263) - Conflict between README and CONFIGURATION ([PR 267](https://github.com/python-lsp/python-lsp-server/pull/267) by [@doolio](https://github.com/doolio)) +* [Issue 245](https://github.com/python-lsp/python-lsp-server/issues/245) - Add alternative ways to install python-lsp-server ([PR 248](https://github.com/python-lsp/python-lsp-server/pull/248) by [@nougcat](https://github.com/nougcat)) +* [Issue 244](https://github.com/python-lsp/python-lsp-server/issues/244) - Add function objects to completions ([PR 246](https://github.com/python-lsp/python-lsp-server/pull/246) by [@llan-ml](https://github.com/llan-ml)) +* [Issue 243](https://github.com/python-lsp/python-lsp-server/issues/243) - `Failed to load hook pylsp_completions: 'NoneType' object has no attribute 'type'` when working with Numpy 1.23 ([PR 281](https://github.com/python-lsp/python-lsp-server/pull/281) by [@gav451](https://github.com/gav451)) +* [Issue 22](https://github.com/python-lsp/python-lsp-server/issues/22) - Consider using docstring_to_markdown for markdown hover and documentation ([PR 80](https://github.com/python-lsp/python-lsp-server/pull/80) by [@krassowski](https://github.com/krassowski)) +* [Issue 21](https://github.com/python-lsp/python-lsp-server/issues/21) - Migrate from deprecated MarkedString to MarkupContent ([PR 80](https://github.com/python-lsp/python-lsp-server/pull/80) by [@krassowski](https://github.com/krassowski)) + +In this release 9 issues were closed. + +### Pull Requests Merged + +* [PR 285](https://github.com/python-lsp/python-lsp-server/pull/285) - Don't include class objects by default in completions, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 281](https://github.com/python-lsp/python-lsp-server/pull/281) - Improve how Jedi handles Numpy, by [@gav451](https://github.com/gav451) ([243](https://github.com/python-lsp/python-lsp-server/issues/243)) +* [PR 274](https://github.com/python-lsp/python-lsp-server/pull/274) - Make default for `include_function_objects` false, by [@airportyh](https://github.com/airportyh) ([273](https://github.com/python-lsp/python-lsp-server/issues/273)) +* [PR 272](https://github.com/python-lsp/python-lsp-server/pull/272) - Include params only for classes and functions, by [@llan-ml](https://github.com/llan-ml) +* [PR 267](https://github.com/python-lsp/python-lsp-server/pull/267) - Update the configuration schema for consistency, by [@doolio](https://github.com/doolio) ([264](https://github.com/python-lsp/python-lsp-server/issues/264), [263](https://github.com/python-lsp/python-lsp-server/issues/263)) +* [PR 266](https://github.com/python-lsp/python-lsp-server/pull/266) - Prefer info log message for missing optional modules, by [@doolio](https://github.com/doolio) ([265](https://github.com/python-lsp/python-lsp-server/issues/265)) +* [PR 262](https://github.com/python-lsp/python-lsp-server/pull/262) - Fix options not being passed to yapf format, by [@masad-frost](https://github.com/masad-frost) +* [PR 261](https://github.com/python-lsp/python-lsp-server/pull/261) - PR: Include all symbols that Jedi reports as declared in a file when `add_import_symbols` is `False`, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 258](https://github.com/python-lsp/python-lsp-server/pull/258) - Fix pylint message in tests, by [@bnavigator](https://github.com/bnavigator) +* [PR 257](https://github.com/python-lsp/python-lsp-server/pull/257) - Add support for flake8 version 5, by [@bnavigator](https://github.com/bnavigator) +* [PR 250](https://github.com/python-lsp/python-lsp-server/pull/250) - Include traceback when plugin fails to load, by [@j2kun](https://github.com/j2kun) +* [PR 248](https://github.com/python-lsp/python-lsp-server/pull/248) - Add more installation instructions to Readme, by [@nougcat](https://github.com/nougcat) ([245](https://github.com/python-lsp/python-lsp-server/issues/245)) +* [PR 246](https://github.com/python-lsp/python-lsp-server/pull/246) - Add support for including function objects, by [@llan-ml](https://github.com/llan-ml) ([244](https://github.com/python-lsp/python-lsp-server/issues/244)) +* [PR 242](https://github.com/python-lsp/python-lsp-server/pull/242) - Remove redundant wheel dep from pyproject.toml, by [@mgorny](https://github.com/mgorny) +* [PR 241](https://github.com/python-lsp/python-lsp-server/pull/241) - Update release instructions to use new build mechanism, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 80](https://github.com/python-lsp/python-lsp-server/pull/80) - Migrate to MarkupContent and convert docstrings to Markdown, by [@krassowski](https://github.com/krassowski) ([22](https://github.com/python-lsp/python-lsp-server/issues/22), [21](https://github.com/python-lsp/python-lsp-server/issues/21)) + +In this release 16 pull requests were closed. + +---- + ## Version 1.5.0 (2022/07/10) ### New features diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/CONFIGURATION.md new/python-lsp-server-1.6.0/CONFIGURATION.md --- old/python-lsp-server-1.5.0/CONFIGURATION.md 2022-07-11 03:55:04.000000000 +0200 +++ new/python-lsp-server-1.6.0/CONFIGURATION.md 2022-11-03 00:27:35.000000000 +0100 @@ -1,9 +1,9 @@ # Python Language Server Configuration -This server can be configured using `workspace/didChangeConfiguration` method. Each configuration option is described below: +This server can be configured using the `workspace/didChangeConfiguration` method. Each configuration option is described below. Note, a value of `null` means that we do not set a value and thus use the plugin's default value. | **Configuration Key** | **Type** | **Description** | **Default** |----|----|----|----| -| `pylsp.configurationSources` | `array` of unique `string` (one of: `pycodestyle`, `pyflakes`) items | List of configuration sources to use. | `["pycodestyle"]` | +| `pylsp.configurationSources` | `array` of unique `string` (one of: `'pycodestyle'`, `'flake8'`) items | List of configuration sources to use. | `["pycodestyle"]` | | `pylsp.plugins.autopep8.enabled` | `boolean` | Enable or disable the plugin (disabling required to use `yapf`). | `true` | | `pylsp.plugins.flake8.config` | `string` | Path to the config file that will be the authoritative config source. | `null` | | `pylsp.plugins.flake8.enabled` | `boolean` | Enable or disable the plugin. | `false` | @@ -16,15 +16,17 @@ | `pylsp.plugins.flake8.indentSize` | `integer` | Set indentation spaces. | `null` | | `pylsp.plugins.flake8.perFileIgnores` | `array` of `string` items | A pairing of filenames and violation codes that defines which violations to ignore in a particular file, for example: `["file_path.py:W305,W304"]`). | `[]` | | `pylsp.plugins.flake8.select` | `array` of unique `string` items | List of errors and warnings to enable. | `null` | +| `pylsp.plugins.jedi.auto_import_modules` | `array` of `string` items | List of module names for jedi.settings.auto_import_modules. | `["numpy"]` | | `pylsp.plugins.jedi.extra_paths` | `array` of `string` items | Define extra paths for jedi.Script. | `[]` | | `pylsp.plugins.jedi.env_vars` | `object` | Define environment variables for jedi.Script and Jedi.names. | `null` | | `pylsp.plugins.jedi.environment` | `string` | Define environment for jedi.Script and Jedi.names. | `null` | | `pylsp.plugins.jedi_completion.enabled` | `boolean` | Enable or disable the plugin. | `true` | | `pylsp.plugins.jedi_completion.include_params` | `boolean` | Auto-completes methods and classes with tabstops for each parameter. | `true` | -| `pylsp.plugins.jedi_completion.include_class_objects` | `boolean` | Adds class objects as a separate completion item. | `true` | +| `pylsp.plugins.jedi_completion.include_class_objects` | `boolean` | Adds class objects as a separate completion item. | `false` | +| `pylsp.plugins.jedi_completion.include_function_objects` | `boolean` | Adds function objects as a separate completion item. | `false` | | `pylsp.plugins.jedi_completion.fuzzy` | `boolean` | Enable fuzzy when requesting autocomplete. | `false` | | `pylsp.plugins.jedi_completion.eager` | `boolean` | Resolve documentation and detail eagerly. | `false` | -| `pylsp.plugins.jedi_completion.resolve_at_most` | `number` | How many labels and snippets (at most) should be resolved? | `25` | +| `pylsp.plugins.jedi_completion.resolve_at_most` | `integer` | How many labels and snippets (at most) should be resolved? | `25` | | `pylsp.plugins.jedi_completion.cache_for` | `array` of `string` items | Modules for which labels and snippets should be cached. | `["pandas", "numpy", "tensorflow", "matplotlib"]` | | `pylsp.plugins.jedi_definition.enabled` | `boolean` | Enable or disable the plugin. | `true` | | `pylsp.plugins.jedi_definition.follow_imports` | `boolean` | The goto call will follow imports. | `true` | @@ -36,23 +38,23 @@ | `pylsp.plugins.jedi_symbols.all_scopes` | `boolean` | If True lists the names of all scopes instead of only the module namespace. | `true` | | `pylsp.plugins.jedi_symbols.include_import_symbols` | `boolean` | If True includes symbols imported from other libraries. | `true` | | `pylsp.plugins.mccabe.enabled` | `boolean` | Enable or disable the plugin. | `true` | -| `pylsp.plugins.mccabe.threshold` | `number` | The minimum threshold that triggers warnings about cyclomatic complexity. | `15` | +| `pylsp.plugins.mccabe.threshold` | `integer` | The minimum threshold that triggers warnings about cyclomatic complexity. | `15` | | `pylsp.plugins.preload.enabled` | `boolean` | Enable or disable the plugin. | `true` | | `pylsp.plugins.preload.modules` | `array` of unique `string` items | List of modules to import on startup | `[]` | | `pylsp.plugins.pycodestyle.enabled` | `boolean` | Enable or disable the plugin. | `true` | | `pylsp.plugins.pycodestyle.exclude` | `array` of unique `string` items | Exclude files or directories which match these patterns. | `[]` | | `pylsp.plugins.pycodestyle.filename` | `array` of unique `string` items | When parsing directories, only check filenames matching these patterns. | `[]` | -| `pylsp.plugins.pycodestyle.select` | `array` of unique `string` items | Select errors and warnings | `[]` | +| `pylsp.plugins.pycodestyle.select` | `array` of unique `string` items | Select errors and warnings | `null` | | `pylsp.plugins.pycodestyle.ignore` | `array` of unique `string` items | Ignore errors and warnings | `[]` | | `pylsp.plugins.pycodestyle.hangClosing` | `boolean` | Hang closing bracket instead of matching indentation of opening bracket's line. | `null` | -| `pylsp.plugins.pycodestyle.maxLineLength` | `number` | Set maximum allowed line length. | `null` | +| `pylsp.plugins.pycodestyle.maxLineLength` | `integer` | Set maximum allowed line length. | `null` | | `pylsp.plugins.pycodestyle.indentSize` | `integer` | Set indentation spaces. | `null` | | `pylsp.plugins.pydocstyle.enabled` | `boolean` | Enable or disable the plugin. | `false` | -| `pylsp.plugins.pydocstyle.convention` | `string` (one of: `pep257`, `numpy`, `None`) | Choose the basic list of checked errors by specifying an existing convention. | `null` | +| `pylsp.plugins.pydocstyle.convention` | `string` (one of: `'pep257'`, `'numpy'`, `None`) | Choose the basic list of checked errors by specifying an existing convention. | `null` | | `pylsp.plugins.pydocstyle.addIgnore` | `array` of unique `string` items | Ignore errors and warnings in addition to the specified convention. | `[]` | | `pylsp.plugins.pydocstyle.addSelect` | `array` of unique `string` items | Select errors and warnings in addition to the specified convention. | `[]` | | `pylsp.plugins.pydocstyle.ignore` | `array` of unique `string` items | Ignore errors and warnings | `[]` | -| `pylsp.plugins.pydocstyle.select` | `array` of unique `string` items | Select errors and warnings | `[]` | +| `pylsp.plugins.pydocstyle.select` | `array` of unique `string` items | Select errors and warnings | `null` | | `pylsp.plugins.pydocstyle.match` | `string` | Check only files that exactly match the given regular expression; default is to match files that don't start with 'test_' but end with '.py'. | `"(?!test_).*\\.py"` | | `pylsp.plugins.pydocstyle.matchDir` | `string` | Search only dirs that exactly match the given regular expression; default is to match dirs which do not begin with a dot. | `"[^\\.].*"` | | `pylsp.plugins.pyflakes.enabled` | `boolean` | Enable or disable the plugin. | `true` | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/PKG-INFO new/python-lsp-server-1.6.0/PKG-INFO --- old/python-lsp-server-1.5.0/PKG-INFO 2022-07-11 04:17:09.427038000 +0200 +++ new/python-lsp-server-1.6.0/PKG-INFO 2022-11-03 00:31:55.146507300 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: python-lsp-server -Version: 1.5.0 +Version: 1.6.0 Summary: Python Language Server for the Language Server Protocol Author: Python Language Server Contributors License: MIT @@ -66,6 +66,34 @@ pip install -U setuptools ``` +### Windows and Linux installation + +If you use Anaconda/Miniconda, you can install `python-lsp-server` using this conda command + +``` +conda install -c conda-forge python-lsp-server +``` + +Python-lsp-server is available in the repos of every major Linux distribution, and it is usually called `python-lsp-server`. + +For example, here is how to install it in Debian and Debian-based distributions (E.g. Ubuntu, Pop!_OS, Linux Mint) + +``` +sudo apt-get install python-lsp-server +``` + +or Fedora Linux + +``` +sudo dnf install python-lsp-server +``` + +Only on Alpine Linux the package is named differently. You can install it there by typing this command in your terminal: + +``` +apk add py3-lsp-server +``` + ### 3rd Party Plugins Installing these plugins will add extra functionality to the language server: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/README.md new/python-lsp-server-1.6.0/README.md --- old/python-lsp-server-1.5.0/README.md 2022-07-01 23:20:01.000000000 +0200 +++ new/python-lsp-server-1.6.0/README.md 2022-10-31 16:56:57.000000000 +0100 @@ -43,6 +43,34 @@ pip install -U setuptools ``` +### Windows and Linux installation + +If you use Anaconda/Miniconda, you can install `python-lsp-server` using this conda command + +``` +conda install -c conda-forge python-lsp-server +``` + +Python-lsp-server is available in the repos of every major Linux distribution, and it is usually called `python-lsp-server`. + +For example, here is how to install it in Debian and Debian-based distributions (E.g. Ubuntu, Pop!_OS, Linux Mint) + +``` +sudo apt-get install python-lsp-server +``` + +or Fedora Linux + +``` +sudo dnf install python-lsp-server +``` + +Only on Alpine Linux the package is named differently. You can install it there by typing this command in your terminal: + +``` +apk add py3-lsp-server +``` + ### 3rd Party Plugins Installing these plugins will add extra functionality to the language server: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/RELEASE.md new/python-lsp-server-1.6.0/RELEASE.md --- old/python-lsp-server-1.5.0/RELEASE.md 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/RELEASE.md 2022-11-03 00:27:35.000000000 +0100 @@ -6,14 +6,17 @@ This is necessary to run our tests before the release, so we can be sure everything is in order. + ## To release a new version of python-lsp-server: 1. git fetch upstream && git checkout upstream/master 2. Close milestone on GitHub 3. git clean -xfdi 4. git tag -a vX.X.X -m "Release vX.X.X" -5. python setup.py sdist -6. python setup.py bdist_wheel -7. twine check dist/* -8. twine upload dist/* -9. git push upstream --tags +5. python -m pip install --upgrade pip +6. pip install --upgrade --upgrade-strategy eager build setuptools twine wheel +7. python -bb -X dev -W error -m build +8. twine check --strict dist/* +9. twine upload dist/* +10. git push upstream --tags +11. Create release on Github diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/_utils.py new/python-lsp-server-1.6.0/pylsp/_utils.py --- old/python-lsp-server-1.5.0/pylsp/_utils.py 2022-06-07 20:04:11.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/_utils.py 2022-10-31 16:56:57.000000000 +0100 @@ -8,7 +8,9 @@ import pathlib import re import threading +from typing import List, Optional +import docstring_to_markdown import jedi JEDI_VERSION = jedi.__version__ @@ -144,17 +146,84 @@ return dict(_merge_dicts_(dict_a, dict_b)) -def format_docstring(contents): - """Python doc strings come in a number of formats, but LSP wants markdown. - - Until we can find a fast enough way of discovering and parsing each format, - we can do a little better by at least preserving indentation. +def escape_plain_text(contents: str) -> str: + """ + Format plain text to display nicely in environments which do not respect whitespaces. """ contents = contents.replace('\t', '\u00A0' * 4) contents = contents.replace(' ', '\u00A0' * 2) return contents +def escape_markdown(contents: str) -> str: + """ + Format plain text to display nicely in Markdown environment. + """ + # escape markdown syntax + contents = re.sub(r'([\\*_#[\]])', r'\\\1', contents) + # preserve white space characters + contents = escape_plain_text(contents) + return contents + + +def wrap_signature(signature): + return '```python\n' + signature + '\n```\n' + + +SERVER_SUPPORTED_MARKUP_KINDS = {'markdown', 'plaintext'} + + +def choose_markup_kind(client_supported_markup_kinds: List[str]): + """Choose a markup kind supported by both client and the server. + + This gives priority to the markup kinds provided earlier on the client preference list. + """ + for kind in client_supported_markup_kinds: + if kind in SERVER_SUPPORTED_MARKUP_KINDS: + return kind + return 'markdown' + + +def format_docstring(contents: str, markup_kind: str, signatures: Optional[List[str]] = None): + """Transform the provided docstring into a MarkupContent object. + + If `markup_kind` is 'markdown' the docstring will get converted to + markdown representation using `docstring-to-markdown`; if it is + `plaintext`, it will be returned as plain text. + Call signatures of functions (or equivalent code summaries) + provided in optional `signatures` argument will be prepended + to the provided contents of the docstring if given. + """ + if not isinstance(contents, str): + contents = '' + + if markup_kind == 'markdown': + try: + value = docstring_to_markdown.convert(contents) + return { + 'kind': 'markdown', + 'value': value + } + except docstring_to_markdown.UnknownFormatError: + # try to escape the Markdown syntax instead: + value = escape_markdown(contents) + + if signatures: + value = wrap_signature('\n'.join(signatures)) + '\n\n' + value + + return { + 'kind': 'markdown', + 'value': value + } + value = contents + if signatures: + value = '\n'.join(signatures) + '\n\n' + value + return { + 'kind': 'plaintext', + 'value': escape_plain_text(value) + } + + def clip_column(column, lines, line_number): """ Normalise the position as per the LSP that accepts character positions > line length diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/_version.py new/python-lsp-server-1.6.0/pylsp/_version.py --- old/python-lsp-server-1.5.0/pylsp/_version.py 2022-07-11 04:17:09.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/_version.py 2022-11-03 00:31:54.000000000 +0100 @@ -1 +1 @@ -__version__ = "1.5.0" +__version__ = "1.6.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/config/config.py new/python-lsp-server-1.6.0/pylsp/config/config.py --- old/python-lsp-server-1.5.0/pylsp/config/config.py 2022-06-07 20:04:11.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/config/config.py 2022-10-31 16:56:57.000000000 +0100 @@ -32,7 +32,7 @@ try: return self._inner_hookexec(hook_name, methods, kwargs, firstresult) except Exception as e: # pylint: disable=broad-except - log.warning(f"Failed to load hook {hook_name}: {e}") + log.warning(f"Failed to load hook {hook_name}: {e}", exc_info=True) return [] @@ -71,7 +71,7 @@ try: entry_point.load() except Exception as e: # pylint: disable=broad-except - log.warning("Failed to load %s entry point '%s': %s", PYLSP, entry_point.name, e) + log.info("Failed to load %s entry point '%s': %s", PYLSP, entry_point.name, e) self._pm.set_blocked(entry_point.name) # Load the entry points into pluggy, having blocked any failing ones diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/config/schema.json new/python-lsp-server-1.6.0/pylsp/config/schema.json --- old/python-lsp-server-1.5.0/pylsp/config/schema.json 2022-07-11 03:55:04.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/config/schema.json 2022-11-03 00:27:35.000000000 +0100 @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Python Language Server Configuration", - "description": "This server can be configured using `workspace/didChangeConfiguration` method. Each configuration option is described below:", + "description": "This server can be configured using the `workspace/didChangeConfiguration` method. Each configuration option is described below. Note, a value of `null` means that we do not set a value and thus use the plugin's default value.", "type": "object", "properties": { "pylsp.configurationSources": { @@ -10,7 +10,7 @@ "description": "List of configuration sources to use.", "items": { "type": "string", - "enum": ["pycodestyle", "pyflakes"] + "enum": ["pycodestyle", "flake8"] }, "uniqueItems": true }, @@ -87,6 +87,14 @@ "uniqueItems": true, "description": "List of errors and warnings to enable." }, + "pylsp.plugins.jedi.auto_import_modules": { + "type": "array", + "default": ["numpy"], + "items": { + "type": "string" + }, + "description": "List of module names for jedi.settings.auto_import_modules." + }, "pylsp.plugins.jedi.extra_paths": { "type": "array", "default": [], @@ -117,9 +125,14 @@ }, "pylsp.plugins.jedi_completion.include_class_objects": { "type": "boolean", - "default": true, + "default": false, "description": "Adds class objects as a separate completion item." }, + "pylsp.plugins.jedi_completion.include_function_objects": { + "type": "boolean", + "default": false, + "description": "Adds function objects as a separate completion item." + }, "pylsp.plugins.jedi_completion.fuzzy": { "type": "boolean", "default": false, @@ -131,7 +144,7 @@ "description": "Resolve documentation and detail eagerly." }, "pylsp.plugins.jedi_completion.resolve_at_most": { - "type": "number", + "type": "integer", "default": 25, "description": "How many labels and snippets (at most) should be resolved?" }, @@ -194,7 +207,7 @@ "description": "Enable or disable the plugin." }, "pylsp.plugins.mccabe.threshold": { - "type": "number", + "type": "integer", "default": 15, "description": "The minimum threshold that triggers warnings about cyclomatic complexity." }, @@ -236,8 +249,8 @@ "description": "When parsing directories, only check filenames matching these patterns." }, "pylsp.plugins.pycodestyle.select": { - "type": "array", - "default": [], + "type": ["array", "null"], + "default": null, "items": { "type": "string" }, @@ -259,7 +272,7 @@ "description": "Hang closing bracket instead of matching indentation of opening bracket's line." }, "pylsp.plugins.pycodestyle.maxLineLength": { - "type": ["number", "null"], + "type": ["integer", "null"], "default": null, "description": "Set maximum allowed line length." }, @@ -307,8 +320,8 @@ "description": "Ignore errors and warnings" }, "pylsp.plugins.pydocstyle.select": { - "type": "array", - "default": [], + "type": ["array", "null"], + "default": null, "items": { "type": "string" }, @@ -365,12 +378,12 @@ "description": "Enable or disable the plugin." }, "pylsp.rope.extensionModules": { - "type": ["null", "string"], + "type": ["string", "null"], "default": null, "description": "Builtin and c-extension modules that are allowed to be imported and inspected by rope." }, "pylsp.rope.ropeFolder": { - "type": ["null", "array"], + "type": ["array", "null"], "default": null, "items": { "type": "string" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/autopep8_format.py new/python-lsp-server-1.6.0/pylsp/plugins/autopep8_format.py --- old/python-lsp-server-1.5.0/pylsp/plugins/autopep8_format.py 2022-04-05 19:06:16.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/autopep8_format.py 2022-10-31 16:56:57.000000000 +0100 @@ -13,13 +13,13 @@ @hookimpl(tryfirst=True) # Prefer autopep8 over YAPF -def pylsp_format_document(config, document, options=None): # pylint: disable=unused-argument +def pylsp_format_document(config, document, options): # pylint: disable=unused-argument log.info("Formatting document %s with autopep8", document) return _format(config, document) @hookimpl(tryfirst=True) # Prefer autopep8 over YAPF -def pylsp_format_range(config, document, range, options=None): # pylint: disable=redefined-builtin,unused-argument +def pylsp_format_range(config, document, range, options): # pylint: disable=redefined-builtin,unused-argument log.info("Formatting document %s in range %s with autopep8", document, range) # First we 'round' the range up/down to full lines only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/hover.py new/python-lsp-server-1.6.0/pylsp/plugins/hover.py --- old/python-lsp-server-1.5.0/pylsp/plugins/hover.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/hover.py 2022-10-31 16:56:57.000000000 +0100 @@ -9,7 +9,7 @@ @hookimpl -def pylsp_hover(document, position): +def pylsp_hover(config, document, position): code_position = _utils.position_to_jedi_linecolumn(document, position) definitions = document.jedi_script(use_document_path=True).infer(**code_position) word = document.word_at_position(position) @@ -26,24 +26,19 @@ if not definition: return {'contents': ''} - # raw docstring returns only doc, without signature - doc = _utils.format_docstring(definition.docstring(raw=True)) + hover_capabilities = config.capabilities.get('textDocument', {}).get('hover', {}) + supported_markup_kinds = hover_capabilities.get('contentFormat', ['markdown']) + preferred_markup_kind = _utils.choose_markup_kind(supported_markup_kinds) # 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} + return { + 'contents': _utils.format_docstring( + # raw docstring returns only doc, without signature + definition.docstring(raw=True), + preferred_markup_kind, + signatures=[signature] if signature else None + ) + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/jedi_completion.py new/python-lsp-server-1.6.0/pylsp/plugins/jedi_completion.py --- old/python-lsp-server-1.5.0/pylsp/plugins/jedi_completion.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/jedi_completion.py 2022-10-31 16:56:57.000000000 +0100 @@ -50,10 +50,14 @@ return None completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) - snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport') + item_capabilities = completion_capabilities.get('completionItem', {}) + snippet_support = item_capabilities.get('snippetSupport') + supported_markup_kinds = item_capabilities.get('documentationFormat', ['markdown']) + preferred_markup_kind = _utils.choose_markup_kind(supported_markup_kinds) should_include_params = settings.get('include_params') - should_include_class_objects = settings.get('include_class_objects', True) + should_include_class_objects = settings.get('include_class_objects', False) + should_include_function_objects = settings.get('include_function_objects', False) max_to_resolve = settings.get('resolve_at_most', 25) modules_to_cache_for = settings.get('cache_for', None) @@ -63,11 +67,13 @@ include_params = snippet_support and should_include_params and use_snippets(document, position) include_class_objects = snippet_support and should_include_class_objects and use_snippets(document, position) + include_function_objects = snippet_support and should_include_function_objects and use_snippets(document, position) ready_completions = [ _format_completion( c, - include_params, + markup_kind=preferred_markup_kind, + include_params=include_params if c.type in ["class", "function"] else False, resolve=resolve_eagerly, resolve_label_or_snippet=(i < max_to_resolve) ) @@ -80,6 +86,20 @@ if c.type == 'class': completion_dict = _format_completion( c, + markup_kind=preferred_markup_kind, + include_params=False, + resolve=resolve_eagerly, + resolve_label_or_snippet=(i < max_to_resolve) + ) + completion_dict['kind'] = lsp.CompletionItemKind.TypeParameter + completion_dict['label'] += ' object' + ready_completions.append(completion_dict) + + if include_function_objects: + for i, c in enumerate(completions): + if c.type == 'function': + completion_dict = _format_completion( + c, False, resolve=resolve_eagerly, resolve_label_or_snippet=(i < max_to_resolve) @@ -104,12 +124,18 @@ @hookimpl -def pylsp_completion_item_resolve(completion_item, document): +def pylsp_completion_item_resolve(config, completion_item, document): """Resolve formatted completion for given non-resolved completion""" shared_data = document.shared_data['LAST_JEDI_COMPLETIONS'].get(completion_item['label']) + + completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) + item_capabilities = completion_capabilities.get('completionItem', {}) + supported_markup_kinds = item_capabilities.get('documentationFormat', ['markdown']) + preferred_markup_kind = _utils.choose_markup_kind(supported_markup_kinds) + if shared_data: completion, data = shared_data - return _resolve_completion(completion, data) + return _resolve_completion(completion, data, markup_kind=preferred_markup_kind) return completion_item @@ -163,18 +189,25 @@ not (expr_type in _ERRORS and 'import' in code)) -def _resolve_completion(completion, d): +def _resolve_completion(completion, d, markup_kind: str): # pylint: disable=broad-except completion['detail'] = _detail(d) try: - docs = _utils.format_docstring(d.docstring()) + docs = _utils.format_docstring( + d.docstring(raw=True), + signatures=[ + signature.to_string() + for signature in d.get_signatures() + ], + markup_kind=markup_kind + ) except Exception: docs = '' completion['documentation'] = docs return completion -def _format_completion(d, include_params=True, resolve=False, resolve_label_or_snippet=False): +def _format_completion(d, markup_kind: str, include_params=True, resolve=False, resolve_label_or_snippet=False): completion = { 'label': _label(d, resolve_label_or_snippet), 'kind': _TYPE_MAP.get(d.type), @@ -183,7 +216,7 @@ } if resolve: - completion = _resolve_completion(completion, d) + completion = _resolve_completion(completion, d, markup_kind) if d.type == 'path': path = osp.normpath(d.name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/rope_completion.py new/python-lsp-server-1.6.0/pylsp/plugins/rope_completion.py --- old/python-lsp-server-1.5.0/pylsp/plugins/rope_completion.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/rope_completion.py 2022-10-31 16:56:57.000000000 +0100 @@ -4,7 +4,7 @@ import logging from rope.contrib.codeassist import code_assist, sorted_proposals -from pylsp import hookimpl, lsp +from pylsp import _utils, hookimpl, lsp log = logging.getLogger(__name__) @@ -16,10 +16,13 @@ return {'plugins': {'rope_completion': {'enabled': False, 'eager': False}}} -def _resolve_completion(completion, data): +def _resolve_completion(completion, data, markup_kind): # pylint: disable=broad-except try: - doc = data.get_doc() + doc = _utils.format_docstring( + data.get_doc(), + markup_kind=markup_kind + ) except Exception as e: log.debug("Failed to resolve Rope completion: %s", e) doc = "" @@ -49,6 +52,11 @@ rope_project = workspace._rope_project_builder(rope_config) document_rope = document._rope_resource(rope_config) + completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) + item_capabilities = completion_capabilities.get('completionItem', {}) + supported_markup_kinds = item_capabilities.get('documentationFormat', ['markdown']) + preferred_markup_kind = _utils.choose_markup_kind(supported_markup_kinds) + try: definitions = code_assist(rope_project, document.source, offset, document_rope, maxfixes=3) except Exception as e: # pylint: disable=broad-except @@ -67,7 +75,7 @@ } } if resolve_eagerly: - item = _resolve_completion(item, d) + item = _resolve_completion(item, d, preferred_markup_kind) new_definitions.append(item) # most recently retrieved completion items, used for resolution @@ -83,12 +91,18 @@ @hookimpl -def pylsp_completion_item_resolve(completion_item, document): +def pylsp_completion_item_resolve(config, completion_item, document): """Resolve formatted completion for given non-resolved completion""" shared_data = document.shared_data['LAST_ROPE_COMPLETIONS'].get(completion_item['label']) + + completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) + item_capabilities = completion_capabilities.get('completionItem', {}) + supported_markup_kinds = item_capabilities.get('documentationFormat', ['markdown']) + preferred_markup_kind = _utils.choose_markup_kind(supported_markup_kinds) + if shared_data: completion, data = shared_data - return _resolve_completion(completion, data) + return _resolve_completion(completion, data, preferred_markup_kind) return completion_item diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/signature.py new/python-lsp-server-1.6.0/pylsp/plugins/signature.py --- old/python-lsp-server-1.5.0/pylsp/plugins/signature.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/signature.py 2022-10-31 16:56:57.000000000 +0100 @@ -15,28 +15,41 @@ @hookimpl -def pylsp_signature_help(document, position): +def pylsp_signature_help(config, document, position): code_position = _utils.position_to_jedi_linecolumn(document, position) signatures = document.jedi_script().get_signatures(**code_position) if not signatures: return {'signatures': []} + signature_capabilities = config.capabilities.get('textDocument', {}).get('signatureHelp', {}) + signature_information_support = signature_capabilities.get('signatureInformation', {}) + supported_markup_kinds = signature_information_support.get('documentationFormat', ['markdown']) + preferred_markup_kind = _utils.choose_markup_kind(supported_markup_kinds) + s = signatures[0] + docstring = s.docstring() + # Docstring contains one or more lines of signature, followed by empty line, followed by docstring - function_sig_lines = (s.docstring().split('\n\n') or [''])[0].splitlines() + function_sig_lines = (docstring.split('\n\n') or [''])[0].splitlines() function_sig = ' '.join([line.strip() for line in function_sig_lines]) sig = { 'label': function_sig, - 'documentation': _utils.format_docstring(s.docstring(raw=True)) + 'documentation': _utils.format_docstring( + s.docstring(raw=True), + markup_kind=preferred_markup_kind + ) } # If there are params, add those if s.params: sig['parameters'] = [{ 'label': p.name, - 'documentation': _param_docs(s.docstring(), p.name) + 'documentation': _utils.format_docstring( + _param_docs(docstring, p.name), + markup_kind=preferred_markup_kind + ) } for p in s.params] # We only return a single signature because Python doesn't allow overloading diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/symbols.py new/python-lsp-server-1.6.0/pylsp/plugins/symbols.py --- old/python-lsp-server-1.5.0/pylsp/plugins/symbols.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/symbols.py 2022-10-31 16:56:57.000000000 +0100 @@ -38,8 +38,9 @@ # Skip imported symbols comparing module names. sym_full_name = d.full_name - document_dot_path = document.dot_path if sym_full_name is not None: + document_dot_path = document.dot_path + # We assume a symbol is imported from another module to start # with. imported_symbol = True @@ -48,6 +49,8 @@ # we need to discard it to do module comparisons below. if '.' in sym_full_name: sym_module_name = sym_full_name.rpartition('.')[0] + else: + sym_module_name = sym_full_name # This is necessary to display symbols in init files (the checks # below fail without it). @@ -56,9 +59,9 @@ # document_dot_path is the module where the symbol is imported, # whereas sym_module_name is the one where it was declared. - if sym_module_name.startswith(document_dot_path): - # If sym_module_name starts with the same string as document_dot_path, - # we can safely assume it was declared in the document. + if document_dot_path in sym_module_name: + # If document_dot_path is in sym_module_name, we can safely assume + # that the symbol was declared in the document. imported_symbol = False elif sym_module_name.split('.')[0] in document_dot_path.split('.'): # If the first module in sym_module_name is one of the modules in @@ -74,10 +77,19 @@ # When there's no __init__.py next to a file or in one of its # parents, the checks above fail. However, Jedi has a nice way # to tell if the symbol was declared in the same file: if - # full_name starts by __main__. + # sym_module_name starts by __main__. if imported_symbol: if not sym_module_name.startswith('__main__'): continue + else: + # We need to skip symbols if their definition doesn't have `full_name` info, they + # are detected as a definition, but their description (e.g. `class Foo`) doesn't + # match the code where they're detected by Jedi. This happens for relative imports. + if _include_def(d): + if d.description not in d.get_line_code(): + continue + else: + continue try: docismodule = os.path.samefile(document.path, d.module_path) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/plugins/yapf_format.py new/python-lsp-server-1.6.0/pylsp/plugins/yapf_format.py --- old/python-lsp-server-1.5.0/pylsp/plugins/yapf_format.py 2022-06-07 20:04:11.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/plugins/yapf_format.py 2022-10-31 16:56:57.000000000 +0100 @@ -16,12 +16,12 @@ @hookimpl -def pylsp_format_document(document, options=None): +def pylsp_format_document(document, options): return _format(document, options=options) @hookimpl -def pylsp_format_range(document, range, options=None): # pylint: disable=redefined-builtin +def pylsp_format_range(document, range, options): # pylint: disable=redefined-builtin # First we 'round' the range up/down to full lines only range['start']['character'] = 0 range['end']['line'] += 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pylsp/workspace.py new/python-lsp-server-1.6.0/pylsp/workspace.py --- old/python-lsp-server-1.5.0/pylsp/workspace.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/pylsp/workspace.py 2022-11-03 00:27:35.000000000 +0100 @@ -14,6 +14,8 @@ log = logging.getLogger(__name__) +DEFAULT_AUTO_IMPORT_MODULES = ["numpy"] + # TODO: this is not the best e.g. we capture numbers RE_START_WORD = re.compile('[A-Za-z_0-9]*$') RE_END_WORD = re.compile('^[A-Za-z_0-9]*') @@ -252,6 +254,8 @@ if self._config: jedi_settings = self._config.plugin_settings('jedi', document_path=self.path) + jedi.settings.auto_import_modules = jedi_settings.get('auto_import_modules', + DEFAULT_AUTO_IMPORT_MODULES) environment_path = jedi_settings.get('environment') extra_paths = jedi_settings.get('extra_paths') or [] env_vars = jedi_settings.get('env_vars') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/pyproject.toml new/python-lsp-server-1.6.0/pyproject.toml --- old/python-lsp-server-1.5.0/pyproject.toml 2022-06-28 18:50:47.000000000 +0200 +++ new/python-lsp-server-1.6.0/pyproject.toml 2022-11-03 00:27:35.000000000 +0100 @@ -2,7 +2,7 @@ # Copyright 2021- Python Language Server Contributors. [build-system] -requires = ["setuptools>=61.2.0", "wheel", "setuptools_scm[toml]>=3.4.3"] +requires = ["setuptools>=61.2.0", "setuptools_scm[toml]>=3.4.3"] build-backend = "setuptools.build_meta" [project] @@ -16,6 +16,7 @@ "jedi>=0.17.2,<0.19.0", "python-lsp-jsonrpc>=1.0.0", "pluggy>=1.0.0", + "docstring-to-markdown", "ujson>=3.0.0", "setuptools>=39.0.0", ] @@ -27,22 +28,22 @@ [project.optional-dependencies] all = [ "autopep8>=1.6.0,<1.7.0", - "flake8>=4.0.0,<4.1.0", - "mccabe>=0.6.0,<0.7.0", - "pycodestyle>=2.8.0,<2.9.0", + "flake8>=5.0.0,<5.1.0", + "mccabe>=0.7.0,<0.8.0", + "pycodestyle>=2.9.0,<2.10.0", "pydocstyle>=2.0.0", - "pyflakes>=2.4.0,<2.5.0", + "pyflakes>=2.5.0,<2.6.0", "pylint>=2.5.0", "rope>=0.10.5", "yapf", "whatthepatch" ] autopep8 = ["autopep8>=1.6.0,<1.7.0"] -flake8 = ["flake8>=4.0.0,<4.1.0"] -mccabe = ["mccabe>=0.6.0,<0.7.0"] -pycodestyle = ["pycodestyle>=2.8.0,<2.9.0"] +flake8 = ["flake8>=5.0.0,<5.1.0"] +mccabe = ["mccabe>=0.7.0,<0.8.0"] +pycodestyle = ["pycodestyle>=2.9.0,<2.10.0"] pydocstyle = ["pydocstyle>=2.0.0"] -pyflakes = ["pyflakes>=2.4.0,<2.5.0"] +pyflakes = ["pyflakes>=2.5.0,<2.6.0"] pylint = ["pylint>=2.5.0"] rope = ["rope>0.10.5"] yapf = ["yapf", "whatthepatch>=1.0.2,<2.0.0"] @@ -52,7 +53,7 @@ "pytest", "pytest-cov", "coverage", - "numpy<1.23", + "numpy", "pandas", "matplotlib", "pyqt5", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/python_lsp_server.egg-info/PKG-INFO new/python-lsp-server-1.6.0/python_lsp_server.egg-info/PKG-INFO --- old/python-lsp-server-1.5.0/python_lsp_server.egg-info/PKG-INFO 2022-07-11 04:17:09.000000000 +0200 +++ new/python-lsp-server-1.6.0/python_lsp_server.egg-info/PKG-INFO 2022-11-03 00:31:55.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: python-lsp-server -Version: 1.5.0 +Version: 1.6.0 Summary: Python Language Server for the Language Server Protocol Author: Python Language Server Contributors License: MIT @@ -66,6 +66,34 @@ pip install -U setuptools ``` +### Windows and Linux installation + +If you use Anaconda/Miniconda, you can install `python-lsp-server` using this conda command + +``` +conda install -c conda-forge python-lsp-server +``` + +Python-lsp-server is available in the repos of every major Linux distribution, and it is usually called `python-lsp-server`. + +For example, here is how to install it in Debian and Debian-based distributions (E.g. Ubuntu, Pop!_OS, Linux Mint) + +``` +sudo apt-get install python-lsp-server +``` + +or Fedora Linux + +``` +sudo dnf install python-lsp-server +``` + +Only on Alpine Linux the package is named differently. You can install it there by typing this command in your terminal: + +``` +apk add py3-lsp-server +``` + ### 3rd Party Plugins Installing these plugins will add extra functionality to the language server: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/python_lsp_server.egg-info/requires.txt new/python-lsp-server-1.6.0/python_lsp_server.egg-info/requires.txt --- old/python-lsp-server-1.5.0/python_lsp_server.egg-info/requires.txt 2022-07-11 04:17:09.000000000 +0200 +++ new/python-lsp-server-1.6.0/python_lsp_server.egg-info/requires.txt 2022-11-03 00:31:55.000000000 +0100 @@ -1,16 +1,17 @@ jedi<0.19.0,>=0.17.2 python-lsp-jsonrpc>=1.0.0 pluggy>=1.0.0 +docstring-to-markdown ujson>=3.0.0 setuptools>=39.0.0 [all] autopep8<1.7.0,>=1.6.0 -flake8<4.1.0,>=4.0.0 -mccabe<0.7.0,>=0.6.0 -pycodestyle<2.9.0,>=2.8.0 +flake8<5.1.0,>=5.0.0 +mccabe<0.8.0,>=0.7.0 +pycodestyle<2.10.0,>=2.9.0 pydocstyle>=2.0.0 -pyflakes<2.5.0,>=2.4.0 +pyflakes<2.6.0,>=2.5.0 pylint>=2.5.0 rope>=0.10.5 yapf @@ -20,19 +21,19 @@ autopep8<1.7.0,>=1.6.0 [flake8] -flake8<4.1.0,>=4.0.0 +flake8<5.1.0,>=5.0.0 [mccabe] -mccabe<0.7.0,>=0.6.0 +mccabe<0.8.0,>=0.7.0 [pycodestyle] -pycodestyle<2.9.0,>=2.8.0 +pycodestyle<2.10.0,>=2.9.0 [pydocstyle] pydocstyle>=2.0.0 [pyflakes] -pyflakes<2.5.0,>=2.4.0 +pyflakes<2.6.0,>=2.5.0 [pylint] pylint>=2.5.0 @@ -45,7 +46,7 @@ pytest pytest-cov coverage -numpy<1.23 +numpy pandas matplotlib pyqt5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/scripts/jsonschema2md.py new/python-lsp-server-1.6.0/scripts/jsonschema2md.py --- old/python-lsp-server-1.5.0/scripts/jsonschema2md.py 2022-07-01 23:20:01.000000000 +0200 +++ new/python-lsp-server-1.6.0/scripts/jsonschema2md.py 2022-10-31 16:56:57.000000000 +0100 @@ -41,7 +41,7 @@ if option in EXTRA_DESCRIPTORS: parts.append(EXTRA_DESCRIPTORS[option](prop)) if "enum" in prop: - allowed_values = [f"`{value}`" for value in prop["enum"]] + allowed_values = [f"`{value!r}`" for value in prop["enum"]] parts.append("(one of: " + ", ".join(allowed_values) + ")") return " ".join(parts) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/setup.py new/python-lsp-server-1.6.0/setup.py --- old/python-lsp-server-1.5.0/setup.py 2022-06-07 20:04:11.000000000 +0200 +++ new/python-lsp-server-1.6.0/setup.py 2022-10-31 16:56:57.000000000 +0100 @@ -5,6 +5,7 @@ from setuptools import setup, find_packages + if __name__ == "__main__": setup( name="python-lsp-server", # to allow GitHub dependency tracking work diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/__init__.py new/python-lsp-server-1.6.0/test/__init__.py --- old/python-lsp-server-1.5.0/test/__init__.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/__init__.py 2022-10-31 16:56:57.000000000 +0100 @@ -1,13 +1,9 @@ # Copyright 2017-2020 Palantir Technologies, Inc. # Copyright 2021- Python Language Server Contributors. -import sys import pytest from pylsp import IS_WIN -IS_PY3 = sys.version_info.major == 3 unix_only = pytest.mark.skipif(IS_WIN, reason="Unix only") windows_only = pytest.mark.skipif(not IS_WIN, reason="Windows only") -py3_only = pytest.mark.skipif(not IS_PY3, reason="Python3 only") -py2_only = pytest.mark.skipif(IS_PY3, reason="Python2 only") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/plugins/test_autopep8_format.py new/python-lsp-server-1.6.0/test/plugins/test_autopep8_format.py --- old/python-lsp-server-1.5.0/test/plugins/test_autopep8_format.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/plugins/test_autopep8_format.py 2022-10-31 16:56:57.000000000 +0100 @@ -41,7 +41,7 @@ def test_format(config, workspace): doc = Document(DOC_URI, workspace, DOC) - res = pylsp_format_document(config, doc) + res = pylsp_format_document(config, doc, options=None) assert len(res) == 1 assert res[0]['newText'] == "a = 123\n\n\ndef func():\n pass\n" @@ -54,7 +54,7 @@ 'start': {'line': 0, 'character': 0}, 'end': {'line': 2, 'character': 0} } - res = pylsp_format_range(config, doc, def_range) + res = pylsp_format_range(config, doc, def_range, options=None) assert len(res) == 1 @@ -64,12 +64,12 @@ def test_no_change(config, workspace): doc = Document(DOC_URI, workspace, GOOD_DOC) - assert not pylsp_format_document(config, doc) + assert not pylsp_format_document(config, doc, options=None) def test_hanging_indentation(config, workspace): doc = Document(DOC_URI, workspace, INDENTED_DOC) - res = pylsp_format_document(config, doc) + res = pylsp_format_document(config, doc, options=None) assert len(res) == 1 assert res[0]['newText'] == CORRECT_INDENTED_DOC @@ -78,6 +78,6 @@ @pytest.mark.parametrize('newline', ['\r\n', '\r']) def test_line_endings(config, workspace, newline): doc = Document(DOC_URI, workspace, f'import os;import sys{2 * newline}dict(a=1)') - res = pylsp_format_document(config, doc) + res = pylsp_format_document(config, doc, options=None) assert res[0]['newText'] == f'import os{newline}import sys{2 * newline}dict(a=1){newline}' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/plugins/test_completion.py new/python-lsp-server-1.6.0/test/plugins/test_completion.py --- old/python-lsp-server-1.5.0/test/plugins/test_completion.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/plugins/test_completion.py 2022-10-31 16:56:57.000000000 +0100 @@ -160,10 +160,15 @@ assert 'detail' not in documented_hello_item resolved_documented_hello = pylsp_jedi_completion_item_resolve( + doc._config, completion_item=documented_hello_item, document=doc ) - assert 'Sends a polite greeting' in resolved_documented_hello['documentation'] + expected_doc = { + 'kind': 'markdown', + 'value': '```python\ndocumented_hello()\n```\n\n\nSends a polite greeting' + } + assert resolved_documented_hello['documentation'] == expected_doc def test_jedi_completion_with_fuzzy_enabled(config, workspace): @@ -356,6 +361,26 @@ assert completions[1]['kind'] == lsp.CompletionItemKind.TypeParameter +def test_completion_with_function_objects(config, workspace): + doc_text = 'def foobar(): pass\nfoob' + com_position = {'line': 1, 'character': 4} + doc = Document(DOC_URI, workspace, doc_text) + config.capabilities['textDocument'] = { + 'completion': {'completionItem': {'snippetSupport': True}}} + config.update({'plugins': {'jedi_completion': { + 'include_params': True, + 'include_function_objects': True, + }}}) + completions = pylsp_jedi_completions(config, doc, com_position) + assert len(completions) == 2 + + assert completions[0]['label'] == 'foobar()' + assert completions[0]['kind'] == lsp.CompletionItemKind.Function + + assert completions[1]['label'] == 'foobar() object' + assert completions[1]['kind'] == lsp.CompletionItemKind.TypeParameter + + def test_snippet_parsing(config, workspace): doc = 'divmod' completion_position = {'line': 0, 'character': 6} @@ -478,8 +503,8 @@ completions = pylsp_jedi_completions(doc._config, doc, com_position) assert completions[0]['label'] == 'loghub' - resolved = pylsp_jedi_completion_item_resolve(completions[0], doc) - assert 'changelog generator' in resolved['documentation'].lower() + resolved = pylsp_jedi_completion_item_resolve(doc._config, completions[0], doc) + assert 'changelog generator' in resolved['documentation']['value'].lower() def test_document_path_completions(tmpdir, workspace_other_root_path): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/plugins/test_hover.py new/python-lsp-server-1.6.0/test/plugins/test_hover.py --- old/python-lsp-server-1.5.0/test/plugins/test_hover.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/plugins/test_hover.py 2022-10-31 16:56:57.000000000 +0100 @@ -38,16 +38,16 @@ doc = Document(DOC_URI, workspace, NUMPY_DOC) contents = '' - assert contents in pylsp_hover(doc, no_hov_position)['contents'] + assert contents in pylsp_hover(doc._config, doc, no_hov_position)['contents'] contents = 'NumPy\n=====\n\nProvides\n' - assert contents in pylsp_hover(doc, numpy_hov_position_1)['contents'][0] + assert contents in pylsp_hover(doc._config, doc, numpy_hov_position_1)['contents']['value'] contents = 'NumPy\n=====\n\nProvides\n' - assert contents in pylsp_hover(doc, numpy_hov_position_2)['contents'][0] + assert contents in pylsp_hover(doc._config, doc, numpy_hov_position_2)['contents']['value'] contents = 'NumPy\n=====\n\nProvides\n' - assert contents in pylsp_hover(doc, numpy_hov_position_3)['contents'][0] + assert contents in pylsp_hover(doc._config, doc, numpy_hov_position_3)['contents']['value'] # https://github.com/davidhalter/jedi/issues/1746 # pylint: disable=import-outside-toplevel @@ -55,8 +55,8 @@ if np.lib.NumpyVersion(np.__version__) < '1.20.0': contents = 'Trigonometric sine, element-wise.\n\n' - assert contents in pylsp_hover( - doc, numpy_sin_hov_position)['contents'][0] + assert contents in pylsp_hover(doc._config, + doc, numpy_sin_hov_position)['contents']['value'] def test_hover(workspace): @@ -67,13 +67,13 @@ doc = Document(DOC_URI, workspace, DOC) - contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] + contents = {'kind': 'markdown', 'value': '```python\nmain()\n```\n\n\nhello world'} assert { 'contents': contents - } == pylsp_hover(doc, hov_position) + } == pylsp_hover(doc._config, doc, hov_position) - assert {'contents': ''} == pylsp_hover(doc, no_hov_position) + assert {'contents': ''} == pylsp_hover(doc._config, doc, no_hov_position) def test_document_path_hover(workspace_other_root_path, tmpdir): @@ -96,6 +96,6 @@ doc = Document(doc_uri, workspace_other_root_path, doc_content) cursor_pos = {'line': 1, 'character': 3} - contents = pylsp_hover(doc, cursor_pos)['contents'] + contents = pylsp_hover(doc._config, doc, cursor_pos)['contents'] - assert contents[1] == 'A docstring for foo.' + assert 'A docstring for foo.' in contents['value'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/plugins/test_pylint_lint.py new/python-lsp-server-1.6.0/test/plugins/test_pylint_lint.py --- old/python-lsp-server-1.5.0/test/plugins/test_pylint_lint.py 2022-07-01 23:20:01.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/plugins/test_pylint_lint.py 2022-10-31 16:56:57.000000000 +0100 @@ -4,10 +4,8 @@ import contextlib import os -import sys import tempfile -from test import py2_only, py3_only, IS_PY3 from pylsp import lsp, uris from pylsp.workspace import Document from pylsp.plugins import pylint_lint @@ -53,30 +51,26 @@ assert unused_import['severity'] == lsp.DiagnosticSeverity.Warning assert unused_import['tags'] == [lsp.DiagnosticTag.Unnecessary] - if IS_PY3: - # test running pylint in stdin - config.plugin_settings('pylint')['executable'] = 'pylint' - diags = pylint_lint.pylsp_lint(config, doc, True) - - msg = 'Unused import sys (unused-import)' - unused_import = [d for d in diags if d['message'] == msg][0] - - assert unused_import['range']['start'] == { - 'line': 0, - 'character': 0, - } - assert unused_import['severity'] == lsp.DiagnosticSeverity.Warning + # test running pylint in stdin + config.plugin_settings('pylint')['executable'] = 'pylint' + diags = pylint_lint.pylsp_lint(config, doc, True) + + msg = 'Unused import sys (unused-import)' + unused_import = [d for d in diags if d['message'] == msg][0] + + assert unused_import['range']['start'] == { + 'line': 0, + 'character': 0, + } + assert unused_import['severity'] == lsp.DiagnosticSeverity.Warning -@py3_only -def test_syntax_error_pylint_py3(config, workspace): +def test_syntax_error_pylint(config, workspace): with temp_document(DOC_SYNTAX_ERR, workspace) as doc: diag = pylint_lint.pylsp_lint(config, doc, True)[0] - if sys.version_info[:2] >= (3, 10): - assert diag['message'].count("[syntax-error] expected ':'") - else: - assert diag['message'].startswith('[syntax-error] invalid syntax') + assert diag['message'].startswith("[syntax-error]") + assert diag['message'].count("expected ':'") or diag['message'].count('invalid syntax') # Pylint doesn't give column numbers for invalid syntax. assert diag['range']['start'] == {'line': 0, 'character': 12} assert diag['severity'] == lsp.DiagnosticSeverity.Error @@ -86,23 +80,12 @@ config.plugin_settings('pylint')['executable'] = 'pylint' diag = pylint_lint.pylsp_lint(config, doc, True)[0] - assert diag['message'].count("expected ':'") or diag['message'].startswith('invalid syntax') + assert diag['message'].count("expected ':'") or diag['message'].count('invalid syntax') # Pylint doesn't give column numbers for invalid syntax. assert diag['range']['start'] == {'line': 0, 'character': 12} assert diag['severity'] == lsp.DiagnosticSeverity.Error -@py2_only -def test_syntax_error_pylint_py2(config, workspace): - with temp_document(DOC_SYNTAX_ERR, workspace) as doc: - diag = pylint_lint.pylsp_lint(config, doc, True)[0] - - assert diag['message'].startswith('[syntax-error] invalid syntax') - # Pylint doesn't give column numbers for invalid syntax. - assert diag['range']['start'] == {'line': 0, 'character': 0} - assert diag['severity'] == lsp.DiagnosticSeverity.Error - - 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/plugins/test_signature.py new/python-lsp-server-1.6.0/test/plugins/test_signature.py --- old/python-lsp-server-1.5.0/test/plugins/test_signature.py 2022-04-05 19:04:58.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/plugins/test_signature.py 2022-10-31 16:56:57.000000000 +0100 @@ -46,7 +46,7 @@ sig_position = {'line': 9, 'character': 0} doc = Document(DOC_URI, workspace, DOC) - sigs = signature.pylsp_signature_help(doc, sig_position)['signatures'] + sigs = signature.pylsp_signature_help(doc._config, doc, sig_position)['signatures'] assert not sigs @@ -55,13 +55,13 @@ sig_position = {'line': 10, 'character': 5} doc = Document(DOC_URI, workspace, DOC) - sig_info = signature.pylsp_signature_help(doc, sig_position) + sig_info = signature.pylsp_signature_help(doc._config, doc, sig_position) sigs = sig_info['signatures'] assert len(sigs) == 1 assert sigs[0]['label'] == 'main(param1, param2)' assert sigs[0]['parameters'][0]['label'] == 'param1' - assert sigs[0]['parameters'][0]['documentation'] == 'Docs for param1' + assert sigs[0]['parameters'][0]['documentation'] == {'kind': 'markdown', 'value': 'Docs for param1'} assert sig_info['activeParameter'] == 0 @@ -71,7 +71,7 @@ sig_position = {'line': 17, 'character': 5} doc = Document(DOC_URI, workspace, MULTI_LINE_DOC) - sig_info = signature.pylsp_signature_help(doc, sig_position) + sig_info = signature.pylsp_signature_help(doc._config, doc, sig_position) sigs = sig_info['signatures'] assert len(sigs) == 1 @@ -80,7 +80,7 @@ 'param5=None, param6=None, param7=None, param8=None)' ) assert sigs[0]['parameters'][0]['label'] == 'param1' - assert sigs[0]['parameters'][0]['documentation'] == 'Docs for param1' + assert sigs[0]['parameters'][0]['documentation'] == {'kind': 'markdown', 'value': 'Docs for param1'} assert sig_info['activeParameter'] == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-lsp-server-1.5.0/test/plugins/test_yapf_format.py new/python-lsp-server-1.6.0/test/plugins/test_yapf_format.py --- old/python-lsp-server-1.5.0/test/plugins/test_yapf_format.py 2022-06-07 20:04:11.000000000 +0200 +++ new/python-lsp-server-1.6.0/test/plugins/test_yapf_format.py 2022-10-31 16:56:57.000000000 +0100 @@ -29,7 +29,7 @@ def test_format(workspace): doc = Document(DOC_URI, workspace, DOC) - res = pylsp_format_document(doc) + res = pylsp_format_document(doc, None) assert apply_text_edits(doc, res) == "A = ['h', 'w', 'a']\n\nB = ['h', 'w']\n" @@ -41,7 +41,7 @@ 'start': {'line': 0, 'character': 0}, 'end': {'line': 4, 'character': 10} } - res = pylsp_format_range(doc, def_range) + res = pylsp_format_range(doc, def_range, None) # Make sure B is still badly formatted assert apply_text_edits(doc, res) == "A = ['h', 'w', 'a']\n\nB = ['h',\n\n\n'w']\n" @@ -49,7 +49,7 @@ def test_no_change(workspace): doc = Document(DOC_URI, workspace, GOOD_DOC) - assert not pylsp_format_document(doc) + assert not pylsp_format_document(doc, options=None) def test_config_file(tmpdir, workspace): @@ -59,7 +59,7 @@ src = tmpdir.join('test.py') doc = Document(uris.from_fs_path(src.strpath), workspace, DOC) - res = pylsp_format_document(doc) + res = pylsp_format_document(doc, options=None) # A was split on multiple lines because of column_limit from config file assert apply_text_edits(doc, res) == "A = [\n 'h', 'w',\n 'a'\n]\n\nB = ['h', 'w']\n" @@ -68,7 +68,7 @@ @pytest.mark.parametrize('newline', ['\r\n']) def test_line_endings(workspace, newline): doc = Document(DOC_URI, workspace, f'import os;import sys{2 * newline}dict(a=1)') - res = pylsp_format_document(doc) + res = pylsp_format_document(doc, options=None) assert apply_text_edits(doc, res) == f'import os{newline}import sys{2 * newline}dict(a=1){newline}' @@ -99,7 +99,7 @@ log("x") log("hi")""" doc = Document(DOC_URI, workspace, single_space_indent) - res = pylsp_format_document(doc) + res = pylsp_format_document(doc, options=None) # two removes and two adds assert len(res) == 4